From 2c5e4aa6add7eefb6663893a47cc6ffbb0241c68 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 6 Oct 2013 18:31:32 +0000 Subject: [PATCH] brcm47xx: b44: fix some problems with the phy * 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 SVN-Revision: 38306 --- ...4-add-support-for-Byte-Queue-Limits.patch} | 13 +- ...HY_ADDR_NO_PHY-to-B44_PHY_ADDR_NO_LO.patch | 87 +++++ ...bort-when-no-PHY-is-available-at-all.patch | 40 +++ ...ii_-read-write-to-b44_mdio_-read-wri.patch | 48 +++ .../205-b44-add-phylib-support.patch | 312 +++++++++++++++++ ...206-b44-activate-PHY-when-MAC-is-off.patch | 28 ++ .../patches-3.10/210-b44_phy_fix.patch | 12 +- .../patches-3.10/211-b44_timeout_spam.patch | 15 - .../patches-3.10/780-b44-phylib.patch | 325 ------------------ 9 files changed, 526 insertions(+), 354 deletions(-) rename target/linux/brcm47xx/patches-3.10/{730-b44-add-support-for-Byte-Queue-Limits.patch => 200-b44-add-support-for-Byte-Queue-Limits.patch} (73%) create mode 100644 target/linux/brcm47xx/patches-3.10/202-b44-rename-B44_PHY_ADDR_NO_PHY-to-B44_PHY_ADDR_NO_LO.patch create mode 100644 target/linux/brcm47xx/patches-3.10/203-b44-abort-when-no-PHY-is-available-at-all.patch create mode 100644 target/linux/brcm47xx/patches-3.10/204-b44-rename-b44_mii_-read-write-to-b44_mdio_-read-wri.patch create mode 100644 target/linux/brcm47xx/patches-3.10/205-b44-add-phylib-support.patch create mode 100644 target/linux/brcm47xx/patches-3.10/206-b44-activate-PHY-when-MAC-is-off.patch delete mode 100644 target/linux/brcm47xx/patches-3.10/211-b44_timeout_spam.patch delete mode 100644 target/linux/brcm47xx/patches-3.10/780-b44-phylib.patch 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/200-b44-add-support-for-Byte-Queue-Limits.patch similarity index 73% rename from target/linux/brcm47xx/patches-3.10/730-b44-add-support-for-Byte-Queue-Limits.patch rename to target/linux/brcm47xx/patches-3.10/200-b44-add-support-for-Byte-Queue-Limits.patch index 5da6abe202..127c9849d5 100644 --- a/target/linux/brcm47xx/patches-3.10/730-b44-add-support-for-Byte-Queue-Limits.patch +++ b/target/linux/brcm47xx/patches-3.10/200-b44-add-support-for-Byte-Queue-Limits.patch @@ -1,9 +1,6 @@ -From: Hauke Mehrtens -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 +@@ -596,6 +596,7 @@ static void b44_timer(unsigned long __op static void b44_tx(struct b44 *bp) { u32 cur, cons; @@ -11,7 +8,7 @@ b44: add support for Byte Queue Limits 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) +@@ -612,9 +613,14 @@ static void b44_tx(struct b44 *bp) skb->len, DMA_TO_DEVICE); rp->skb = NULL; @@ -26,7 +23,7 @@ b44: add support for Byte Queue Limits 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 +@@ -1018,6 +1024,8 @@ static netdev_tx_t b44_start_xmit(struct if (bp->flags & B44_FLAG_REORDER_BUG) br32(bp, B44_DMATX_PTR); @@ -35,11 +32,11 @@ b44: add support for Byte Queue Limits if (TX_BUFFS_AVAIL(bp) < 1) netif_stop_queue(dev); -@@ -1442,6 +1450,8 @@ static void b44_init_hw(struct b44 *bp, +@@ -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); } 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 index 0000000000..8610f0c51c --- /dev/null +++ b/target/linux/brcm47xx/patches-3.10/202-b44-rename-B44_PHY_ADDR_NO_PHY-to-B44_PHY_ADDR_NO_LO.patch @@ -0,0 +1,87 @@ +From 991b6722fb727b6e2a98e7e8b57176ac68626110 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 index 0000000000..54256dbaa0 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.10/203-b44-abort-when-no-PHY-is-available-at-all.patch @@ -0,0 +1,40 @@ +From 1bfdc259652abe22a587fd6d856c1b71168cccb2 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 index 0000000000..4758875e69 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.10/204-b44-rename-b44_mii_-read-write-to-b44_mdio_-read-wri.patch @@ -0,0 +1,48 @@ +From 6dcaccfc1e0046632dd54d91b6f679fee7f841bc Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 index 0000000000..3c8e7a3714 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.10/205-b44-add-phylib-support.patch @@ -0,0 +1,312 @@ +From 46e5460f446109565b3f4a0cb728171d74bce33b Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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 ++ * Copyright (C) 2013 Hauke Mehrtens + * + * Distribute under GPL. + */ +@@ -29,6 +30,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -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 index 0000000000..e6c39b0547 --- /dev/null +++ b/target/linux/brcm47xx/patches-3.10/206-b44-activate-PHY-when-MAC-is-off.patch @@ -0,0 +1,28 @@ +From 444044a410d4cf3b6dd462f2c9352d56039d9e07 Mon Sep 17 00:00:00 2001 +From: Hauke Mehrtens +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 +--- + 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. */ diff --git a/target/linux/brcm47xx/patches-3.10/210-b44_phy_fix.patch b/target/linux/brcm47xx/patches-3.10/210-b44_phy_fix.patch index 8cf4b0f00c..1cafb86512 100644 --- a/target/linux/brcm47xx/patches-3.10/210-b44_phy_fix.patch +++ b/target/linux/brcm47xx/patches-3.10/210-b44_phy_fix.patch @@ -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"); } @@ -12,14 +12,14 @@ + + /* 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; @@ -35,15 +35,15 @@ #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 index c2eb3ad90b..0000000000 --- a/target/linux/brcm47xx/patches-3.10/211-b44_timeout_spam.patch +++ /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/780-b44-phylib.patch b/target/linux/brcm47xx/patches-3.10/780-b44-phylib.patch deleted file mode 100644 index 0295ca0e4d..0000000000 --- a/target/linux/brcm47xx/patches-3.10/780-b44-phylib.patch +++ /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 - #include - #include -+#include - - #include - #include -@@ -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 */