experimental multiphy support for 2.6.29
SVN-Revision: 15491
This commit is contained in:
parent
ad66840108
commit
7df13dc926
7 changed files with 394 additions and 20 deletions
|
@ -1,20 +0,0 @@
|
|||
TODO: take care of additional PHYs through the PHY abstraction layer
|
||||
|
||||
--- a/arch/arm/mach-ixp4xx/include/mach/platform.h
|
||||
+++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
|
||||
@@ -95,12 +95,15 @@ struct sys_timer;
|
||||
#define IXP4XX_ETH_NPEB 0x10
|
||||
#define IXP4XX_ETH_NPEC 0x20
|
||||
|
||||
+#define IXP4XX_ETH_PHY_MAX_ADDR 32
|
||||
+
|
||||
/* Information about built-in Ethernet MAC interfaces */
|
||||
struct eth_plat_info {
|
||||
u8 phy; /* MII PHY ID, 0 - 31 */
|
||||
u8 rxq; /* configurable, currently 0 - 31 only */
|
||||
u8 txreadyq;
|
||||
u8 hwaddr[6];
|
||||
+ u32 phy_mask;
|
||||
};
|
||||
|
||||
/* Information about built-in HSS (synchronous serial) interfaces */
|
|
@ -0,0 +1,13 @@
|
|||
--- a/drivers/net/arm/ixp4xx_eth.c
|
||||
+++ b/drivers/net/arm/ixp4xx_eth.c
|
||||
@@ -1218,6 +1218,10 @@ static int __devinit eth_init_one(struct
|
||||
return PTR_ERR(port->phydev);
|
||||
}
|
||||
|
||||
+ /* mask with MAC supported features */
|
||||
+ port->phydev->supported &= PHY_BASIC_FEATURES;
|
||||
+ port->phydev->advertising = port->phydev->supported;
|
||||
+
|
||||
port->phydev->irq = PHY_POLL;
|
||||
|
||||
printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
|
|
@ -0,0 +1,10 @@
|
|||
--- a/drivers/net/arm/ixp4xx_eth.c
|
||||
+++ b/drivers/net/arm/ixp4xx_eth.c
|
||||
@@ -1243,6 +1243,7 @@ static int __devexit eth_remove_one(stru
|
||||
struct net_device *dev = platform_get_drvdata(pdev);
|
||||
struct port *port = netdev_priv(dev);
|
||||
|
||||
+ phy_disconnect(port->phydev);
|
||||
unregister_netdev(dev);
|
||||
npe_port_tab[NPE_ID(port->id)] = NULL;
|
||||
platform_set_drvdata(pdev, NULL);
|
|
@ -0,0 +1,118 @@
|
|||
--- a/drivers/net/arm/ixp4xx_eth.c
|
||||
+++ b/drivers/net/arm/ixp4xx_eth.c
|
||||
@@ -394,6 +394,53 @@ static void ixp4xx_adjust_link(struct ne
|
||||
dev->name, port->speed, port->duplex ? "full" : "half");
|
||||
}
|
||||
|
||||
+static int ixp4xx_phy_connect(struct net_device *dev)
|
||||
+{
|
||||
+ struct port *port = netdev_priv(dev);
|
||||
+ struct eth_plat_info *plat = port->plat;
|
||||
+ char phy_id[BUS_ID_SIZE];
|
||||
+
|
||||
+ snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, "0", plat->phy);
|
||||
+ port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,
|
||||
+ PHY_INTERFACE_MODE_MII);
|
||||
+ if (IS_ERR(port->phydev)) {
|
||||
+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
|
||||
+ return PTR_ERR(port->phydev);
|
||||
+ }
|
||||
+
|
||||
+ /* mask with MAC supported features */
|
||||
+ port->phydev->supported &= PHY_BASIC_FEATURES;
|
||||
+ port->phydev->advertising = port->phydev->supported;
|
||||
+
|
||||
+ port->phydev->irq = PHY_POLL;
|
||||
+
|
||||
+ printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
|
||||
+ npe_name(port->npe));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void ixp4xx_phy_disconnect(struct net_device *dev)
|
||||
+{
|
||||
+ struct port *port = netdev_priv(dev);
|
||||
+
|
||||
+ phy_disconnect(port->phydev);
|
||||
+}
|
||||
+
|
||||
+static void ixp4xx_phy_start(struct net_device *dev)
|
||||
+{
|
||||
+ struct port *port = netdev_priv(dev);
|
||||
+
|
||||
+ port->speed = 0; /* force "link up" message */
|
||||
+ phy_start(port->phydev);
|
||||
+}
|
||||
+
|
||||
+static void ixp4xx_phy_stop(struct net_device *dev)
|
||||
+{
|
||||
+ struct port *port = netdev_priv(dev);
|
||||
+
|
||||
+ phy_stop(port->phydev);
|
||||
+}
|
||||
|
||||
static inline void debug_pkt(struct net_device *dev, const char *func,
|
||||
u8 *data, int len)
|
||||
@@ -1001,8 +1048,7 @@ static int eth_open(struct net_device *d
|
||||
return err;
|
||||
}
|
||||
|
||||
- port->speed = 0; /* force "link up" message */
|
||||
- phy_start(port->phydev);
|
||||
+ ixp4xx_phy_start(dev);
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
__raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]);
|
||||
@@ -1123,7 +1169,7 @@ static int eth_close(struct net_device *
|
||||
printk(KERN_CRIT "%s: unable to disable loopback\n",
|
||||
dev->name);
|
||||
|
||||
- phy_stop(port->phydev);
|
||||
+ ixp4xx_phy_stop(dev);
|
||||
|
||||
if (!ports_open)
|
||||
qmgr_disable_irq(TXDONE_QUEUE);
|
||||
@@ -1147,7 +1193,6 @@ static int __devinit eth_init_one(struct
|
||||
struct net_device *dev;
|
||||
struct eth_plat_info *plat = pdev->dev.platform_data;
|
||||
u32 regs_phys;
|
||||
- char phy_id[BUS_ID_SIZE];
|
||||
int err;
|
||||
|
||||
if (!(dev = alloc_etherdev(sizeof(struct port))))
|
||||
@@ -1210,22 +1255,9 @@ static int __devinit eth_init_one(struct
|
||||
__raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
|
||||
udelay(50);
|
||||
|
||||
- snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, "0", plat->phy);
|
||||
- port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,
|
||||
- PHY_INTERFACE_MODE_MII);
|
||||
- if (IS_ERR(port->phydev)) {
|
||||
- printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
|
||||
- return PTR_ERR(port->phydev);
|
||||
- }
|
||||
-
|
||||
- /* mask with MAC supported features */
|
||||
- port->phydev->supported &= PHY_BASIC_FEATURES;
|
||||
- port->phydev->advertising = port->phydev->supported;
|
||||
-
|
||||
- port->phydev->irq = PHY_POLL;
|
||||
-
|
||||
- printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
|
||||
- npe_name(port->npe));
|
||||
+ err = ixp4xx_phy_connect(dev);
|
||||
+ if (err)
|
||||
+ goto err_unreg;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1243,7 +1275,7 @@ static int __devexit eth_remove_one(stru
|
||||
struct net_device *dev = platform_get_drvdata(pdev);
|
||||
struct port *port = netdev_priv(dev);
|
||||
|
||||
- phy_disconnect(port->phydev);
|
||||
+ ixp4xx_phy_disconnect(dev);
|
||||
unregister_netdev(dev);
|
||||
npe_port_tab[NPE_ID(port->id)] = NULL;
|
||||
platform_set_drvdata(pdev, NULL);
|
|
@ -0,0 +1,98 @@
|
|||
--- a/drivers/net/arm/ixp4xx_eth.c
|
||||
+++ b/drivers/net/arm/ixp4xx_eth.c
|
||||
@@ -169,7 +169,7 @@ struct port {
|
||||
struct desc *desc_tab; /* coherent */
|
||||
u32 desc_tab_phys;
|
||||
int id; /* logical port ID */
|
||||
- int speed, duplex;
|
||||
+ int link, speed, duplex;
|
||||
u8 firmware[4];
|
||||
};
|
||||
|
||||
@@ -363,37 +363,52 @@ static void ixp4xx_mdio_remove(void)
|
||||
mdiobus_free(mdio_bus);
|
||||
}
|
||||
|
||||
-
|
||||
-static void ixp4xx_adjust_link(struct net_device *dev)
|
||||
+static void ixp4xx_update_link(struct net_device *dev)
|
||||
{
|
||||
struct port *port = netdev_priv(dev);
|
||||
- struct phy_device *phydev = port->phydev;
|
||||
|
||||
- if (!phydev->link) {
|
||||
- if (port->speed) {
|
||||
- port->speed = 0;
|
||||
- printk(KERN_INFO "%s: link down\n", dev->name);
|
||||
- }
|
||||
+ if (!port->link) {
|
||||
+ netif_carrier_off(dev);
|
||||
+ printk(KERN_INFO "%s: link down\n", dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
- if (port->speed == phydev->speed && port->duplex == phydev->duplex)
|
||||
- return;
|
||||
-
|
||||
- port->speed = phydev->speed;
|
||||
- port->duplex = phydev->duplex;
|
||||
-
|
||||
- if (port->duplex)
|
||||
+ if (port->duplex == DUPLEX_FULL)
|
||||
__raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
|
||||
&port->regs->tx_control[0]);
|
||||
else
|
||||
__raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
|
||||
&port->regs->tx_control[0]);
|
||||
|
||||
+ netif_carrier_on(dev);
|
||||
printk(KERN_INFO "%s: link up, speed %u Mb/s, %s duplex\n",
|
||||
dev->name, port->speed, port->duplex ? "full" : "half");
|
||||
}
|
||||
|
||||
+static void ixp4xx_adjust_link(struct net_device *dev)
|
||||
+{
|
||||
+ struct port *port = netdev_priv(dev);
|
||||
+ struct phy_device *phydev = port->phydev;
|
||||
+ int status_change = 0;
|
||||
+
|
||||
+ if (phydev->link) {
|
||||
+ if (port->duplex != phydev->duplex
|
||||
+ || port->speed != phydev->speed) {
|
||||
+ status_change = 1;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (phydev->link != port->link)
|
||||
+ status_change = 1;
|
||||
+
|
||||
+ port->link = phydev->link;
|
||||
+ port->speed = phydev->speed;
|
||||
+ port->duplex = phydev->duplex;
|
||||
+
|
||||
+ if (status_change)
|
||||
+ ixp4xx_update_link(dev);
|
||||
+}
|
||||
+
|
||||
static int ixp4xx_phy_connect(struct net_device *dev)
|
||||
{
|
||||
struct port *port = netdev_priv(dev);
|
||||
@@ -414,6 +429,10 @@ static int ixp4xx_phy_connect(struct net
|
||||
|
||||
port->phydev->irq = PHY_POLL;
|
||||
|
||||
+ port->link = 0;
|
||||
+ port->speed = 0;
|
||||
+ port->duplex = -1;
|
||||
+
|
||||
printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
|
||||
npe_name(port->npe));
|
||||
|
||||
@@ -431,7 +450,6 @@ static void ixp4xx_phy_start(struct net_
|
||||
{
|
||||
struct port *port = netdev_priv(dev);
|
||||
|
||||
- port->speed = 0; /* force "link up" message */
|
||||
phy_start(port->phydev);
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
TODO: take care of additional PHYs through the PHY abstraction layer
|
||||
|
||||
--- a/arch/arm/mach-ixp4xx/include/mach/platform.h
|
||||
+++ b/arch/arm/mach-ixp4xx/include/mach/platform.h
|
||||
@@ -72,7 +72,7 @@ extern unsigned long ixp4xx_exp_bus_size
|
||||
/*
|
||||
* Clock Speed Definitions.
|
||||
*/
|
||||
-#define IXP4XX_PERIPHERAL_BUS_CLOCK (66) /* 66Mhzi APB BUS */
|
||||
+#define IXP4XX_PERIPHERAL_BUS_CLOCK (66) /* 66Mhzi APB BUS */
|
||||
#define IXP4XX_UART_XTAL 14745600
|
||||
|
||||
/*
|
||||
@@ -95,12 +95,23 @@ struct sys_timer;
|
||||
#define IXP4XX_ETH_NPEB 0x10
|
||||
#define IXP4XX_ETH_NPEC 0x20
|
||||
|
||||
+#define IXP4XX_ETH_PHY_MAX_ADDR 32
|
||||
+
|
||||
/* Information about built-in Ethernet MAC interfaces */
|
||||
struct eth_plat_info {
|
||||
u8 phy; /* MII PHY ID, 0 - 31 */
|
||||
u8 rxq; /* configurable, currently 0 - 31 only */
|
||||
u8 txreadyq;
|
||||
u8 hwaddr[6];
|
||||
+
|
||||
+ u32 phy_mask;
|
||||
+#if 0
|
||||
+ int speed;
|
||||
+ int duplex;
|
||||
+#else
|
||||
+ int speed_10;
|
||||
+ int half_duplex;
|
||||
+#endif
|
||||
};
|
||||
|
||||
/* Information about built-in HSS (synchronous serial) interfaces */
|
||||
--- a/drivers/net/arm/ixp4xx_eth.c
|
||||
+++ b/drivers/net/arm/ixp4xx_eth.c
|
||||
@@ -415,6 +415,37 @@ static int ixp4xx_phy_connect(struct net
|
||||
struct eth_plat_info *plat = port->plat;
|
||||
char phy_id[BUS_ID_SIZE];
|
||||
|
||||
+ if (plat->phy == IXP4XX_ETH_PHY_MAX_ADDR) {
|
||||
+#if 0
|
||||
+ switch (plat->speed) {
|
||||
+ case SPEED_10:
|
||||
+ case SPEED_100:
|
||||
+ break;
|
||||
+ default:
|
||||
+ printk(KERN_ERR "%s: invalid speed (%d)\n",
|
||||
+ dev->name, plat->speed);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ switch (plat->duplex) {
|
||||
+ case DUPLEX_HALF:
|
||||
+ case DUPLEX_FULL:
|
||||
+ break;
|
||||
+ default:
|
||||
+ printk(KERN_ERR "%s: invalid duplex mode (%d)\n",
|
||||
+ dev->name, plat->duplex);
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ port->speed = plat->speed;
|
||||
+ port->duplex = plat->duplex;
|
||||
+#else
|
||||
+ port->speed = plat->speed_10 ? SPEED_10 : SPEED_100;
|
||||
+ port->duplex = plat->half_duplex ? DUPLEX_HALF : DUPLEX_FULL;
|
||||
+#endif
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, "0", plat->phy);
|
||||
port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,
|
||||
PHY_INTERFACE_MODE_MII);
|
||||
@@ -443,21 +474,32 @@ static void ixp4xx_phy_disconnect(struct
|
||||
{
|
||||
struct port *port = netdev_priv(dev);
|
||||
|
||||
- phy_disconnect(port->phydev);
|
||||
+ if (port->phydev)
|
||||
+ phy_disconnect(port->phydev);
|
||||
}
|
||||
|
||||
static void ixp4xx_phy_start(struct net_device *dev)
|
||||
{
|
||||
struct port *port = netdev_priv(dev);
|
||||
|
||||
- phy_start(port->phydev);
|
||||
+ if (port->phydev) {
|
||||
+ phy_start(port->phydev);
|
||||
+ } else {
|
||||
+ port->link = 1;
|
||||
+ ixp4xx_update_link(dev);
|
||||
+ }
|
||||
}
|
||||
|
||||
static void ixp4xx_phy_stop(struct net_device *dev)
|
||||
{
|
||||
struct port *port = netdev_priv(dev);
|
||||
|
||||
- phy_stop(port->phydev);
|
||||
+ if (port->phydev) {
|
||||
+ phy_stop(port->phydev);
|
||||
+ } else {
|
||||
+ port->link = 0;
|
||||
+ ixp4xx_update_link(dev);
|
||||
+ }
|
||||
}
|
||||
|
||||
static inline void debug_pkt(struct net_device *dev, const char *func,
|
||||
@@ -829,6 +871,10 @@ static int eth_ioctl(struct net_device *
|
||||
|
||||
if (!netif_running(dev))
|
||||
return -EINVAL;
|
||||
+
|
||||
+ if (!port->phydev)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
return phy_mii_ioctl(port->phydev, if_mii(req), cmd);
|
||||
}
|
||||
|
||||
@@ -848,18 +894,30 @@ static void ixp4xx_get_drvinfo(struct ne
|
||||
static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct port *port = netdev_priv(dev);
|
||||
+
|
||||
+ if (!port->phydev)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
return phy_ethtool_gset(port->phydev, cmd);
|
||||
}
|
||||
|
||||
static int ixp4xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
struct port *port = netdev_priv(dev);
|
||||
+
|
||||
+ if (!port->phydev)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
return phy_ethtool_sset(port->phydev, cmd);
|
||||
}
|
||||
|
||||
static int ixp4xx_nway_reset(struct net_device *dev)
|
||||
{
|
||||
struct port *port = netdev_priv(dev);
|
||||
+
|
||||
+ if (!port->phydev)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
return phy_start_aneg(port->phydev);
|
||||
}
|
||||
|
Loading…
Reference in a new issue