parent
ad66840108
commit
7df13dc926
@ -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 new issue