brcm47xx: b44: fix some problems with the phy
authorhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Sun, 6 Oct 2013 18:31:32 +0000 (18:31 +0000)
committerhauke <hauke@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Sun, 6 Oct 2013 18:31:32 +0000 (18:31 +0000)
* do not try initialize a unused phy
* some improvements to the phylib patch
* do not turn the phy off when mac is off

Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@38306 3c298f89-4303-0410-b956-a3cf2f4a3e73

target/linux/brcm47xx/patches-3.10/200-b44-add-support-for-Byte-Queue-Limits.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.10/202-b44-rename-B44_PHY_ADDR_NO_PHY-to-B44_PHY_ADDR_NO_LO.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.10/203-b44-abort-when-no-PHY-is-available-at-all.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.10/204-b44-rename-b44_mii_-read-write-to-b44_mdio_-read-wri.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.10/205-b44-add-phylib-support.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.10/206-b44-activate-PHY-when-MAC-is-off.patch [new file with mode: 0644]
target/linux/brcm47xx/patches-3.10/210-b44_phy_fix.patch
target/linux/brcm47xx/patches-3.10/211-b44_timeout_spam.patch [deleted file]
target/linux/brcm47xx/patches-3.10/730-b44-add-support-for-Byte-Queue-Limits.patch [deleted file]
target/linux/brcm47xx/patches-3.10/780-b44-phylib.patch [deleted file]

