summaryrefslogtreecommitdiff
path: root/target/linux/brcm47xx/patches-3.10
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/brcm47xx/patches-3.10')
-rw-r--r--target/linux/brcm47xx/patches-3.10/770-bgmac-phylib.patch208
-rw-r--r--target/linux/brcm47xx/patches-3.10/780-b43-phylib.patch330
2 files changed, 538 insertions, 0 deletions
diff --git a/target/linux/brcm47xx/patches-3.10/770-bgmac-phylib.patch b/target/linux/brcm47xx/patches-3.10/770-bgmac-phylib.patch
new file mode 100644
index 0000000000..6041d2a77a
--- /dev/null
+++ b/target/linux/brcm47xx/patches-3.10/770-bgmac-phylib.patch
@@ -0,0 +1,208 @@
+--- a/drivers/net/ethernet/broadcom/Kconfig
++++ b/drivers/net/ethernet/broadcom/Kconfig
+@@ -133,6 +133,7 @@ config BNX2X_SRIOV
+ config BGMAC
+ tristate "BCMA bus GBit core support"
+ depends on BCMA_HOST_SOC && HAS_DMA
++ select PHYLIB
+ ---help---
+ This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
+ They can be found on BCM47xx SoCs and provide gigabit ethernet.
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1201,27 +1201,14 @@ static int bgmac_set_mac_address(struct
+ static int bgmac_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
+ {
+ struct bgmac *bgmac = netdev_priv(net_dev);
+- struct mii_ioctl_data *data = if_mii(ifr);
+
+- switch (cmd) {
+- case SIOCGMIIPHY:
+- data->phy_id = bgmac->phyaddr;
+- /* fallthru */
+- case SIOCGMIIREG:
+- if (!netif_running(net_dev))
+- return -EAGAIN;
+- data->val_out = bgmac_phy_read(bgmac, data->phy_id,
+- data->reg_num & 0x1f);
+- return 0;
+- case SIOCSMIIREG:
+- if (!netif_running(net_dev))
+- return -EAGAIN;
+- bgmac_phy_write(bgmac, data->phy_id, data->reg_num & 0x1f,
+- data->val_in);
+- return 0;
+- default:
+- return -EOPNOTSUPP;
+- }
++ if (!netif_running(net_dev))
++ return -EINVAL;
++
++ if (!bgmac->phydev)
++ return -EINVAL;
++
++ return phy_mii_ioctl(bgmac->phydev, ifr, cmd);
+ }
+
+ static const struct net_device_ops bgmac_netdev_ops = {
+@@ -1243,61 +1230,18 @@ static int bgmac_get_settings(struct net
+ {
+ struct bgmac *bgmac = netdev_priv(net_dev);
+
+- cmd->supported = SUPPORTED_10baseT_Half |
+- SUPPORTED_10baseT_Full |
+- SUPPORTED_100baseT_Half |
+- SUPPORTED_100baseT_Full |
+- SUPPORTED_1000baseT_Half |
+- SUPPORTED_1000baseT_Full |
+- SUPPORTED_Autoneg;
+-
+- if (bgmac->autoneg) {
+- WARN_ON(cmd->advertising);
+- if (bgmac->full_duplex) {
+- if (bgmac->speed & BGMAC_SPEED_10)
+- cmd->advertising |= ADVERTISED_10baseT_Full;
+- if (bgmac->speed & BGMAC_SPEED_100)
+- cmd->advertising |= ADVERTISED_100baseT_Full;
+- if (bgmac->speed & BGMAC_SPEED_1000)
+- cmd->advertising |= ADVERTISED_1000baseT_Full;
+- } else {
+- if (bgmac->speed & BGMAC_SPEED_10)
+- cmd->advertising |= ADVERTISED_10baseT_Half;
+- if (bgmac->speed & BGMAC_SPEED_100)
+- cmd->advertising |= ADVERTISED_100baseT_Half;
+- if (bgmac->speed & BGMAC_SPEED_1000)
+- cmd->advertising |= ADVERTISED_1000baseT_Half;
+- }
+- } else {
+- switch (bgmac->speed) {
+- case BGMAC_SPEED_10:
+- ethtool_cmd_speed_set(cmd, SPEED_10);
+- break;
+- case BGMAC_SPEED_100:
+- ethtool_cmd_speed_set(cmd, SPEED_100);
+- break;
+- case BGMAC_SPEED_1000:
+- ethtool_cmd_speed_set(cmd, SPEED_1000);
+- break;
+- }
+- }
+-
+- cmd->duplex = bgmac->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
+-
+- cmd->autoneg = bgmac->autoneg;
+-
+- return 0;
++ return phy_ethtool_gset(bgmac->phydev, cmd);
+ }
+
+-#if 0
++
+ static int bgmac_set_settings(struct net_device *net_dev,
+ struct ethtool_cmd *cmd)
+ {
+ struct bgmac *bgmac = netdev_priv(net_dev);
+
+- return -1;
++ return phy_ethtool_sset(bgmac->phydev, cmd);
+ }
+-#endif
++
+
+ static void bgmac_get_drvinfo(struct net_device *net_dev,
+ struct ethtool_drvinfo *info)
+@@ -1308,6 +1252,7 @@ static void bgmac_get_drvinfo(struct net
+
+ static const struct ethtool_ops bgmac_ethtool_ops = {
+ .get_settings = bgmac_get_settings,
++ .set_settings = bgmac_set_settings,
+ .get_drvinfo = bgmac_get_drvinfo,
+ };
+
+@@ -1326,10 +1271,42 @@ static int bgmac_mii_write(struct mii_bu
+ return bgmac_phy_write(bus->priv, mii_id, regnum, value);
+ }
+
++static void bgmac_adjust_link(struct net_device *dev)
++{
++ struct bgmac *bgmac = netdev_priv(dev);
++ struct phy_device *phydev = bgmac->phydev;
++ int status_changed = 0;
++
++ BUG_ON(!phydev);
++
++ if (bgmac->old_link != phydev->link) {
++ status_changed = 1;
++ bgmac->old_link = phydev->link;
++ }
++
++ /* reflect duplex change */
++ if (phydev->link && (bgmac->old_duplex != phydev->duplex)) {
++ status_changed = 1;
++ bgmac->old_duplex = phydev->duplex;
++ }
++
++ if (status_changed) {
++ pr_info("%s: link %s", dev->name, phydev->link ?
++ "UP" : "DOWN");
++ if (phydev->link)
++ pr_cont(" - %d/%s", phydev->speed,
++ phydev->duplex == DUPLEX_FULL ? "full" : "half");
++ pr_cont("\n");
++ }
++}
++
+ static int bgmac_mii_register(struct bgmac *bgmac)
+ {
+ struct mii_bus *mii_bus;
+ int i, err = 0;
++ struct phy_device *phydev = NULL;
++ char phy_id[MII_BUS_ID_SIZE + 3];
++ struct net_device *net_dev = bgmac->net_dev;
+
+ mii_bus = mdiobus_alloc();
+ if (!mii_bus)
+@@ -1360,7 +1337,29 @@ static int bgmac_mii_register(struct bgm
+
+ bgmac->mii_bus = mii_bus;
+
+- return err;
++ /* connect to PHY */
++ snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT,
++ mii_bus->id, bgmac->phyaddr);
++
++ phydev = phy_connect(net_dev, phy_id, &bgmac_adjust_link,
++ PHY_INTERFACE_MODE_MII);
++
++ if (IS_ERR(phydev)) {
++ netdev_err(net_dev, "could not attach PHY: %s", phy_id);
++ bgmac->phyaddr = BGMAC_PHY_NOREGS;
++ return PTR_ERR(phydev);
++ }
++
++ bgmac->phydev = phydev;
++ bgmac->old_link = 0;
++ bgmac->old_duplex = -1;
++ bgmac->phyaddr = phydev->addr;
++
++ netdev_info(net_dev, "attached PHY driver [%s] "
++ "(mii_bus:phy_addr=%s)\n",
++ phydev->drv->name, dev_name(&phydev->dev));
++
++ return 0;
+
+ err_free_irq:
+ kfree(mii_bus->irq);
+--- a/drivers/net/ethernet/broadcom/bgmac.h
++++ b/drivers/net/ethernet/broadcom/bgmac.h
+@@ -399,7 +399,10 @@ struct bgmac {
+ struct bcma_device *cmn; /* Reference to CMN core for BCM4706 */
+ struct net_device *net_dev;
+ struct napi_struct napi;
++ struct phy_device *phydev;
+ struct mii_bus *mii_bus;
++ int old_link;
++ int old_duplex;
+
+ /* DMA */
+ struct bgmac_dma_ring tx_ring[BGMAC_MAX_TX_RINGS];
diff --git a/target/linux/brcm47xx/patches-3.10/780-b43-phylib.patch b/target/linux/brcm47xx/patches-3.10/780-b43-phylib.patch
new file mode 100644
index 0000000000..72b374ce55
--- /dev/null
+++ b/target/linux/brcm47xx/patches-3.10/780-b43-phylib.patch
@@ -0,0 +1,330 @@
+--- 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)
+@@ -1821,102 +1824,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,
+@@ -2092,20 +2017,81 @@ 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;
++ int 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) {
++ pr_info("%s: link %s", dev->name, phydev->link ?
++ "UP" : "DOWN");
++ if (phydev->link)
++ pr_cont(" - %d/%s", phydev->speed,
++ phydev->duplex == DUPLEX_FULL ? "full" : "half");
++ pr_cont("\n");
++ }
++}
++
++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", 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;
+@@ -2225,12 +2211,38 @@ 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";
++ 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 |
+@@ -2262,6 +2274,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);
+
+@@ -2275,8 +2297,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 */