···5959config IXP4XX_ETH6060 tristate "Intel IXP4xx Ethernet support"6161 depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR6262- select MII6262+ select PHYLIB6363 help6464 Say Y here if you want to use built-in Ethernet ports6565 on IXP4xx processor.
+99-103
drivers/net/arm/ixp4xx_eth.c
···3030#include <linux/etherdevice.h>3131#include <linux/io.h>3232#include <linux/kernel.h>3333-#include <linux/mii.h>3333+#include <linux/phy.h>3434#include <linux/platform_device.h>3535#include <mach/npe.h>3636#include <mach/qmgr.h>···5959#define NAPI_WEIGHT 166060#define MDIO_INTERVAL (3 * HZ)6161#define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */6262-#define MAX_MII_RESET_RETRIES 100 /* mdio_read() cycles, typically 4 */6362#define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */64636564#define NPE_ID(port_id) ((port_id) >> 4)···163164 struct npe *npe;164165 struct net_device *netdev;165166 struct napi_struct napi;166166- struct mii_if_info mii;167167- struct delayed_work mdio_thread;167167+ struct phy_device *phydev;168168 struct eth_plat_info *plat;169169 buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS];170170 struct desc *desc_tab; /* coherent */171171 u32 desc_tab_phys;172172 int id; /* logical port ID */173173- u16 mii_bmcr;173173+ int speed, duplex;174174};175175176176/* NPE message structure */···240242241243static spinlock_t mdio_lock;242244static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */245245+struct mii_bus *mdio_bus;243246static int ports_open;244247static struct port *npe_port_tab[MAX_NPES];245248static struct dma_pool *dma_pool;246249247250248248-static u16 mdio_cmd(struct net_device *dev, int phy_id, int location,249249- int write, u16 cmd)251251+static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location,252252+ int write, u16 cmd)250253{251254 int cycles = 0;252255253256 if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {254254- printk(KERN_ERR "%s: MII not ready to transmit\n", dev->name);255255- return 0;257257+ printk(KERN_ERR "%s: MII not ready to transmit\n", bus->name);258258+ return -1;256259 }257260258261 if (write) {···272273 }273274274275 if (cycles == MAX_MDIO_RETRIES) {275275- printk(KERN_ERR "%s: MII write failed\n", dev->name);276276- return 0;276276+ printk(KERN_ERR "%s #%i: MII write failed\n", bus->name,277277+ phy_id);278278+ return -1;277279 }278280279281#if DEBUG_MDIO280280- printk(KERN_DEBUG "%s: mdio_cmd() took %i cycles\n", dev->name,281281- cycles);282282+ printk(KERN_DEBUG "%s #%i: mdio_%s() took %i cycles\n", bus->name,283283+ phy_id, write ? "write" : "read", cycles);282284#endif283285284286 if (write)285287 return 0;286288287289 if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {288288- printk(KERN_ERR "%s: MII read failed\n", dev->name);289289- return 0;290290+#if DEBUG_MDIO291291+ printk(KERN_DEBUG "%s #%i: MII read failed\n", bus->name,292292+ phy_id);293293+#endif294294+ return 0xFFFF; /* don't return error */290295 }291296292297 return (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |293293- (__raw_readl(&mdio_regs->mdio_status[1]) << 8);298298+ ((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8);294299}295300296296-static int mdio_read(struct net_device *dev, int phy_id, int location)301301+static int ixp4xx_mdio_read(struct mii_bus *bus, int phy_id, int location)297302{298303 unsigned long flags;299299- u16 val;304304+ int ret;300305301306 spin_lock_irqsave(&mdio_lock, flags);302302- val = mdio_cmd(dev, phy_id, location, 0, 0);307307+ ret = ixp4xx_mdio_cmd(bus, phy_id, location, 0, 0);303308 spin_unlock_irqrestore(&mdio_lock, flags);304304- return val;309309+#if DEBUG_MDIO310310+ printk(KERN_DEBUG "%s #%i: MII read [%i] -> 0x%X\n", bus->name,311311+ phy_id, location, ret);312312+#endif313313+ return ret;305314}306315307307-static void mdio_write(struct net_device *dev, int phy_id, int location,308308- int val)316316+static int ixp4xx_mdio_write(struct mii_bus *bus, int phy_id, int location,317317+ u16 val)309318{310319 unsigned long flags;320320+ int ret;311321312322 spin_lock_irqsave(&mdio_lock, flags);313313- mdio_cmd(dev, phy_id, location, 1, val);323323+ ret = ixp4xx_mdio_cmd(bus, phy_id, location, 1, val);314324 spin_unlock_irqrestore(&mdio_lock, flags);325325+#if DEBUG_MDIO326326+ printk(KERN_DEBUG "%s #%i: MII read [%i] <- 0x%X, err = %i\n",327327+ bus->name, phy_id, location, val, ret);328328+#endif329329+ return ret;315330}316331317317-static void phy_reset(struct net_device *dev, int phy_id)332332+static int ixp4xx_mdio_register(void)333333+{334334+ int err;335335+336336+ if (!(mdio_bus = mdiobus_alloc()))337337+ return -ENOMEM;338338+339339+ /* All MII PHY accesses use NPE-B Ethernet registers */340340+ spin_lock_init(&mdio_lock);341341+ mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;342342+ __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);343343+344344+ mdio_bus->name = "IXP4xx MII Bus";345345+ mdio_bus->read = &ixp4xx_mdio_read;346346+ mdio_bus->write = &ixp4xx_mdio_write;347347+ strcpy(mdio_bus->id, "0");348348+349349+ if ((err = mdiobus_register(mdio_bus)))350350+ mdiobus_free(mdio_bus);351351+ return err;352352+}353353+354354+static void ixp4xx_mdio_remove(void)355355+{356356+ mdiobus_unregister(mdio_bus);357357+ mdiobus_free(mdio_bus);358358+}359359+360360+361361+static void ixp4xx_adjust_link(struct net_device *dev)318362{319363 struct port *port = netdev_priv(dev);320320- int cycles = 0;364364+ struct phy_device *phydev = port->phydev;321365322322- mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr | BMCR_RESET);323323-324324- while (cycles < MAX_MII_RESET_RETRIES) {325325- if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) {326326-#if DEBUG_MDIO327327- printk(KERN_DEBUG "%s: phy_reset() took %i cycles\n",328328- dev->name, cycles);329329-#endif330330- return;366366+ if (!phydev->link) {367367+ if (port->speed) {368368+ port->speed = 0;369369+ printk(KERN_INFO "%s: link down\n", dev->name);331370 }332332- udelay(1);333333- cycles++;371371+ return;334372 }335373336336- printk(KERN_ERR "%s: MII reset failed\n", dev->name);337337-}374374+ if (port->speed == phydev->speed && port->duplex == phydev->duplex)375375+ return;338376339339-static void eth_set_duplex(struct port *port)340340-{341341- if (port->mii.full_duplex)377377+ port->speed = phydev->speed;378378+ port->duplex = phydev->duplex;379379+380380+ if (port->duplex)342381 __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,343382 &port->regs->tx_control[0]);344383 else345384 __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,346385 &port->regs->tx_control[0]);347347-}348386349349-350350-static void phy_check_media(struct port *port, int init)351351-{352352- if (mii_check_media(&port->mii, 1, init))353353- eth_set_duplex(port);354354- if (port->mii.force_media) { /* mii_check_media() doesn't work */355355- struct net_device *dev = port->netdev;356356- int cur_link = mii_link_ok(&port->mii);357357- int prev_link = netif_carrier_ok(dev);358358-359359- if (!prev_link && cur_link) {360360- printk(KERN_INFO "%s: link up\n", dev->name);361361- netif_carrier_on(dev);362362- } else if (prev_link && !cur_link) {363363- printk(KERN_INFO "%s: link down\n", dev->name);364364- netif_carrier_off(dev);365365- }366366- }367367-}368368-369369-370370-static void mdio_thread(struct work_struct *work)371371-{372372- struct port *port = container_of(work, struct port, mdio_thread.work);373373-374374- phy_check_media(port, 0);375375- schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL);387387+ printk(KERN_INFO "%s: link up, speed %u Mb/s, %s duplex\n",388388+ dev->name, port->speed, port->duplex ? "full" : "half");376389}377390378391···788777789778static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)790779{791791- struct port *port = netdev_priv(dev);792792- unsigned int duplex_chg;793793- int err;794794-795780 if (!netif_running(dev))796781 return -EINVAL;797797- err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg);798798- if (duplex_chg)799799- eth_set_duplex(port);800800- return err;782782+ return -EINVAL;801783}802784803785···942938 }943939 }944940945945- mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr);946946-947941 memset(&msg, 0, sizeof(msg));948942 msg.cmd = NPE_VLAN_SETRXQOSENTRY;949943 msg.eth_id = port->id;···979977 return err;980978 }981979980980+ port->speed = 0; /* force "link up" message */981981+ phy_start(port->phydev);982982+982983 for (i = 0; i < ETH_ALEN; i++)983984 __raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]);984985 __raw_writel(0x08, &port->regs->random_seed);···10091004 __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);1010100510111006 napi_enable(&port->napi);10121012- phy_check_media(port, 1);10131007 eth_set_mcast_list(dev);10141008 netif_start_queue(dev);10151015- schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL);1016100910171010 qmgr_set_irq(port->plat->rxq, QUEUE_IRQ_SRC_NOT_EMPTY,10181011 eth_rx_irq, dev);···11011098 printk(KERN_CRIT "%s: unable to disable loopback\n",11021099 dev->name);1103110011041104- port->mii_bmcr = mdio_read(dev, port->plat->phy, MII_BMCR) &11051105- ~(BMCR_RESET | BMCR_PDOWN); /* may have been altered */11061106- mdio_write(dev, port->plat->phy, MII_BMCR,11071107- port->mii_bmcr | BMCR_PDOWN);11011101+ phy_stop(port->phydev);1108110211091103 if (!ports_open)11101104 qmgr_disable_irq(TXDONE_QUEUE);11111111- cancel_rearming_delayed_work(&port->mdio_thread);11121105 destroy_queues(port);11131106 release_queues(port);11141107 return 0;···11161117 struct net_device *dev;11171118 struct eth_plat_info *plat = pdev->dev.platform_data;11181119 u32 regs_phys;11201120+ char phy_id[BUS_ID_SIZE];11191121 int err;1120112211211123 if (!(dev = alloc_etherdev(sizeof(struct port))))···11821182 __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);11831183 udelay(50);1184118411851185- port->mii.dev = dev;11861186- port->mii.mdio_read = mdio_read;11871187- port->mii.mdio_write = mdio_write;11881188- port->mii.phy_id = plat->phy;11891189- port->mii.phy_id_mask = 0x1F;11901190- port->mii.reg_num_mask = 0x1F;11851185+ snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, "0", plat->phy);11861186+ port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0,11871187+ PHY_INTERFACE_MODE_MII);11881188+ if (IS_ERR(port->phydev)) {11891189+ printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);11901190+ return PTR_ERR(port->phydev);11911191+ }11921192+11931193+ port->phydev->irq = PHY_POLL;1191119411921195 printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,11931196 npe_name(port->npe));1194119711951195- phy_reset(dev, plat->phy);11961196- port->mii_bmcr = mdio_read(dev, plat->phy, MII_BMCR) &11971197- ~(BMCR_RESET | BMCR_PDOWN);11981198- mdio_write(dev, plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN);11991199-12001200- INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread);12011198 return 0;1202119912031200err_unreg:···1228123112291232static int __init eth_init_module(void)12301233{12341234+ int err;12311235 if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))12321236 return -ENOSYS;1233123712341234- /* All MII PHY accesses use NPE-B Ethernet registers */12351235- spin_lock_init(&mdio_lock);12361236- mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;12371237- __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);12381238-12381238+ if ((err = ixp4xx_mdio_register()))12391239+ return err;12391240 return platform_driver_register(&ixp4xx_eth_driver);12401241}1241124212421243static void __exit eth_cleanup_module(void)12431244{12441245 platform_driver_unregister(&ixp4xx_eth_driver);12461246+ ixp4xx_mdio_remove();12451247}1246124812471249MODULE_AUTHOR("Krzysztof Halasa");