diff --git a/target/linux/brcm47xx/patches-3.10/200-b44-add-support-for-Byte-Queue-Limits.patch b/target/linux/brcm47xx/patches-3.10/200-b44-add-support-for-Byte-Queue-Limits.patch
new file mode 100644 (file)
index 0000000..127c984
--- /dev/null
@@ -0,0 +1,43 @@
+--- a/drivers/net/ethernet/broadcom/b44.c
++++ b/drivers/net/ethernet/broadcom/b44.c
+@@ -596,6 +596,7 @@ static void b44_timer(unsigned long __op
+ static void b44_tx(struct b44 *bp)
+ {
+       u32 cur, cons;
++      unsigned bytes_compl = 0, pkts_compl = 0;
+       cur  = br32(bp, B44_DMATX_STAT) & DMATX_STAT_CDMASK;
+       cur /= sizeof(struct dma_desc);
+@@ -612,9 +613,14 @@ static void b44_tx(struct b44 *bp)
+                                skb->len,
+                                DMA_TO_DEVICE);
+               rp->skb = NULL;
++
++              bytes_compl += skb->len;
++              pkts_compl++;
++
+               dev_kfree_skb_irq(skb);
+       }
++      netdev_completed_queue(bp->dev, pkts_compl, bytes_compl);
+       bp->tx_cons = cons;
+       if (netif_queue_stopped(bp->dev) &&
+           TX_BUFFS_AVAIL(bp) > B44_TX_WAKEUP_THRESH)
+@@ -1018,6 +1024,8 @@ static netdev_tx_t b44_start_xmit(struct
+       if (bp->flags & B44_FLAG_REORDER_BUG)
+               br32(bp, B44_DMATX_PTR);
++      netdev_sent_queue(dev, skb->len);
++
+       if (TX_BUFFS_AVAIL(bp) < 1)
+               netif_stop_queue(dev);
+@@ -1416,6 +1424,8 @@ static void b44_init_hw(struct b44 *bp,
+       val = br32(bp, B44_ENET_CTRL);
+       bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
++
++      netdev_reset_queue(bp->dev);
+ }
+ static int b44_open(struct net_device *dev)
diff --git a/target/linux/brcm47xx/patches-3.10/202-b44-rename-B44_PHY_ADDR_NO_PHY-to-B44_PHY_ADDR_NO_LO.patch b/target/linux/brcm47xx/patches-3.10/202-b44-rename-B44_PHY_ADDR_NO_PHY-to-B44_PHY_ADDR_NO_LO.patch
new file mode 100644 (file)
index 0000000..8610f0c
--- /dev/null
@@ -0,0 +1,87 @@
+From 991b6722fb727b6e2a98e7e8b57176ac68626110 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 3 Oct 2013 20:41:29 +0200
+Subject: [PATCH 2/5] b44: rename B44_PHY_ADDR_NO_PHY to
+ B44_PHY_ADDR_NO_LOCAL_PHY
+
+The PHY address 30 means there is no local PHY, but there could be an
+external PHY like a switch connected via MII. This is the case on most
+embedded home routers where this driver is used.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/net/ethernet/broadcom/b44.c |   12 ++++++------
+ drivers/net/ethernet/broadcom/b44.h |    6 +++---
+ 2 files changed, 9 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/b44.c
++++ b/drivers/net/ethernet/broadcom/b44.c
+@@ -284,7 +284,7 @@ static int __b44_writephy(struct b44 *bp
+ static inline int b44_readphy(struct b44 *bp, int reg, u32 *val)
+ {
+-      if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++      if (bp->phy_addr == B44_PHY_ADDR_NO_LOACL_PHY)
+               return 0;
+       return __b44_readphy(bp, bp->phy_addr, reg, val);
+@@ -292,7 +292,7 @@ static inline int b44_readphy(struct b44
+ static inline int b44_writephy(struct b44 *bp, int reg, u32 val)
+ {
+-      if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++      if (bp->phy_addr == B44_PHY_ADDR_NO_LOACL_PHY)
+               return 0;
+       return __b44_writephy(bp, bp->phy_addr, reg, val);
+@@ -321,7 +321,7 @@ static int b44_phy_reset(struct b44 *bp)
+       u32 val;
+       int err;
+-      if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++      if (bp->phy_addr == B44_PHY_ADDR_NO_LOACL_PHY)
+               return 0;
+       err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
+       if (err)
+@@ -423,7 +423,7 @@ static int b44_setup_phy(struct b44 *bp)
+       b44_wap54g10_workaround(bp);
+-      if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
++      if (bp->phy_addr == B44_PHY_ADDR_NO_LOACL_PHY)
+               return 0;
+       if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
+               goto out;
+@@ -521,7 +521,7 @@ static void b44_check_phy(struct b44 *bp
+ {
+       u32 bmsr, aux;
+-      if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
++      if (bp->phy_addr == B44_PHY_ADDR_NO_LOACL_PHY) {
+               bp->flags |= B44_FLAG_100_BASE_T;
+               bp->flags |= B44_FLAG_FULL_DUPLEX;
+               if (!netif_carrier_ok(bp->dev)) {
+@@ -2238,7 +2238,7 @@ static int b44_init_one(struct ssb_devic
+       /* do a phy reset to test if there is an active phy */
+       if (b44_phy_reset(bp) < 0)
+-              bp->phy_addr = B44_PHY_ADDR_NO_PHY;
++              bp->phy_addr = B44_PHY_ADDR_NO_LOACL_PHY;
+       netdev_info(dev, "%s %pM\n", DRV_DESCRIPTION, dev->dev_addr);
+--- a/drivers/net/ethernet/broadcom/b44.h
++++ b/drivers/net/ethernet/broadcom/b44.h
+@@ -280,9 +280,9 @@ struct ring_info {
+       dma_addr_t      mapping;
+ };
+-#define B44_MCAST_TABLE_SIZE  32
+-#define B44_PHY_ADDR_NO_PHY   30
+-#define B44_MDC_RATIO         5000000
++#define B44_MCAST_TABLE_SIZE          32
++#define B44_PHY_ADDR_NO_LOACL_PHY     30 /* no local phy regs */
++#define B44_MDC_RATIO                 5000000
+ #define       B44_STAT_REG_DECLARE            \
+       _B44(tx_good_octets)            \
diff --git a/target/linux/brcm47xx/patches-3.10/203-b44-abort-when-no-PHY-is-available-at-all.patch b/target/linux/brcm47xx/patches-3.10/203-b44-abort-when-no-PHY-is-available-at-all.patch
new file mode 100644 (file)
index 0000000..54256db
--- /dev/null
@@ -0,0 +1,40 @@
+From 1bfdc259652abe22a587fd6d856c1b71168cccb2 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 3 Oct 2013 20:49:10 +0200
+Subject: [PATCH 3/5] b44: abort when no PHY is available at all
+
+When the phy address is 31, this means that there is no PHY connected
+to this MAC at all, no internal and no external PHY. Reading these PHY
+registers causes a system reset on some routers.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/net/ethernet/broadcom/b44.c |    6 ++++++
+ drivers/net/ethernet/broadcom/b44.h |    1 +
+ 2 files changed, 7 insertions(+)
+
+--- a/drivers/net/ethernet/broadcom/b44.c
++++ b/drivers/net/ethernet/broadcom/b44.c
+@@ -2207,6 +2207,12 @@ static int b44_init_one(struct ssb_devic
+               goto err_out_powerdown;
+       }
++      if (bp->phy_addr == B44_PHY_ADDR_NO_PHY) {
++              dev_err(sdev->dev, "No PHY present on this MAC, aborting\n");
++              err = -ENODEV;
++              goto err_out_powerdown;
++      }
++
+       bp->mii_if.dev = dev;
+       bp->mii_if.mdio_read = b44_mii_read;
+       bp->mii_if.mdio_write = b44_mii_write;
+--- a/drivers/net/ethernet/broadcom/b44.h
++++ b/drivers/net/ethernet/broadcom/b44.h
+@@ -282,6 +282,7 @@ struct ring_info {
+ #define B44_MCAST_TABLE_SIZE          32
+ #define B44_PHY_ADDR_NO_LOACL_PHY     30 /* no local phy regs */
++#define B44_PHY_ADDR_NO_PHY           31 /* no phy present at all */
+ #define B44_MDC_RATIO                 5000000
+ #define       B44_STAT_REG_DECLARE            \
diff --git a/target/linux/brcm47xx/patches-3.10/204-b44-rename-b44_mii_-read-write-to-b44_mdio_-read-wri.patch b/target/linux/brcm47xx/patches-3.10/204-b44-rename-b44_mii_-read-write-to-b44_mdio_-read-wri.patch
new file mode 100644 (file)
index 0000000..4758875
--- /dev/null
@@ -0,0 +1,48 @@
+From 6dcaccfc1e0046632dd54d91b6f679fee7f841bc Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 6 Oct 2013 15:31:04 +0200
+Subject: [PATCH 4/5] b44: rename b44_mii_{read,write} to
+ b44_mdio_{read,write}_mii
+
+The next patch will add these functions for phylib, and we should
+rename the old ones before. This now indicates that these functions are
+used for the mdio registers and on the mii interface.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/net/ethernet/broadcom/b44.c |   10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/b44.c
++++ b/drivers/net/ethernet/broadcom/b44.c
+@@ -299,7 +299,7 @@ static inline int b44_writephy(struct b4
+ }
+ /* miilib interface */
+-static int b44_mii_read(struct net_device *dev, int phy_id, int location)
++static int b44_mdio_read_mii(struct net_device *dev, int phy_id, int location)
+ {
+       u32 val;
+       struct b44 *bp = netdev_priv(dev);
+@@ -309,8 +309,8 @@ static int b44_mii_read(struct net_devic
+       return val;
+ }
+-static void b44_mii_write(struct net_device *dev, int phy_id, int location,
+-                       int val)
++static void b44_mdio_write_mii(struct net_device *dev, int phy_id, int location,
++                             int val)
+ {
+       struct b44 *bp = netdev_priv(dev);
+       __b44_writephy(bp, phy_id, location, val);
+@@ -2214,8 +2214,8 @@ static int b44_init_one(struct ssb_devic
+       }
+       bp->mii_if.dev = dev;
+-      bp->mii_if.mdio_read = b44_mii_read;
+-      bp->mii_if.mdio_write = b44_mii_write;
++      bp->mii_if.mdio_read = b44_mdio_read_mii;
++      bp->mii_if.mdio_write = b44_mdio_write_mii;
+       bp->mii_if.phy_id = bp->phy_addr;
+       bp->mii_if.phy_id_mask = 0x1f;
+       bp->mii_if.reg_num_mask = 0x1f;
diff --git a/target/linux/brcm47xx/patches-3.10/205-b44-add-phylib-support.patch b/target/linux/brcm47xx/patches-3.10/205-b44-add-phylib-support.patch
new file mode 100644 (file)
index 0000000..3c8e7a3
--- /dev/null
@@ -0,0 +1,312 @@
+From 46e5460f446109565b3f4a0cb728171d74bce33b Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 3 Oct 2013 22:07:11 +0200
+Subject: [PATCH 5/6] b44: add phylib support
+
+Most of the older home routers based on the Broadcom BCM47XX SoC series
+are using a MAC that is supported by b44. On most of these routers not
+the internal PHY of this MAC core is used, but a switch sometimes on an
+external chip or integrated into the same SoC as the Ethernet core.
+For this switch a special PHY driver is needed which should not be
+integrated into b44 as the same switches are also used by other
+Broadcom home networking SoCs which are using different Ethernet MAC
+drivers. This was tested with the b53 switch driver which is currently
+on its way to mainline.
+
+With this patch we scan the mdio bus when the sprom or nvram says that
+the PHY address is 30, if a PHY was found at this address b44 uses it.
+
+This was tested with a BCM4704, BCM4712 and BCM5354.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/net/ethernet/broadcom/Kconfig |    1 +
+ drivers/net/ethernet/broadcom/b44.c   |  183 ++++++++++++++++++++++++++++++++-
+ drivers/net/ethernet/broadcom/b44.h   |    5 +
+ 3 files changed, 186 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/Kconfig
++++ b/drivers/net/ethernet/broadcom/Kconfig
+@@ -24,6 +24,7 @@ config B44
+       select SSB
+       select NET_CORE
+       select MII
++      select PHYLIB
+       ---help---
+         If you have a network (Ethernet) controller of this type, say Y
+         or M and read the Ethernet-HOWTO, available from
+--- a/drivers/net/ethernet/broadcom/b44.c
++++ b/drivers/net/ethernet/broadcom/b44.c
+@@ -6,6 +6,7 @@
+  * Copyright (C) 2006 Felix Fietkau (nbd@openwrt.org)
+  * Copyright (C) 2006 Broadcom Corporation.
+  * Copyright (C) 2007 Michael Buesch <m@bues.ch>
++ * Copyright (C) 2013 Hauke Mehrtens <hauke@hauke-m.de>
+  *
+  * Distribute under GPL.
+  */
+@@ -29,6 +30,7 @@
+ #include <linux/dma-mapping.h>
+ #include <linux/ssb/ssb.h>
+ #include <linux/slab.h>
++#include <linux/phy.h>
+ #include <asm/uaccess.h>
+ #include <asm/io.h>
+@@ -316,6 +318,23 @@ static void b44_mdio_write_mii(struct ne
+       __b44_writephy(bp, phy_id, location, val);
+ }
++static int b44_mdio_read_phylib(struct mii_bus *bus, int phy_id, int location)
++{
++      u32 val;
++      struct b44 *bp = bus->priv;
++      int rc = __b44_readphy(bp, phy_id, location, &val);
++      if (rc)
++              return 0xffffffff;
++      return val;
++}
++
++static int b44_mdio_write_phylib(struct mii_bus *bus, int phy_id, int location,
++                               u16 val)
++{
++      struct b44 *bp = bus->priv;
++      return __b44_writephy(bp, phy_id, location, val);
++}
++
+ static int b44_phy_reset(struct b44 *bp)
+ {
+       u32 val;
+@@ -1805,6 +1824,11 @@ static int b44_get_settings(struct net_d
+ {
+       struct b44 *bp = netdev_priv(dev);
++      if (bp->has_phy) {
++              BUG_ON(!bp->phydev);
++              return phy_ethtool_gset(bp->phydev, cmd);
++      }
++
+       cmd->supported = (SUPPORTED_Autoneg);
+       cmd->supported |= (SUPPORTED_100baseT_Half |
+                         SUPPORTED_100baseT_Full |
+@@ -1846,7 +1870,23 @@ static int b44_get_settings(struct net_d
+ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+ {
+       struct b44 *bp = netdev_priv(dev);
+-      u32 speed = ethtool_cmd_speed(cmd);
++      u32 speed;
++      int ret;
++
++      if (bp->has_phy) {
++              BUG_ON(!bp->phydev);
++              spin_lock_irq(&bp->lock);
++              if (netif_running(dev))
++                      b44_setup_phy(bp);
++
++              ret = phy_ethtool_sset(bp->phydev, cmd);
++
++              spin_unlock_irq(&bp->lock);
++
++              return ret;
++      }
++
++      speed = ethtool_cmd_speed(cmd);
+       /* We do not support gigabit. */
+       if (cmd->autoneg == AUTONEG_ENABLE) {
+@@ -2076,7 +2116,6 @@ static const struct ethtool_ops b44_etht
+ static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+ {
+-      struct mii_ioctl_data *data = if_mii(ifr);
+       struct b44 *bp = netdev_priv(dev);
+       int err = -EINVAL;
+@@ -2084,7 +2123,12 @@ static int b44_ioctl(struct net_device *
+               goto out;
+       spin_lock_irq(&bp->lock);
+-      err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
++      if (bp->has_phy) {
++              BUG_ON(bp->phydev);
++              err = phy_mii_ioctl(bp->phydev, ifr, cmd);
++      } else {
++              err = generic_mii_ioctl(&bp->mii_if, if_mii(ifr), cmd, NULL);
++      }
+       spin_unlock_irq(&bp->lock);
+ out:
+       return err;
+@@ -2146,6 +2190,124 @@ static const struct net_device_ops b44_n
+ #endif
+ };
++static void b44_adjust_link(struct net_device *dev)
++{
++      struct b44 *bp = netdev_priv(dev);
++      struct phy_device *phydev = bp->phydev;
++      bool status_changed = 0;
++
++      BUG_ON(!phydev);
++
++      if (bp->old_link != phydev->link) {
++              status_changed = 1;
++              bp->old_link = phydev->link;
++      }
++
++      /* reflect duplex change */
++      if (phydev->link && (bp->old_duplex != phydev->duplex)) {
++              status_changed = 1;
++              bp->old_duplex = phydev->duplex;
++      }
++
++      if (status_changed)
++              phy_print_status(phydev);
++}
++
++static int b44_register_phy_one(struct b44 *bp)
++{
++      struct mii_bus *mii_bus;
++      struct ssb_device *sdev = bp->sdev;
++      struct phy_device *phydev;
++      int err;
++
++      mii_bus = mdiobus_alloc();
++      if (!mii_bus) {
++              dev_err(sdev->dev, "mdiobus_alloc() failed\n");
++              err = -ENOMEM;
++              goto err_out;
++      }
++
++      mii_bus->priv = bp;
++      mii_bus->read = b44_mdio_read_phylib;
++      mii_bus->write = b44_mdio_write_phylib;
++      mii_bus->name = "b44_eth_mii";
++      mii_bus->parent = sdev->dev;
++      mii_bus->phy_mask = ~(1 << bp->phy_addr);
++      snprintf(mii_bus->id, MII_BUS_ID_SIZE, "%x", instance);
++      mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
++      if (!mii_bus->irq) {
++              dev_err(sdev->dev, "mii_bus irq allocation failed\n");
++              err = -ENOMEM;
++              goto err_out_mdiobus;
++      }
++
++      memset(mii_bus->irq, PHY_POLL, sizeof(int) * PHY_MAX_ADDR);
++
++      bp->mii_bus = mii_bus;
++
++      err = mdiobus_register(mii_bus);
++      if (err) {
++              dev_err(sdev->dev, "failed to register MII bus\n");
++              goto err_out_mdiobus_irq;
++      }
++
++      phydev = bp->mii_bus->phy_map[bp->phy_addr];
++      if (!phydev) {
++              dev_err(sdev->dev, "could not find PHY at %i\n", bp->phy_addr);
++              err = -ENODEV;
++              goto err_out_mdiobus_unregister;
++      }
++
++      err = phy_connect_direct(bp->dev, phydev, &b44_adjust_link,
++                               PHY_INTERFACE_MODE_MII);
++      if (err < 0) {
++              dev_err(sdev->dev, "could not attach PHY at %i\n",
++                      bp->phy_addr);
++              goto err_out_mdiobus_unregister;
++      }
++
++      /* mask with MAC supported features */
++      phydev->supported &= (SUPPORTED_10baseT_Half |
++                            SUPPORTED_10baseT_Full |
++                            SUPPORTED_100baseT_Half |
++                            SUPPORTED_100baseT_Full |
++                            SUPPORTED_Autoneg |
++                            SUPPORTED_MII);
++      phydev->advertising = phydev->supported;
++
++      bp->phydev = phydev;
++      bp->old_link = 0;
++      bp->old_duplex = -1;
++      bp->phy_addr = phydev->addr;
++
++      dev_info(sdev->dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
++               phydev->drv->name, dev_name(&phydev->dev));
++
++      return 0;
++
++err_out_mdiobus_unregister:
++      mdiobus_unregister(mii_bus);
++
++err_out_mdiobus_irq:
++      kfree(mii_bus->irq);
++
++err_out_mdiobus:
++      mdiobus_free(mii_bus);
++
++err_out:
++      return err;
++}
++
++static void b44_unregister_phy_one(struct b44 *bp)
++{
++      struct mii_bus *mii_bus = bp->mii_bus;
++
++      phy_disconnect(bp->phydev);
++      mdiobus_unregister(mii_bus);
++      kfree(mii_bus->irq);
++      mdiobus_free(mii_bus);
++}
++
+ static int b44_init_one(struct ssb_device *sdev,
+                       const struct ssb_device_id *ent)
+ {
+@@ -2246,10 +2408,22 @@ static int b44_init_one(struct ssb_devic
+       if (b44_phy_reset(bp) < 0)
+               bp->phy_addr = B44_PHY_ADDR_NO_LOACL_PHY;
++      bp->has_phy = bp->phy_addr == B44_PHY_ADDR_NO_LOACL_PHY;
++
++      if (bp->has_phy) {
++              err = b44_register_phy_one(bp);
++              if (err) {
++                      dev_err(sdev->dev, "Cannot register PHY, aborting\n");
++                      goto err_out_unregister_netdev;
++              }
++      }
++
+       netdev_info(dev, "%s %pM\n", DRV_DESCRIPTION, dev->dev_addr);
+       return 0;
++err_out_unregister_netdev:
++      unregister_netdev(dev);
+ err_out_powerdown:
+       ssb_bus_may_powerdown(sdev->bus);
+@@ -2263,8 +2437,11 @@ out:
+ static void b44_remove_one(struct ssb_device *sdev)
+ {
+       struct net_device *dev = ssb_get_drvdata(sdev);
++      struct b44 *bp = netdev_priv(dev);
+       unregister_netdev(dev);
++      if (bp->has_phy)
++              b44_unregister_phy_one(bp);
+       ssb_device_disable(sdev, 0);
+       ssb_bus_may_powerdown(sdev->bus);
+       free_netdev(dev);
+--- a/drivers/net/ethernet/broadcom/b44.h
++++ b/drivers/net/ethernet/broadcom/b44.h
+@@ -397,6 +397,11 @@ struct b44 {
+       u32                     tx_pending;
+       u8                      phy_addr;
+       u8                      force_copybreak;
++      bool                    has_phy;
++      struct phy_device       *phydev;
++      struct mii_bus          *mii_bus;
++      int                     old_link;
++      int                     old_duplex;
+       struct mii_if_info      mii_if;
+ };
diff --git a/target/linux/brcm47xx/patches-3.10/206-b44-activate-PHY-when-MAC-is-off.patch b/target/linux/brcm47xx/patches-3.10/206-b44-activate-PHY-when-MAC-is-off.patch
new file mode 100644 (file)
index 0000000..e6c39b0
--- /dev/null
@@ -0,0 +1,28 @@
+From 444044a410d4cf3b6dd462f2c9352d56039d9e07 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 6 Oct 2013 17:58:24 +0200
+Subject: [PATCH 6/6] b44: activate PHY when MAC is off
+
+Without this patch we can not access the PHY when the MAC is switched
+off. This PHY access is needed to configure the switch, which is done
+through PHY registers.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/net/ethernet/broadcom/b44.c |    5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/net/ethernet/broadcom/b44.c
++++ b/drivers/net/ethernet/broadcom/b44.c
+@@ -1358,7 +1358,10 @@ static void b44_halt(struct b44 *bp)
+       bw32(bp, B44_MAC_CTRL, MAC_CTRL_PHY_PDOWN);
+       /* now reset the chip, but without enabling the MAC&PHY
+        * part of it. This has to be done _after_ we shut down the PHY */
+-      b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
++      if (bp->has_phy)
++              b44_chip_reset(bp, B44_CHIP_RESET_FULL);
++      else
++              b44_chip_reset(bp, B44_CHIP_RESET_PARTIAL);
+ }
+ /* bp->lock is held. */
index 8cf4b0f..1cafb86 100644 (file)
@@ -1,6 +1,6 @@
 --- a/drivers/net/ethernet/broadcom/b44.c
 +++ b/drivers/net/ethernet/broadcom/b44.c
-@@ -410,10 +410,34 @@ static void b44_wap54g10_workaround(stru
+@@ -429,10 +429,34 @@ static void b44_wap54g10_workaround(stru
  error:
        pr_warning("PHY: cannot reset MII transceiver isolate bit\n");
  }
 +
 +      /* Toshiba WRC-1000, Siemens SE505 v1, Askey RT-210W, RT-220W */
 +      if (sdev->bus->sprom.board_num == 100) {
-+              bp->phy_addr = B44_PHY_ADDR_NO_PHY;
++              bp->phy_addr = B44_PHY_ADDR_NO_LOACL_PHY;
 +      } else {
 +              /* WL-HDD */
 +              if (bcm47xx_nvram_getenv("hardware_version", buf, sizeof(buf)) >= 0 &&
 +                  !strncmp(buf, "WL300-", strlen("WL300-"))) {
 +                      if (sdev->bus->sprom.et0phyaddr == 0 &&
 +                          sdev->bus->sprom.et1phyaddr == 1)
-+                              bp->phy_addr = B44_PHY_ADDR_NO_PHY;
++                              bp->phy_addr = B44_PHY_ADDR_NO_LOACL_PHY;
 +              }
 +      }
 +      return;
  #endif
  
  static int b44_setup_phy(struct b44 *bp)
-@@ -422,6 +446,7 @@ static int b44_setup_phy(struct b44 *bp)
+@@ -441,6 +465,7 @@ static int b44_setup_phy(struct b44 *bp)
        int err;
  
        b44_wap54g10_workaround(bp);
 +      b44_bcm47xx_workarounds(bp);
  
-       if (bp->phy_addr == B44_PHY_ADDR_NO_PHY)
+       if (bp->phy_addr == B44_PHY_ADDR_NO_LOACL_PHY)
                return 0;
-@@ -2101,6 +2126,8 @@ static int b44_get_invariants(struct b44
+@@ -2158,6 +2183,8 @@ static int b44_get_invariants(struct b44
         * valid PHY address. */
        bp->phy_addr &= 0x1F;
  
diff --git a/target/linux/brcm47xx/patches-3.10/211-b44_timeout_spam.patch b/target/linux/brcm47xx/patches-3.10/211-b44_timeout_spam.patch
deleted file mode 100644 (file)
index c2eb3ad..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
---- a/drivers/net/ethernet/broadcom/b44.c
-+++ b/drivers/net/ethernet/broadcom/b44.c
-@@ -187,10 +187,11 @@ static int b44_wait_bit(struct b44 *bp,
-               udelay(10);
-       }
-       if (i == timeout) {
-+#if 0
-               if (net_ratelimit())
-                       netdev_err(bp->dev, "BUG!  Timeout waiting for bit %08x of register %lx to %s\n",
-                                  bit, reg, clear ? "clear" : "set");
--
-+#endif
-               return -ENODEV;
-       }
-       return 0;
diff --git a/target/linux/brcm47xx/patches-3.10/730-b44-add-support-for-Byte-Queue-Limits.patch b/target/linux/brcm47xx/patches-3.10/730-b44-add-support-for-Byte-Queue-Limits.patch
deleted file mode 100644 (file)
index 5da6abe..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-From: Hauke Mehrtens <hauke@hauke-m.de>
-b44: add support for Byte Queue Limits
-
---- a/drivers/net/ethernet/broadcom/b44.c
-+++ b/drivers/net/ethernet/broadcom/b44.c
-@@ -622,6 +622,7 @@ static void b44_timer(unsigned long __op
- static void b44_tx(struct b44 *bp)
- {
-       u32 cur, cons;
-+      unsigned bytes_compl = 0, pkts_compl = 0;
-       cur  = br32(bp, B44_DMATX_STAT) & DMATX_STAT_CDMASK;
-       cur /= sizeof(struct dma_desc);
-@@ -638,9 +639,14 @@ static void b44_tx(struct b44 *bp)
-                                skb->len,
-                                DMA_TO_DEVICE);
-               rp->skb = NULL;
-+
-+              bytes_compl += skb->len;
-+              pkts_compl++;
-+
-               dev_kfree_skb_irq(skb);
-       }
-+      netdev_completed_queue(bp->dev, pkts_compl, bytes_compl);
-       bp->tx_cons = cons;
-       if (netif_queue_stopped(bp->dev) &&
-           TX_BUFFS_AVAIL(bp) > B44_TX_WAKEUP_THRESH)
-@@ -1044,6 +1050,8 @@ static netdev_tx_t b44_start_xmit(struct
-       if (bp->flags & B44_FLAG_REORDER_BUG)
-               br32(bp, B44_DMATX_PTR);
-+      netdev_sent_queue(dev, skb->len);
-+
-       if (TX_BUFFS_AVAIL(bp) < 1)
-               netif_stop_queue(dev);
-@@ -1442,6 +1450,8 @@ static void b44_init_hw(struct b44 *bp,
-       val = br32(bp, B44_ENET_CTRL);
-       bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
-+      
-+      netdev_reset_queue(bp->dev);
- }
- static int b44_open(struct net_device *dev)
diff --git a/target/linux/brcm47xx/patches-3.10/780-b44-phylib.patch b/target/linux/brcm47xx/patches-3.10/780-b44-phylib.patch
deleted file mode 100644 (file)
index 0295ca0..0000000
+++ /dev/null
@@ -1,325 +0,0 @@
---- a/drivers/net/ethernet/broadcom/Kconfig
-+++ b/drivers/net/ethernet/broadcom/Kconfig
-@@ -24,6 +24,7 @@ config B44
-       select SSB
-       select NET_CORE
-       select MII
-+      select PHYLIB
-       ---help---
-         If you have a network (Ethernet) controller of this type, say Y
-         or M and read the Ethernet-HOWTO, available from
---- a/drivers/net/ethernet/broadcom/b44.c
-+++ b/drivers/net/ethernet/broadcom/b44.c
-@@ -29,6 +29,7 @@
- #include <linux/dma-mapping.h>
- #include <linux/ssb/ssb.h>
- #include <linux/slab.h>
-+#include <linux/phy.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
-@@ -300,21 +301,23 @@ static inline int b44_writephy(struct b4
- }
- /* miilib interface */
--static int b44_mii_read(struct net_device *dev, int phy_id, int location)
-+static int b44_mii_read(struct mii_bus *bus, int phy_id, int location)
- {
-       u32 val;
--      struct b44 *bp = netdev_priv(dev);
-+      struct b44 *bp = bus->priv;
-       int rc = __b44_readphy(bp, phy_id, location, &val);
-       if (rc)
-               return 0xffffffff;
-       return val;
- }
--static void b44_mii_write(struct net_device *dev, int phy_id, int location,
--                       int val)
-+static int b44_mii_write(struct mii_bus *bus, int phy_id, int location,
-+                       u16 val)
- {
--      struct b44 *bp = netdev_priv(dev);
-+      struct b44 *bp = bus->priv;
-       __b44_writephy(bp, phy_id, location, val);
-+
-+      return 0;
- }
- static int b44_phy_reset(struct b44 *bp)
-@@ -1831,102 +1834,24 @@ static int b44_get_settings(struct net_d
- {
-       struct b44 *bp = netdev_priv(dev);
--      cmd->supported = (SUPPORTED_Autoneg);
--      cmd->supported |= (SUPPORTED_100baseT_Half |
--                        SUPPORTED_100baseT_Full |
--                        SUPPORTED_10baseT_Half |
--                        SUPPORTED_10baseT_Full |
--                        SUPPORTED_MII);
--
--      cmd->advertising = 0;
--      if (bp->flags & B44_FLAG_ADV_10HALF)
--              cmd->advertising |= ADVERTISED_10baseT_Half;
--      if (bp->flags & B44_FLAG_ADV_10FULL)
--              cmd->advertising |= ADVERTISED_10baseT_Full;
--      if (bp->flags & B44_FLAG_ADV_100HALF)
--              cmd->advertising |= ADVERTISED_100baseT_Half;
--      if (bp->flags & B44_FLAG_ADV_100FULL)
--              cmd->advertising |= ADVERTISED_100baseT_Full;
--      cmd->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
--      ethtool_cmd_speed_set(cmd, ((bp->flags & B44_FLAG_100_BASE_T) ?
--                                  SPEED_100 : SPEED_10));
--      cmd->duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
--              DUPLEX_FULL : DUPLEX_HALF;
--      cmd->port = 0;
--      cmd->phy_address = bp->phy_addr;
--      cmd->transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
--              XCVR_INTERNAL : XCVR_EXTERNAL;
--      cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
--              AUTONEG_DISABLE : AUTONEG_ENABLE;
--      if (cmd->autoneg == AUTONEG_ENABLE)
--              cmd->advertising |= ADVERTISED_Autoneg;
--      if (!netif_running(dev)){
--              ethtool_cmd_speed_set(cmd, 0);
--              cmd->duplex = 0xff;
--      }
--      cmd->maxtxpkt = 0;
--      cmd->maxrxpkt = 0;
--      return 0;
-+      return phy_ethtool_gset(bp->phydev, cmd);
- }
- static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
- {
-       struct b44 *bp = netdev_priv(dev);
--      u32 speed = ethtool_cmd_speed(cmd);
--
--      /* We do not support gigabit. */
--      if (cmd->autoneg == AUTONEG_ENABLE) {
--              if (cmd->advertising &
--                  (ADVERTISED_1000baseT_Half |
--                   ADVERTISED_1000baseT_Full))
--                      return -EINVAL;
--      } else if ((speed != SPEED_100 &&
--                  speed != SPEED_10) ||
--                 (cmd->duplex != DUPLEX_HALF &&
--                  cmd->duplex != DUPLEX_FULL)) {
--                      return -EINVAL;
--      }
-+      int ret;
-       spin_lock_irq(&bp->lock);
--      if (cmd->autoneg == AUTONEG_ENABLE) {
--              bp->flags &= ~(B44_FLAG_FORCE_LINK |
--                             B44_FLAG_100_BASE_T |
--                             B44_FLAG_FULL_DUPLEX |
--                             B44_FLAG_ADV_10HALF |
--                             B44_FLAG_ADV_10FULL |
--                             B44_FLAG_ADV_100HALF |
--                             B44_FLAG_ADV_100FULL);
--              if (cmd->advertising == 0) {
--                      bp->flags |= (B44_FLAG_ADV_10HALF |
--                                    B44_FLAG_ADV_10FULL |
--                                    B44_FLAG_ADV_100HALF |
--                                    B44_FLAG_ADV_100FULL);
--              } else {
--                      if (cmd->advertising & ADVERTISED_10baseT_Half)
--                              bp->flags |= B44_FLAG_ADV_10HALF;
--                      if (cmd->advertising & ADVERTISED_10baseT_Full)
--                              bp->flags |= B44_FLAG_ADV_10FULL;
--                      if (cmd->advertising & ADVERTISED_100baseT_Half)
--                              bp->flags |= B44_FLAG_ADV_100HALF;
--                      if (cmd->advertising & ADVERTISED_100baseT_Full)
--                              bp->flags |= B44_FLAG_ADV_100FULL;
--              }
--      } else {
--              bp->flags |= B44_FLAG_FORCE_LINK;
--              bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX);
--              if (speed == SPEED_100)
--                      bp->flags |= B44_FLAG_100_BASE_T;
--              if (cmd->duplex == DUPLEX_FULL)
--                      bp->flags |= B44_FLAG_FULL_DUPLEX;
--      }
--
-       if (netif_running(dev))
-               b44_setup_phy(bp);
-+      ret = phy_ethtool_sset(bp->phydev, cmd);
-+
-       spin_unlock_irq(&bp->lock);
--      return 0;
-+      return ret;
- }
- static void b44_get_ringparam(struct net_device *dev,
-@@ -2102,20 +2027,74 @@ static const struct ethtool_ops b44_etht
- static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
- {
--      struct mii_ioctl_data *data = if_mii(ifr);
-       struct b44 *bp = netdev_priv(dev);
-       int err = -EINVAL;
-       if (!netif_running(dev))
-               goto out;
-+      if (!bp->phydev)
-+              return -EINVAL;
-+
-       spin_lock_irq(&bp->lock);
--      err = generic_mii_ioctl(&bp->mii_if, data, cmd, NULL);
-+      err = phy_mii_ioctl(bp->phydev, ifr, cmd);
-       spin_unlock_irq(&bp->lock);
- out:
-       return err;
- }
-+static void b44_adjust_link(struct net_device *dev)
-+{
-+      struct b44 *bp = netdev_priv(dev);
-+      struct phy_device *phydev = bp->phydev;
-+      bool status_changed = 0;
-+
-+      BUG_ON(!phydev);
-+
-+      if (bp->old_link != phydev->link) {
-+              status_changed = 1;
-+              bp->old_link = phydev->link;
-+      }
-+
-+      /* reflect duplex change */
-+      if (phydev->link && (bp->old_duplex != phydev->duplex)) {
-+              status_changed = 1;
-+              bp->old_duplex = phydev->duplex;
-+      }
-+
-+      if (status_changed)
-+              phy_print_status(phydev);
-+}
-+
-+static int b44_mii_probe(struct net_device *dev)
-+{
-+      struct b44 *bp = netdev_priv(dev);
-+      struct phy_device *phydev = NULL;
-+      char phy_id[MII_BUS_ID_SIZE + 3];
-+
-+      /* connect to PHY */
-+      snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
-+               bp->mii_bus->id, bp->phy_addr);
-+
-+      phydev = phy_connect(dev, phy_id, &b44_adjust_link,
-+                           PHY_INTERFACE_MODE_MII);
-+      if (IS_ERR(phydev)) {
-+              netdev_err(dev, "could not attach PHY: %s\n", phy_id);
-+              bp->phy_addr = B44_PHY_ADDR_NO_PHY;
-+              return PTR_ERR(phydev);
-+      }
-+
-+      bp->phydev = phydev;
-+      bp->old_link = 0;
-+      bp->old_duplex = -1;
-+      bp->phy_addr = phydev->addr;
-+
-+      netdev_info(dev, "attached PHY driver [%s] (mii_bus:phy_addr=%s)\n",
-+                  phydev->drv->name, dev_name(&phydev->dev));
-+
-+      return 0;
-+}
-+
- static int b44_get_invariants(struct b44 *bp)
- {
-       struct ssb_device *sdev = bp->sdev;
-@@ -2235,12 +2214,40 @@ static int b44_init_one(struct ssb_devic
-               goto err_out_powerdown;
-       }
--      bp->mii_if.dev = dev;
--      bp->mii_if.mdio_read = b44_mii_read;
--      bp->mii_if.mdio_write = b44_mii_write;
--      bp->mii_if.phy_id = bp->phy_addr;
--      bp->mii_if.phy_id_mask = 0x1f;
--      bp->mii_if.reg_num_mask = 0x1f;
-+      bp->mii_bus = mdiobus_alloc();
-+      if (!bp->mii_bus) {
-+              dev_err(sdev->dev, "mdiobus_alloc() failed\n");
-+              err = -ENOMEM;
-+              goto err_out_powerdown;
-+      }
-+
-+      bp->mii_bus->priv = bp;
-+      bp->mii_bus->read = b44_mii_read;
-+      bp->mii_bus->write = b44_mii_write;
-+      bp->mii_bus->name = "b44_eth_mii";
-+      bp->mii_bus->parent = sdev->dev;
-+      bp->mii_bus->phy_mask = ~(1 << bp->phy_addr);
-+      snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", instance);
-+      bp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
-+      if (!bp->mii_bus->irq) {
-+              dev_err(sdev->dev, "mii_bus irq allocation failed\n");
-+              err = -ENOMEM;
-+              goto err_out_mdiobus;
-+      }
-+
-+      memset(bp->mii_bus->irq, PHY_POLL, sizeof(int) * PHY_MAX_ADDR);
-+
-+      err = mdiobus_register(bp->mii_bus);
-+      if (err) {
-+              dev_err(sdev->dev, "failed to register MII bus\n");
-+              goto err_out_mdiobus_irq;
-+      }
-+
-+      err = b44_mii_probe(dev);
-+      if (err) {
-+              dev_err(sdev->dev, "failed to probe MII bus\n");
-+              goto err_out_mdiobus_unregister;
-+      }
-       /* By default, advertise all speed/duplex settings. */
-       bp->flags |= (B44_FLAG_ADV_10HALF | B44_FLAG_ADV_10FULL |
-@@ -2272,6 +2279,16 @@ static int b44_init_one(struct ssb_devic
-       return 0;
-+
-+err_out_mdiobus_unregister:
-+      mdiobus_unregister(bp->mii_bus);
-+
-+err_out_mdiobus_irq:
-+      kfree(bp->mii_bus->irq);
-+
-+err_out_mdiobus:
-+      mdiobus_free(bp->mii_bus);
-+
- err_out_powerdown:
-       ssb_bus_may_powerdown(sdev->bus);
-@@ -2285,8 +2302,12 @@ out:
- static void b44_remove_one(struct ssb_device *sdev)
- {
-       struct net_device *dev = ssb_get_drvdata(sdev);
-+      struct b44 *bp = netdev_priv(dev);
-       unregister_netdev(dev);
-+      mdiobus_unregister(bp->mii_bus);
-+      kfree(bp->mii_bus->irq);
-+      mdiobus_free(bp->mii_bus);
-       ssb_device_disable(sdev, 0);
-       ssb_bus_may_powerdown(sdev->bus);
-       free_netdev(dev);
---- a/drivers/net/ethernet/broadcom/b44.h
-+++ b/drivers/net/ethernet/broadcom/b44.h
-@@ -396,7 +396,10 @@ struct b44 {
-       u32                     tx_pending;
-       u8                      phy_addr;
-       u8                      force_copybreak;
--      struct mii_if_info      mii_if;
-+      struct phy_device       *phydev;
-+      struct mii_bus          *mii_bus;
-+      int                     old_link;
-+      int                     old_duplex;
- };
- #endif /* _B44_H */