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 <hauke@hauke-m.de> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@38306 3c298f89-4303-0410-b956-a3cf2f4a3e73master
parent
06712cae90
commit
e0f3beb7cc
|
@ -1,9 +1,6 @@
|
||||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
|
||||||
b44: add support for Byte Queue Limits
|
|
||||||
|
|
||||||
--- a/drivers/net/ethernet/broadcom/b44.c
|
--- a/drivers/net/ethernet/broadcom/b44.c
|
||||||
+++ b/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)
|
static void b44_tx(struct b44 *bp)
|
||||||
{
|
{
|
||||||
u32 cur, cons;
|
u32 cur, cons;
|
||||||
|
@ -11,7 +8,7 @@ b44: add support for Byte Queue Limits
|
||||||
|
|
||||||
cur = br32(bp, B44_DMATX_STAT) & DMATX_STAT_CDMASK;
|
cur = br32(bp, B44_DMATX_STAT) & DMATX_STAT_CDMASK;
|
||||||
cur /= sizeof(struct dma_desc);
|
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,
|
skb->len,
|
||||||
DMA_TO_DEVICE);
|
DMA_TO_DEVICE);
|
||||||
rp->skb = NULL;
|
rp->skb = NULL;
|
||||||
|
@ -26,7 +23,7 @@ b44: add support for Byte Queue Limits
|
||||||
bp->tx_cons = cons;
|
bp->tx_cons = cons;
|
||||||
if (netif_queue_stopped(bp->dev) &&
|
if (netif_queue_stopped(bp->dev) &&
|
||||||
TX_BUFFS_AVAIL(bp) > B44_TX_WAKEUP_THRESH)
|
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)
|
if (bp->flags & B44_FLAG_REORDER_BUG)
|
||||||
br32(bp, B44_DMATX_PTR);
|
br32(bp, B44_DMATX_PTR);
|
||||||
|
|
||||||
|
@ -35,7 +32,7 @@ b44: add support for Byte Queue Limits
|
||||||
if (TX_BUFFS_AVAIL(bp) < 1)
|
if (TX_BUFFS_AVAIL(bp) < 1)
|
||||||
netif_stop_queue(dev);
|
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);
|
val = br32(bp, B44_ENET_CTRL);
|
||||||
bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
|
bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
|
|
@ -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) \
|
|
@ -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 \
|
|
@ -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;
|
|
@ -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;
|
||||||
|
};
|
||||||
|
|
|
@ -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. */
|
|
@ -1,6 +1,6 @@
|
||||||
--- a/drivers/net/ethernet/broadcom/b44.c
|
--- a/drivers/net/ethernet/broadcom/b44.c
|
||||||
+++ b/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:
|
error:
|
||||||
pr_warning("PHY: cannot reset MII transceiver isolate bit\n");
|
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 */
|
+ /* Toshiba WRC-1000, Siemens SE505 v1, Askey RT-210W, RT-220W */
|
||||||
+ if (sdev->bus->sprom.board_num == 100) {
|
+ 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 {
|
+ } else {
|
||||||
+ /* WL-HDD */
|
+ /* WL-HDD */
|
||||||
+ if (bcm47xx_nvram_getenv("hardware_version", buf, sizeof(buf)) >= 0 &&
|
+ if (bcm47xx_nvram_getenv("hardware_version", buf, sizeof(buf)) >= 0 &&
|
||||||
+ !strncmp(buf, "WL300-", strlen("WL300-"))) {
|
+ !strncmp(buf, "WL300-", strlen("WL300-"))) {
|
||||||
+ if (sdev->bus->sprom.et0phyaddr == 0 &&
|
+ if (sdev->bus->sprom.et0phyaddr == 0 &&
|
||||||
+ sdev->bus->sprom.et1phyaddr == 1)
|
+ sdev->bus->sprom.et1phyaddr == 1)
|
||||||
+ bp->phy_addr = B44_PHY_ADDR_NO_PHY;
|
+ bp->phy_addr = B44_PHY_ADDR_NO_LOACL_PHY;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ return;
|
+ return;
|
||||||
|
@ -35,15 +35,15 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int b44_setup_phy(struct b44 *bp)
|
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;
|
int err;
|
||||||
|
|
||||||
b44_wap54g10_workaround(bp);
|
b44_wap54g10_workaround(bp);
|
||||||
+ b44_bcm47xx_workarounds(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;
|
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. */
|
* valid PHY address. */
|
||||||
bp->phy_addr &= 0x1F;
|
bp->phy_addr &= 0x1F;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
|
@ -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 */
|
|
Loading…
Reference in New Issue