From: Gabor Juhos Date: Wed, 29 Apr 2009 20:31:27 +0000 (+0000) Subject: [ixp4xx] experimental multiphy support for 2.6.29 X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fsvn-archive%2Farchive.git;a=commitdiff_plain;h=f66feffee85eb5dd742d4e2c2979a010c491b61f [ixp4xx] experimental multiphy support for 2.6.29 SVN-Revision: 15491 --- diff --git a/target/linux/ixp4xx/patches-2.6.29/202-npe_driver_ixp43x_support.patch b/target/linux/ixp4xx/patches-2.6.29/202-npe_driver_ixp43x_support.patch new file mode 100644 index 0000000000..7ac41e5982 --- /dev/null +++ b/target/linux/ixp4xx/patches-2.6.29/202-npe_driver_ixp43x_support.patch @@ -0,0 +1,88 @@ +From cba5c286f3ea34ea4767fc00c705434a00fe2c37 Mon Sep 17 00:00:00 2001 +From: Imre Kaloz +Date: Thu, 26 Jun 2008 01:58:02 +0200 +Subject: [PATCH] Add support for the ethernet ports on IXP43x + +--- + arch/arm/mach-ixp4xx/ixp4xx_npe.c | 6 +++--- + drivers/net/arm/ixp4xx_eth.c | 13 +++++++++---- + include/asm-arm/arch-ixp4xx/cpu.h | 2 ++ + include/asm-arm/arch-ixp4xx/ixp4xx-regs.h | 7 ++++--- + 4 files changed, 18 insertions(+), 10 deletions(-) + +--- a/arch/arm/mach-ixp4xx/ixp4xx_npe.c ++++ b/arch/arm/mach-ixp4xx/ixp4xx_npe.c +@@ -575,8 +575,8 @@ int npe_load_firmware(struct npe *npe, c + for (i = 0; i < image->size; i++) + image->data[i] = swab32(image->data[i]); + +- if (!cpu_is_ixp46x() && ((image->id >> 28) & 0xF /* device ID */)) { +- print_npe(KERN_INFO, npe, "IXP46x firmware ignored on " ++ if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) { ++ print_npe(KERN_INFO, npe, "IXP46x/IXP43x firmware ignored on " + "IXP42x\n"); + goto err; + } +@@ -598,7 +598,7 @@ int npe_load_firmware(struct npe *npe, c + "revision 0x%X:%X\n", (image->id >> 16) & 0xFF, + (image->id >> 8) & 0xFF, image->id & 0xFF); + +- if (!cpu_is_ixp46x()) { ++ if (cpu_is_ixp42x()) { + if (!npe->id) + instr_size = NPE_A_42X_INSTR_SIZE; + else +--- a/drivers/net/arm/ixp4xx_eth.c ++++ b/drivers/net/arm/ixp4xx_eth.c +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -337,7 +338,13 @@ static int ixp4xx_mdio_register(void) + + /* All MII PHY accesses use NPE-B Ethernet registers */ + spin_lock_init(&mdio_lock); +- mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; ++ if (!cpu_is_ixp43x()) ++ /* All MII PHY accesses use NPE-B Ethernet registers */ ++ mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; ++ else ++ /* IXP43x lacks NPE-B and uses NPE-C for MII PHY access */ ++ mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthC_BASE_VIRT; ++ + __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control); + + mdio_bus->name = "IXP4xx MII Bus"; +--- a/arch/arm/mach-ixp4xx/include/mach/cpu.h ++++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h +@@ -35,6 +35,8 @@ static inline u32 ixp4xx_read_feature_bi + val &= ~IXP4XX_FEATURE_RESERVED; + if (!cpu_is_ixp46x()) + val &= ~IXP4XX_FEATURE_IXP46X_ONLY; ++ if (cpu_is_ixp42x()) ++ val &= ~IXP4XX_FEATURE_IXP43X_46X; + + return val; + } +--- a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h ++++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h +@@ -628,11 +628,12 @@ + #define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22) + #define IXP4XX_FEATURE_RESERVED (0xFF << 24) + +-#define IXP4XX_FEATURE_IXP46X_ONLY (IXP4XX_FEATURE_ECC_TIMESYNC | \ ++#define IXP4XX_FEATURE_IXP43X_46X (IXP4XX_FEATURE_ECC_TIMESYNC | \ + IXP4XX_FEATURE_USB_HOST | \ + IXP4XX_FEATURE_NPEA_ETH | \ +- IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \ +- IXP4XX_FEATURE_RSA | \ + IXP4XX_FEATURE_XSCALE_MAX_FREQ) + ++#define IXP4XX_FEATURE_IXP46X_ONLY (IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \ ++ IXP4XX_FEATURE_RSA) ++ + #endif diff --git a/target/linux/ixp4xx/patches-2.6.29/202-npe_driver_switch_support.patch b/target/linux/ixp4xx/patches-2.6.29/202-npe_driver_switch_support.patch deleted file mode 100644 index ba1efd8430..0000000000 --- a/target/linux/ixp4xx/patches-2.6.29/202-npe_driver_switch_support.patch +++ /dev/null @@ -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 */ diff --git a/target/linux/ixp4xx/patches-2.6.29/203-npe_driver_mask_phy_features.patch b/target/linux/ixp4xx/patches-2.6.29/203-npe_driver_mask_phy_features.patch new file mode 100644 index 0000000000..0e8729ac20 --- /dev/null +++ b/target/linux/ixp4xx/patches-2.6.29/203-npe_driver_mask_phy_features.patch @@ -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, diff --git a/target/linux/ixp4xx/patches-2.6.29/204-npe_driver_add_missing_phy_disconnect.patch b/target/linux/ixp4xx/patches-2.6.29/204-npe_driver_add_missing_phy_disconnect.patch new file mode 100644 index 0000000000..eb9cf869a2 --- /dev/null +++ b/target/linux/ixp4xx/patches-2.6.29/204-npe_driver_add_missing_phy_disconnect.patch @@ -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); diff --git a/target/linux/ixp4xx/patches-2.6.29/204-npe_driver_ixp43x_support.patch b/target/linux/ixp4xx/patches-2.6.29/204-npe_driver_ixp43x_support.patch deleted file mode 100644 index 7ac41e5982..0000000000 --- a/target/linux/ixp4xx/patches-2.6.29/204-npe_driver_ixp43x_support.patch +++ /dev/null @@ -1,88 +0,0 @@ -From cba5c286f3ea34ea4767fc00c705434a00fe2c37 Mon Sep 17 00:00:00 2001 -From: Imre Kaloz -Date: Thu, 26 Jun 2008 01:58:02 +0200 -Subject: [PATCH] Add support for the ethernet ports on IXP43x - ---- - arch/arm/mach-ixp4xx/ixp4xx_npe.c | 6 +++--- - drivers/net/arm/ixp4xx_eth.c | 13 +++++++++---- - include/asm-arm/arch-ixp4xx/cpu.h | 2 ++ - include/asm-arm/arch-ixp4xx/ixp4xx-regs.h | 7 ++++--- - 4 files changed, 18 insertions(+), 10 deletions(-) - ---- a/arch/arm/mach-ixp4xx/ixp4xx_npe.c -+++ b/arch/arm/mach-ixp4xx/ixp4xx_npe.c -@@ -575,8 +575,8 @@ int npe_load_firmware(struct npe *npe, c - for (i = 0; i < image->size; i++) - image->data[i] = swab32(image->data[i]); - -- if (!cpu_is_ixp46x() && ((image->id >> 28) & 0xF /* device ID */)) { -- print_npe(KERN_INFO, npe, "IXP46x firmware ignored on " -+ if (cpu_is_ixp42x() && ((image->id >> 28) & 0xF /* device ID */)) { -+ print_npe(KERN_INFO, npe, "IXP46x/IXP43x firmware ignored on " - "IXP42x\n"); - goto err; - } -@@ -598,7 +598,7 @@ int npe_load_firmware(struct npe *npe, c - "revision 0x%X:%X\n", (image->id >> 16) & 0xFF, - (image->id >> 8) & 0xFF, image->id & 0xFF); - -- if (!cpu_is_ixp46x()) { -+ if (cpu_is_ixp42x()) { - if (!npe->id) - instr_size = NPE_A_42X_INSTR_SIZE; - else ---- a/drivers/net/arm/ixp4xx_eth.c -+++ b/drivers/net/arm/ixp4xx_eth.c -@@ -32,6 +32,7 @@ - #include - #include - #include -+#include - #include - #include - -@@ -337,7 +338,13 @@ static int ixp4xx_mdio_register(void) - - /* All MII PHY accesses use NPE-B Ethernet registers */ - spin_lock_init(&mdio_lock); -- mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; -+ if (!cpu_is_ixp43x()) -+ /* All MII PHY accesses use NPE-B Ethernet registers */ -+ mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; -+ else -+ /* IXP43x lacks NPE-B and uses NPE-C for MII PHY access */ -+ mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthC_BASE_VIRT; -+ - __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control); - - mdio_bus->name = "IXP4xx MII Bus"; ---- a/arch/arm/mach-ixp4xx/include/mach/cpu.h -+++ b/arch/arm/mach-ixp4xx/include/mach/cpu.h -@@ -35,6 +35,8 @@ static inline u32 ixp4xx_read_feature_bi - val &= ~IXP4XX_FEATURE_RESERVED; - if (!cpu_is_ixp46x()) - val &= ~IXP4XX_FEATURE_IXP46X_ONLY; -+ if (cpu_is_ixp42x()) -+ val &= ~IXP4XX_FEATURE_IXP43X_46X; - - return val; - } ---- a/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h -+++ b/arch/arm/mach-ixp4xx/include/mach/ixp4xx-regs.h -@@ -628,11 +628,12 @@ - #define IXP4XX_FEATURE_XSCALE_MAX_FREQ (3 << 22) - #define IXP4XX_FEATURE_RESERVED (0xFF << 24) - --#define IXP4XX_FEATURE_IXP46X_ONLY (IXP4XX_FEATURE_ECC_TIMESYNC | \ -+#define IXP4XX_FEATURE_IXP43X_46X (IXP4XX_FEATURE_ECC_TIMESYNC | \ - IXP4XX_FEATURE_USB_HOST | \ - IXP4XX_FEATURE_NPEA_ETH | \ -- IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \ -- IXP4XX_FEATURE_RSA | \ - IXP4XX_FEATURE_XSCALE_MAX_FREQ) - -+#define IXP4XX_FEATURE_IXP46X_ONLY (IXP4XX_FEATURE_NPEB_ETH_1_TO_3 | \ -+ IXP4XX_FEATURE_RSA) -+ - #endif diff --git a/target/linux/ixp4xx/patches-2.6.29/205-npe_driver_separate_phy_functions.patch b/target/linux/ixp4xx/patches-2.6.29/205-npe_driver_separate_phy_functions.patch new file mode 100644 index 0000000000..d3e6314a9d --- /dev/null +++ b/target/linux/ixp4xx/patches-2.6.29/205-npe_driver_separate_phy_functions.patch @@ -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); diff --git a/target/linux/ixp4xx/patches-2.6.29/206-npe_driver_add_update_link_function.patch b/target/linux/ixp4xx/patches-2.6.29/206-npe_driver_add_update_link_function.patch new file mode 100644 index 0000000000..2071d23263 --- /dev/null +++ b/target/linux/ixp4xx/patches-2.6.29/206-npe_driver_add_update_link_function.patch @@ -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); + } + diff --git a/target/linux/ixp4xx/patches-2.6.29/207-npe_driver_multiphy_support.patch b/target/linux/ixp4xx/patches-2.6.29/207-npe_driver_multiphy_support.patch new file mode 100644 index 0000000000..89ff69f266 --- /dev/null +++ b/target/linux/ixp4xx/patches-2.6.29/207-npe_driver_multiphy_support.patch @@ -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); + } +