Loading MAINTAINERS +6 −1 Original line number Diff line number Diff line Loading @@ -1844,7 +1844,7 @@ P: Haavard Skinnemoen M: hskinnemoen@atmel.com S: Supported GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS GENERIC HDLC (WAN) DRIVERS P: Krzysztof Halasa M: khc@pm.waw.pl W: http://www.kernel.org/pub/linux/utils/net/hdlc/ Loading Loading @@ -2243,6 +2243,11 @@ M: dan.j.williams@intel.com L: linux-kernel@vger.kernel.org S: Supported INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT P: Krzysztof Halasa M: khc@pm.waw.pl S: Maintained INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT P: Deepak Saxena M: dsaxena@plexity.net Loading arch/arm/mach-ixp4xx/include/mach/qmgr.h +33 −2 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ #include <linux/io.h> #include <linux/kernel.h> #define DEBUG_QMGR 0 #define HALF_QUEUES 32 #define QUEUES 64 /* only 32 lower queues currently supported */ #define MAX_QUEUE_LENGTH 4 /* in dwords */ Loading Loading @@ -61,22 +63,51 @@ void qmgr_enable_irq(unsigned int queue); void qmgr_disable_irq(unsigned int queue); /* request_ and release_queue() must be called from non-IRQ context */ #if DEBUG_QMGR extern char qmgr_queue_descs[QUEUES][32]; int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, unsigned int nearly_full_watermark, const char *desc_format, const char* name); #else int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, unsigned int nearly_full_watermark); #define qmgr_request_queue(queue, len, nearly_empty_watermark, \ nearly_full_watermark, desc_format, name) \ __qmgr_request_queue(queue, len, nearly_empty_watermark, \ nearly_full_watermark) #endif void qmgr_release_queue(unsigned int queue); static inline void qmgr_put_entry(unsigned int queue, u32 val) { extern struct qmgr_regs __iomem *qmgr_regs; #if DEBUG_QMGR BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */ printk(KERN_DEBUG "Queue %s(%i) put %X\n", qmgr_queue_descs[queue], queue, val); #endif __raw_writel(val, &qmgr_regs->acc[queue][0]); } static inline u32 qmgr_get_entry(unsigned int queue) { u32 val; extern struct qmgr_regs __iomem *qmgr_regs; return __raw_readl(&qmgr_regs->acc[queue][0]); val = __raw_readl(&qmgr_regs->acc[queue][0]); #if DEBUG_QMGR BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */ printk(KERN_DEBUG "Queue %s(%i) get %X\n", qmgr_queue_descs[queue], queue, val); #endif return val; } static inline int qmgr_get_stat1(unsigned int queue) Loading arch/arm/mach-ixp4xx/ixp4xx_qmgr.c +33 −11 Original line number Diff line number Diff line Loading @@ -14,8 +14,6 @@ #include <linux/module.h> #include <mach/qmgr.h> #define DEBUG 0 struct qmgr_regs __iomem *qmgr_regs; static struct resource *mem_res; static spinlock_t qmgr_lock; Loading @@ -23,6 +21,10 @@ static u32 used_sram_bitmap[4]; /* 128 16-dword pages */ static void (*irq_handlers[HALF_QUEUES])(void *pdev); static void *irq_pdevs[HALF_QUEUES]; #if DEBUG_QMGR char qmgr_queue_descs[QUEUES][32]; #endif void qmgr_set_irq(unsigned int queue, int src, void (*handler)(void *pdev), void *pdev) { Loading Loading @@ -70,6 +72,7 @@ void qmgr_disable_irq(unsigned int queue) spin_lock_irqsave(&qmgr_lock, flags); __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue), &qmgr_regs->irqen[0]); __raw_writel(1 << queue, &qmgr_regs->irqstat[0]); /* clear */ spin_unlock_irqrestore(&qmgr_lock, flags); } Loading @@ -81,9 +84,16 @@ static inline void shift_mask(u32 *mask) mask[0] <<= 1; } #if DEBUG_QMGR int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, unsigned int nearly_full_watermark, const char *desc_format, const char* name) #else int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, unsigned int nearly_full_watermark) #endif { u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ int err; Loading Loading @@ -151,12 +161,13 @@ int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, used_sram_bitmap[2] |= mask[2]; used_sram_bitmap[3] |= mask[3]; __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]); spin_unlock_irq(&qmgr_lock); #if DEBUG printk(KERN_DEBUG "qmgr: requested queue %i, addr = 0x%02X\n", queue, addr); #if DEBUG_QMGR snprintf(qmgr_queue_descs[queue], sizeof(qmgr_queue_descs[0]), desc_format, name); printk(KERN_DEBUG "qmgr: requested queue %s(%i) addr = 0x%02X\n", qmgr_queue_descs[queue], queue, addr); #endif spin_unlock_irq(&qmgr_lock); return 0; err: Loading Loading @@ -189,6 +200,11 @@ void qmgr_release_queue(unsigned int queue) while (addr--) shift_mask(mask); #if DEBUG_QMGR printk(KERN_DEBUG "qmgr: releasing queue %s(%i)\n", qmgr_queue_descs[queue], queue); qmgr_queue_descs[queue][0] = '\x0'; #endif __raw_writel(0, &qmgr_regs->sram[queue]); used_sram_bitmap[0] &= ~mask[0]; Loading @@ -199,9 +215,10 @@ void qmgr_release_queue(unsigned int queue) spin_unlock_irq(&qmgr_lock); module_put(THIS_MODULE); #if DEBUG printk(KERN_DEBUG "qmgr: released queue %i\n", queue); #endif while ((addr = qmgr_get_entry(queue))) printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n", queue, addr); } static int qmgr_init(void) Loading Loading @@ -272,5 +289,10 @@ EXPORT_SYMBOL(qmgr_regs); EXPORT_SYMBOL(qmgr_set_irq); EXPORT_SYMBOL(qmgr_enable_irq); EXPORT_SYMBOL(qmgr_disable_irq); #if DEBUG_QMGR EXPORT_SYMBOL(qmgr_queue_descs); EXPORT_SYMBOL(qmgr_request_queue); #else EXPORT_SYMBOL(__qmgr_request_queue); #endif EXPORT_SYMBOL(qmgr_release_queue); drivers/net/arm/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,7 @@ config EP93XX_ETH config IXP4XX_ETH tristate "Intel IXP4xx Ethernet support" depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR select MII select PHYLIB help Say Y here if you want to use built-in Ethernet ports on IXP4xx processor. drivers/net/arm/ixp4xx_eth.c +173 −164 Original line number Diff line number Diff line Loading @@ -30,12 +30,11 @@ #include <linux/etherdevice.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/mii.h> #include <linux/phy.h> #include <linux/platform_device.h> #include <mach/npe.h> #include <mach/qmgr.h> #define DEBUG_QUEUES 0 #define DEBUG_DESC 0 #define DEBUG_RX 0 #define DEBUG_TX 0 Loading @@ -59,7 +58,6 @@ #define NAPI_WEIGHT 16 #define MDIO_INTERVAL (3 * HZ) #define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */ #define MAX_MII_RESET_RETRIES 100 /* mdio_read() cycles, typically 4 */ #define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */ #define NPE_ID(port_id) ((port_id) >> 4) Loading Loading @@ -164,15 +162,14 @@ struct port { struct npe *npe; struct net_device *netdev; struct napi_struct napi; struct net_device_stats stat; struct mii_if_info mii; struct delayed_work mdio_thread; struct phy_device *phydev; struct eth_plat_info *plat; buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS]; struct desc *desc_tab; /* coherent */ u32 desc_tab_phys; int id; /* logical port ID */ u16 mii_bmcr; int speed, duplex; u8 firmware[4]; }; /* NPE message structure */ Loading Loading @@ -243,19 +240,20 @@ static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt) static spinlock_t mdio_lock; static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */ struct mii_bus *mdio_bus; static int ports_open; static struct port *npe_port_tab[MAX_NPES]; static struct dma_pool *dma_pool; static u16 mdio_cmd(struct net_device *dev, int phy_id, int location, static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location, int write, u16 cmd) { int cycles = 0; if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) { printk(KERN_ERR "%s: MII not ready to transmit\n", dev->name); return 0; printk(KERN_ERR "%s: MII not ready to transmit\n", bus->name); return -1; } if (write) { Loading @@ -274,107 +272,119 @@ static u16 mdio_cmd(struct net_device *dev, int phy_id, int location, } if (cycles == MAX_MDIO_RETRIES) { printk(KERN_ERR "%s: MII write failed\n", dev->name); return 0; printk(KERN_ERR "%s #%i: MII write failed\n", bus->name, phy_id); return -1; } #if DEBUG_MDIO printk(KERN_DEBUG "%s: mdio_cmd() took %i cycles\n", dev->name, cycles); printk(KERN_DEBUG "%s #%i: mdio_%s() took %i cycles\n", bus->name, phy_id, write ? "write" : "read", cycles); #endif if (write) return 0; if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) { printk(KERN_ERR "%s: MII read failed\n", dev->name); return 0; #if DEBUG_MDIO printk(KERN_DEBUG "%s #%i: MII read failed\n", bus->name, phy_id); #endif return 0xFFFF; /* don't return error */ } return (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) | (__raw_readl(&mdio_regs->mdio_status[1]) << 8); ((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8); } static int mdio_read(struct net_device *dev, int phy_id, int location) static int ixp4xx_mdio_read(struct mii_bus *bus, int phy_id, int location) { unsigned long flags; u16 val; int ret; spin_lock_irqsave(&mdio_lock, flags); val = mdio_cmd(dev, phy_id, location, 0, 0); ret = ixp4xx_mdio_cmd(bus, phy_id, location, 0, 0); spin_unlock_irqrestore(&mdio_lock, flags); return val; #if DEBUG_MDIO printk(KERN_DEBUG "%s #%i: MII read [%i] -> 0x%X\n", bus->name, phy_id, location, ret); #endif return ret; } static void mdio_write(struct net_device *dev, int phy_id, int location, int val) static int ixp4xx_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val) { unsigned long flags; int ret; spin_lock_irqsave(&mdio_lock, flags); mdio_cmd(dev, phy_id, location, 1, val); ret = ixp4xx_mdio_cmd(bus, phy_id, location, 1, val); spin_unlock_irqrestore(&mdio_lock, flags); #if DEBUG_MDIO printk(KERN_DEBUG "%s #%i: MII read [%i] <- 0x%X, err = %i\n", bus->name, phy_id, location, val, ret); #endif return ret; } static void phy_reset(struct net_device *dev, int phy_id) static int ixp4xx_mdio_register(void) { struct port *port = netdev_priv(dev); int cycles = 0; int err; mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr | BMCR_RESET); if (!(mdio_bus = mdiobus_alloc())) return -ENOMEM; while (cycles < MAX_MII_RESET_RETRIES) { if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) { #if DEBUG_MDIO printk(KERN_DEBUG "%s: phy_reset() took %i cycles\n", dev->name, cycles); #endif return; } udelay(1); cycles++; } /* All MII PHY accesses use NPE-B Ethernet registers */ spin_lock_init(&mdio_lock); mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control); mdio_bus->name = "IXP4xx MII Bus"; mdio_bus->read = &ixp4xx_mdio_read; mdio_bus->write = &ixp4xx_mdio_write; strcpy(mdio_bus->id, "0"); printk(KERN_ERR "%s: MII reset failed\n", dev->name); if ((err = mdiobus_register(mdio_bus))) mdiobus_free(mdio_bus); return err; } static void eth_set_duplex(struct port *port) static void ixp4xx_mdio_remove(void) { if (port->mii.full_duplex) __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]); mdiobus_unregister(mdio_bus); mdiobus_free(mdio_bus); } static void phy_check_media(struct port *port, int init) static void ixp4xx_adjust_link(struct net_device *dev) { if (mii_check_media(&port->mii, 1, init)) eth_set_duplex(port); if (port->mii.force_media) { /* mii_check_media() doesn't work */ struct net_device *dev = port->netdev; int cur_link = mii_link_ok(&port->mii); int prev_link = netif_carrier_ok(dev); struct port *port = netdev_priv(dev); struct phy_device *phydev = port->phydev; if (!prev_link && cur_link) { printk(KERN_INFO "%s: link up\n", dev->name); netif_carrier_on(dev); } else if (prev_link && !cur_link) { if (!phydev->link) { if (port->speed) { port->speed = 0; printk(KERN_INFO "%s: link down\n", dev->name); netif_carrier_off(dev); } } return; } if (port->speed == phydev->speed && port->duplex == phydev->duplex) return; static void mdio_thread(struct work_struct *work) { struct port *port = container_of(work, struct port, mdio_thread.work); port->speed = phydev->speed; port->duplex = phydev->duplex; if (port->duplex) __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]); phy_check_media(port, 0); schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL); printk(KERN_INFO "%s: link up, speed %u Mb/s, %s duplex\n", dev->name, port->speed, port->duplex ? "full" : "half"); } Loading Loading @@ -412,47 +422,13 @@ static inline void debug_desc(u32 phys, struct desc *desc) #endif } static inline void debug_queue(unsigned int queue, int is_get, u32 phys) { #if DEBUG_QUEUES static struct { int queue; char *name; } names[] = { { TX_QUEUE(0x10), "TX#0 " }, { TX_QUEUE(0x20), "TX#1 " }, { TX_QUEUE(0x00), "TX#2 " }, { RXFREE_QUEUE(0x10), "RX-free#0 " }, { RXFREE_QUEUE(0x20), "RX-free#1 " }, { RXFREE_QUEUE(0x00), "RX-free#2 " }, { TXDONE_QUEUE, "TX-done " }, }; int i; for (i = 0; i < ARRAY_SIZE(names); i++) if (names[i].queue == queue) break; printk(KERN_DEBUG "Queue %i %s%s %X\n", queue, i < ARRAY_SIZE(names) ? names[i].name : "", is_get ? "->" : "<-", phys); #endif } static inline u32 queue_get_entry(unsigned int queue) { u32 phys = qmgr_get_entry(queue); debug_queue(queue, 1, phys); return phys; } static inline int queue_get_desc(unsigned int queue, struct port *port, int is_tx) { u32 phys, tab_phys, n_desc; struct desc *tab; if (!(phys = queue_get_entry(queue))) if (!(phys = qmgr_get_entry(queue))) return -1; phys &= ~0x1F; /* mask out non-address bits */ Loading @@ -468,7 +444,6 @@ static inline int queue_get_desc(unsigned int queue, struct port *port, static inline void queue_put_desc(unsigned int queue, u32 phys, struct desc *desc) { debug_queue(queue, 0, phys); debug_desc(phys, desc); BUG_ON(phys & 0x1F); qmgr_put_entry(queue, phys); Loading Loading @@ -562,7 +537,7 @@ static int eth_poll(struct napi_struct *napi, int budget) #endif if (!skb) { port->stat.rx_dropped++; dev->stats.rx_dropped++; /* put the desc back on RX-ready queue */ desc->buf_len = MAX_MRU; desc->pkt_len = 0; Loading @@ -588,8 +563,8 @@ static int eth_poll(struct napi_struct *napi, int budget) debug_pkt(dev, "eth_poll", skb->data, skb->len); skb->protocol = eth_type_trans(skb, dev); port->stat.rx_packets++; port->stat.rx_bytes += skb->len; dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; netif_receive_skb(skb); /* put the new buffer on RX-free queue */ Loading Loading @@ -617,7 +592,7 @@ static void eth_txdone_irq(void *unused) #if DEBUG_TX printk(KERN_DEBUG DRV_NAME ": eth_txdone_irq\n"); #endif while ((phys = queue_get_entry(TXDONE_QUEUE)) != 0) { while ((phys = qmgr_get_entry(TXDONE_QUEUE)) != 0) { u32 npe_id, n_desc; struct port *port; struct desc *desc; Loading @@ -634,8 +609,8 @@ static void eth_txdone_irq(void *unused) debug_desc(phys, desc); if (port->tx_buff_tab[n_desc]) { /* not the draining packet */ port->stat.tx_packets++; port->stat.tx_bytes += desc->pkt_len; port->netdev->stats.tx_packets++; port->netdev->stats.tx_bytes += desc->pkt_len; dma_unmap_tx(port, desc); #if DEBUG_TX Loading Loading @@ -673,7 +648,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len > MAX_MRU)) { dev_kfree_skb(skb); port->stat.tx_errors++; dev->stats.tx_errors++; return NETDEV_TX_OK; } Loading @@ -689,7 +664,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) bytes = ALIGN(offset + len, 4); if (!(mem = kmalloc(bytes, GFP_ATOMIC))) { dev_kfree_skb(skb); port->stat.tx_dropped++; dev->stats.tx_dropped++; return NETDEV_TX_OK; } memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4); Loading @@ -703,7 +678,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) #else kfree(mem); #endif port->stat.tx_dropped++; dev->stats.tx_dropped++; return NETDEV_TX_OK; } Loading Loading @@ -746,12 +721,6 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) } static struct net_device_stats *eth_stats(struct net_device *dev) { struct port *port = netdev_priv(dev); return &port->stat; } static void eth_set_mcast_list(struct net_device *dev) { struct port *port = netdev_priv(dev); Loading Loading @@ -785,41 +754,80 @@ static void eth_set_mcast_list(struct net_device *dev) static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd) { struct port *port = netdev_priv(dev); unsigned int duplex_chg; int err; if (!netif_running(dev)) return -EINVAL; err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg); if (duplex_chg) eth_set_duplex(port); return err; return phy_mii_ioctl(port->phydev, if_mii(req), cmd); } /* ethtool support */ static void ixp4xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct port *port = netdev_priv(dev); strcpy(info->driver, DRV_NAME); snprintf(info->fw_version, sizeof(info->fw_version), "%u:%u:%u:%u", port->firmware[0], port->firmware[1], port->firmware[2], port->firmware[3]); strcpy(info->bus_info, "internal"); } static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct port *port = netdev_priv(dev); 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); return phy_ethtool_sset(port->phydev, cmd); } static int ixp4xx_nway_reset(struct net_device *dev) { struct port *port = netdev_priv(dev); return phy_start_aneg(port->phydev); } static struct ethtool_ops ixp4xx_ethtool_ops = { .get_drvinfo = ixp4xx_get_drvinfo, .get_settings = ixp4xx_get_settings, .set_settings = ixp4xx_set_settings, .nway_reset = ixp4xx_nway_reset, .get_link = ethtool_op_get_link, }; static int request_queues(struct port *port) { int err; err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0); err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0, "%s:RX-free", port->netdev->name); if (err) return err; err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0); err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0, "%s:RX", port->netdev->name); if (err) goto rel_rxfree; err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0); err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0, "%s:TX", port->netdev->name); if (err) goto rel_rx; err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0); err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0, "%s:TX-ready", port->netdev->name); if (err) goto rel_tx; /* TX-done queue handles skbs sent out by the NPEs */ if (!ports_open) { err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0); err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0, "%s:TX-done", DRV_NAME); if (err) goto rel_txready; } Loading Loading @@ -943,10 +951,12 @@ static int eth_open(struct net_device *dev) npe_name(npe)); return -EIO; } port->firmware[0] = msg.byte4; port->firmware[1] = msg.byte5; port->firmware[2] = msg.byte6; port->firmware[3] = msg.byte7; } mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr); memset(&msg, 0, sizeof(msg)); msg.cmd = NPE_VLAN_SETRXQOSENTRY; msg.eth_id = port->id; Loading Loading @@ -984,6 +994,9 @@ static int eth_open(struct net_device *dev) return err; } port->speed = 0; /* force "link up" message */ phy_start(port->phydev); for (i = 0; i < ETH_ALEN; i++) __raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]); __raw_writel(0x08, &port->regs->random_seed); Loading Loading @@ -1011,10 +1024,8 @@ static int eth_open(struct net_device *dev) __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]); napi_enable(&port->napi); phy_check_media(port, 1); eth_set_mcast_list(dev); netif_start_queue(dev); schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL); qmgr_set_irq(port->plat->rxq, QUEUE_IRQ_SRC_NOT_EMPTY, eth_rx_irq, dev); Loading Loading @@ -1105,25 +1116,31 @@ static int eth_close(struct net_device *dev) printk(KERN_CRIT "%s: unable to disable loopback\n", dev->name); port->mii_bmcr = mdio_read(dev, port->plat->phy, MII_BMCR) & ~(BMCR_RESET | BMCR_PDOWN); /* may have been altered */ mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN); phy_stop(port->phydev); if (!ports_open) qmgr_disable_irq(TXDONE_QUEUE); cancel_rearming_delayed_work(&port->mdio_thread); destroy_queues(port); release_queues(port); return 0; } static const struct net_device_ops ixp4xx_netdev_ops = { .ndo_open = eth_open, .ndo_stop = eth_close, .ndo_start_xmit = eth_xmit, .ndo_set_multicast_list = eth_set_mcast_list, .ndo_do_ioctl = eth_ioctl, }; static int __devinit eth_init_one(struct platform_device *pdev) { struct port *port; 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)))) Loading Loading @@ -1152,12 +1169,8 @@ static int __devinit eth_init_one(struct platform_device *pdev) goto err_free; } dev->open = eth_open; dev->hard_start_xmit = eth_xmit; dev->stop = eth_close; dev->get_stats = eth_stats; dev->do_ioctl = eth_ioctl; dev->set_multicast_list = eth_set_mcast_list; dev->netdev_ops = &ixp4xx_netdev_ops; dev->ethtool_ops = &ixp4xx_ethtool_ops; dev->tx_queue_len = 100; netif_napi_add(dev, &port->napi, eth_poll, NAPI_WEIGHT); Loading Loading @@ -1190,22 +1203,19 @@ static int __devinit eth_init_one(struct platform_device *pdev) __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control); udelay(50); port->mii.dev = dev; port->mii.mdio_read = mdio_read; port->mii.mdio_write = mdio_write; port->mii.phy_id = plat->phy; port->mii.phy_id_mask = 0x1F; port->mii.reg_num_mask = 0x1F; 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); } port->phydev->irq = PHY_POLL; printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy, npe_name(port->npe)); phy_reset(dev, plat->phy); port->mii_bmcr = mdio_read(dev, plat->phy, MII_BMCR) & ~(BMCR_RESET | BMCR_PDOWN); mdio_write(dev, plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN); INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread); return 0; err_unreg: Loading @@ -1231,7 +1241,7 @@ static int __devexit eth_remove_one(struct platform_device *pdev) return 0; } static struct platform_driver drv = { static struct platform_driver ixp4xx_eth_driver = { .driver.name = DRV_NAME, .probe = eth_init_one, .remove = eth_remove_one, Loading @@ -1239,20 +1249,19 @@ static struct platform_driver drv = { static int __init eth_init_module(void) { int err; if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0)) return -ENOSYS; /* All MII PHY accesses use NPE-B Ethernet registers */ spin_lock_init(&mdio_lock); mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control); return platform_driver_register(&drv); if ((err = ixp4xx_mdio_register())) return err; return platform_driver_register(&ixp4xx_eth_driver); } static void __exit eth_cleanup_module(void) { platform_driver_unregister(&drv); platform_driver_unregister(&ixp4xx_eth_driver); ixp4xx_mdio_remove(); } MODULE_AUTHOR("Krzysztof Halasa"); Loading Loading
MAINTAINERS +6 −1 Original line number Diff line number Diff line Loading @@ -1844,7 +1844,7 @@ P: Haavard Skinnemoen M: hskinnemoen@atmel.com S: Supported GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS GENERIC HDLC (WAN) DRIVERS P: Krzysztof Halasa M: khc@pm.waw.pl W: http://www.kernel.org/pub/linux/utils/net/hdlc/ Loading Loading @@ -2243,6 +2243,11 @@ M: dan.j.williams@intel.com L: linux-kernel@vger.kernel.org S: Supported INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT P: Krzysztof Halasa M: khc@pm.waw.pl S: Maintained INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT P: Deepak Saxena M: dsaxena@plexity.net Loading
arch/arm/mach-ixp4xx/include/mach/qmgr.h +33 −2 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ #include <linux/io.h> #include <linux/kernel.h> #define DEBUG_QMGR 0 #define HALF_QUEUES 32 #define QUEUES 64 /* only 32 lower queues currently supported */ #define MAX_QUEUE_LENGTH 4 /* in dwords */ Loading Loading @@ -61,22 +63,51 @@ void qmgr_enable_irq(unsigned int queue); void qmgr_disable_irq(unsigned int queue); /* request_ and release_queue() must be called from non-IRQ context */ #if DEBUG_QMGR extern char qmgr_queue_descs[QUEUES][32]; int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, unsigned int nearly_full_watermark, const char *desc_format, const char* name); #else int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, unsigned int nearly_full_watermark); #define qmgr_request_queue(queue, len, nearly_empty_watermark, \ nearly_full_watermark, desc_format, name) \ __qmgr_request_queue(queue, len, nearly_empty_watermark, \ nearly_full_watermark) #endif void qmgr_release_queue(unsigned int queue); static inline void qmgr_put_entry(unsigned int queue, u32 val) { extern struct qmgr_regs __iomem *qmgr_regs; #if DEBUG_QMGR BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */ printk(KERN_DEBUG "Queue %s(%i) put %X\n", qmgr_queue_descs[queue], queue, val); #endif __raw_writel(val, &qmgr_regs->acc[queue][0]); } static inline u32 qmgr_get_entry(unsigned int queue) { u32 val; extern struct qmgr_regs __iomem *qmgr_regs; return __raw_readl(&qmgr_regs->acc[queue][0]); val = __raw_readl(&qmgr_regs->acc[queue][0]); #if DEBUG_QMGR BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */ printk(KERN_DEBUG "Queue %s(%i) get %X\n", qmgr_queue_descs[queue], queue, val); #endif return val; } static inline int qmgr_get_stat1(unsigned int queue) Loading
arch/arm/mach-ixp4xx/ixp4xx_qmgr.c +33 −11 Original line number Diff line number Diff line Loading @@ -14,8 +14,6 @@ #include <linux/module.h> #include <mach/qmgr.h> #define DEBUG 0 struct qmgr_regs __iomem *qmgr_regs; static struct resource *mem_res; static spinlock_t qmgr_lock; Loading @@ -23,6 +21,10 @@ static u32 used_sram_bitmap[4]; /* 128 16-dword pages */ static void (*irq_handlers[HALF_QUEUES])(void *pdev); static void *irq_pdevs[HALF_QUEUES]; #if DEBUG_QMGR char qmgr_queue_descs[QUEUES][32]; #endif void qmgr_set_irq(unsigned int queue, int src, void (*handler)(void *pdev), void *pdev) { Loading Loading @@ -70,6 +72,7 @@ void qmgr_disable_irq(unsigned int queue) spin_lock_irqsave(&qmgr_lock, flags); __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue), &qmgr_regs->irqen[0]); __raw_writel(1 << queue, &qmgr_regs->irqstat[0]); /* clear */ spin_unlock_irqrestore(&qmgr_lock, flags); } Loading @@ -81,9 +84,16 @@ static inline void shift_mask(u32 *mask) mask[0] <<= 1; } #if DEBUG_QMGR int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, unsigned int nearly_full_watermark, const char *desc_format, const char* name) #else int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, unsigned int nearly_full_watermark) #endif { u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ int err; Loading Loading @@ -151,12 +161,13 @@ int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, used_sram_bitmap[2] |= mask[2]; used_sram_bitmap[3] |= mask[3]; __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]); spin_unlock_irq(&qmgr_lock); #if DEBUG printk(KERN_DEBUG "qmgr: requested queue %i, addr = 0x%02X\n", queue, addr); #if DEBUG_QMGR snprintf(qmgr_queue_descs[queue], sizeof(qmgr_queue_descs[0]), desc_format, name); printk(KERN_DEBUG "qmgr: requested queue %s(%i) addr = 0x%02X\n", qmgr_queue_descs[queue], queue, addr); #endif spin_unlock_irq(&qmgr_lock); return 0; err: Loading Loading @@ -189,6 +200,11 @@ void qmgr_release_queue(unsigned int queue) while (addr--) shift_mask(mask); #if DEBUG_QMGR printk(KERN_DEBUG "qmgr: releasing queue %s(%i)\n", qmgr_queue_descs[queue], queue); qmgr_queue_descs[queue][0] = '\x0'; #endif __raw_writel(0, &qmgr_regs->sram[queue]); used_sram_bitmap[0] &= ~mask[0]; Loading @@ -199,9 +215,10 @@ void qmgr_release_queue(unsigned int queue) spin_unlock_irq(&qmgr_lock); module_put(THIS_MODULE); #if DEBUG printk(KERN_DEBUG "qmgr: released queue %i\n", queue); #endif while ((addr = qmgr_get_entry(queue))) printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n", queue, addr); } static int qmgr_init(void) Loading Loading @@ -272,5 +289,10 @@ EXPORT_SYMBOL(qmgr_regs); EXPORT_SYMBOL(qmgr_set_irq); EXPORT_SYMBOL(qmgr_enable_irq); EXPORT_SYMBOL(qmgr_disable_irq); #if DEBUG_QMGR EXPORT_SYMBOL(qmgr_queue_descs); EXPORT_SYMBOL(qmgr_request_queue); #else EXPORT_SYMBOL(__qmgr_request_queue); #endif EXPORT_SYMBOL(qmgr_release_queue);
drivers/net/arm/Kconfig +1 −1 Original line number Diff line number Diff line Loading @@ -59,7 +59,7 @@ config EP93XX_ETH config IXP4XX_ETH tristate "Intel IXP4xx Ethernet support" depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR select MII select PHYLIB help Say Y here if you want to use built-in Ethernet ports on IXP4xx processor.
drivers/net/arm/ixp4xx_eth.c +173 −164 Original line number Diff line number Diff line Loading @@ -30,12 +30,11 @@ #include <linux/etherdevice.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/mii.h> #include <linux/phy.h> #include <linux/platform_device.h> #include <mach/npe.h> #include <mach/qmgr.h> #define DEBUG_QUEUES 0 #define DEBUG_DESC 0 #define DEBUG_RX 0 #define DEBUG_TX 0 Loading @@ -59,7 +58,6 @@ #define NAPI_WEIGHT 16 #define MDIO_INTERVAL (3 * HZ) #define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */ #define MAX_MII_RESET_RETRIES 100 /* mdio_read() cycles, typically 4 */ #define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */ #define NPE_ID(port_id) ((port_id) >> 4) Loading Loading @@ -164,15 +162,14 @@ struct port { struct npe *npe; struct net_device *netdev; struct napi_struct napi; struct net_device_stats stat; struct mii_if_info mii; struct delayed_work mdio_thread; struct phy_device *phydev; struct eth_plat_info *plat; buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS]; struct desc *desc_tab; /* coherent */ u32 desc_tab_phys; int id; /* logical port ID */ u16 mii_bmcr; int speed, duplex; u8 firmware[4]; }; /* NPE message structure */ Loading Loading @@ -243,19 +240,20 @@ static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt) static spinlock_t mdio_lock; static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */ struct mii_bus *mdio_bus; static int ports_open; static struct port *npe_port_tab[MAX_NPES]; static struct dma_pool *dma_pool; static u16 mdio_cmd(struct net_device *dev, int phy_id, int location, static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location, int write, u16 cmd) { int cycles = 0; if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) { printk(KERN_ERR "%s: MII not ready to transmit\n", dev->name); return 0; printk(KERN_ERR "%s: MII not ready to transmit\n", bus->name); return -1; } if (write) { Loading @@ -274,107 +272,119 @@ static u16 mdio_cmd(struct net_device *dev, int phy_id, int location, } if (cycles == MAX_MDIO_RETRIES) { printk(KERN_ERR "%s: MII write failed\n", dev->name); return 0; printk(KERN_ERR "%s #%i: MII write failed\n", bus->name, phy_id); return -1; } #if DEBUG_MDIO printk(KERN_DEBUG "%s: mdio_cmd() took %i cycles\n", dev->name, cycles); printk(KERN_DEBUG "%s #%i: mdio_%s() took %i cycles\n", bus->name, phy_id, write ? "write" : "read", cycles); #endif if (write) return 0; if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) { printk(KERN_ERR "%s: MII read failed\n", dev->name); return 0; #if DEBUG_MDIO printk(KERN_DEBUG "%s #%i: MII read failed\n", bus->name, phy_id); #endif return 0xFFFF; /* don't return error */ } return (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) | (__raw_readl(&mdio_regs->mdio_status[1]) << 8); ((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8); } static int mdio_read(struct net_device *dev, int phy_id, int location) static int ixp4xx_mdio_read(struct mii_bus *bus, int phy_id, int location) { unsigned long flags; u16 val; int ret; spin_lock_irqsave(&mdio_lock, flags); val = mdio_cmd(dev, phy_id, location, 0, 0); ret = ixp4xx_mdio_cmd(bus, phy_id, location, 0, 0); spin_unlock_irqrestore(&mdio_lock, flags); return val; #if DEBUG_MDIO printk(KERN_DEBUG "%s #%i: MII read [%i] -> 0x%X\n", bus->name, phy_id, location, ret); #endif return ret; } static void mdio_write(struct net_device *dev, int phy_id, int location, int val) static int ixp4xx_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val) { unsigned long flags; int ret; spin_lock_irqsave(&mdio_lock, flags); mdio_cmd(dev, phy_id, location, 1, val); ret = ixp4xx_mdio_cmd(bus, phy_id, location, 1, val); spin_unlock_irqrestore(&mdio_lock, flags); #if DEBUG_MDIO printk(KERN_DEBUG "%s #%i: MII read [%i] <- 0x%X, err = %i\n", bus->name, phy_id, location, val, ret); #endif return ret; } static void phy_reset(struct net_device *dev, int phy_id) static int ixp4xx_mdio_register(void) { struct port *port = netdev_priv(dev); int cycles = 0; int err; mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr | BMCR_RESET); if (!(mdio_bus = mdiobus_alloc())) return -ENOMEM; while (cycles < MAX_MII_RESET_RETRIES) { if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) { #if DEBUG_MDIO printk(KERN_DEBUG "%s: phy_reset() took %i cycles\n", dev->name, cycles); #endif return; } udelay(1); cycles++; } /* All MII PHY accesses use NPE-B Ethernet registers */ spin_lock_init(&mdio_lock); mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control); mdio_bus->name = "IXP4xx MII Bus"; mdio_bus->read = &ixp4xx_mdio_read; mdio_bus->write = &ixp4xx_mdio_write; strcpy(mdio_bus->id, "0"); printk(KERN_ERR "%s: MII reset failed\n", dev->name); if ((err = mdiobus_register(mdio_bus))) mdiobus_free(mdio_bus); return err; } static void eth_set_duplex(struct port *port) static void ixp4xx_mdio_remove(void) { if (port->mii.full_duplex) __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]); mdiobus_unregister(mdio_bus); mdiobus_free(mdio_bus); } static void phy_check_media(struct port *port, int init) static void ixp4xx_adjust_link(struct net_device *dev) { if (mii_check_media(&port->mii, 1, init)) eth_set_duplex(port); if (port->mii.force_media) { /* mii_check_media() doesn't work */ struct net_device *dev = port->netdev; int cur_link = mii_link_ok(&port->mii); int prev_link = netif_carrier_ok(dev); struct port *port = netdev_priv(dev); struct phy_device *phydev = port->phydev; if (!prev_link && cur_link) { printk(KERN_INFO "%s: link up\n", dev->name); netif_carrier_on(dev); } else if (prev_link && !cur_link) { if (!phydev->link) { if (port->speed) { port->speed = 0; printk(KERN_INFO "%s: link down\n", dev->name); netif_carrier_off(dev); } } return; } if (port->speed == phydev->speed && port->duplex == phydev->duplex) return; static void mdio_thread(struct work_struct *work) { struct port *port = container_of(work, struct port, mdio_thread.work); port->speed = phydev->speed; port->duplex = phydev->duplex; if (port->duplex) __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]); phy_check_media(port, 0); schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL); printk(KERN_INFO "%s: link up, speed %u Mb/s, %s duplex\n", dev->name, port->speed, port->duplex ? "full" : "half"); } Loading Loading @@ -412,47 +422,13 @@ static inline void debug_desc(u32 phys, struct desc *desc) #endif } static inline void debug_queue(unsigned int queue, int is_get, u32 phys) { #if DEBUG_QUEUES static struct { int queue; char *name; } names[] = { { TX_QUEUE(0x10), "TX#0 " }, { TX_QUEUE(0x20), "TX#1 " }, { TX_QUEUE(0x00), "TX#2 " }, { RXFREE_QUEUE(0x10), "RX-free#0 " }, { RXFREE_QUEUE(0x20), "RX-free#1 " }, { RXFREE_QUEUE(0x00), "RX-free#2 " }, { TXDONE_QUEUE, "TX-done " }, }; int i; for (i = 0; i < ARRAY_SIZE(names); i++) if (names[i].queue == queue) break; printk(KERN_DEBUG "Queue %i %s%s %X\n", queue, i < ARRAY_SIZE(names) ? names[i].name : "", is_get ? "->" : "<-", phys); #endif } static inline u32 queue_get_entry(unsigned int queue) { u32 phys = qmgr_get_entry(queue); debug_queue(queue, 1, phys); return phys; } static inline int queue_get_desc(unsigned int queue, struct port *port, int is_tx) { u32 phys, tab_phys, n_desc; struct desc *tab; if (!(phys = queue_get_entry(queue))) if (!(phys = qmgr_get_entry(queue))) return -1; phys &= ~0x1F; /* mask out non-address bits */ Loading @@ -468,7 +444,6 @@ static inline int queue_get_desc(unsigned int queue, struct port *port, static inline void queue_put_desc(unsigned int queue, u32 phys, struct desc *desc) { debug_queue(queue, 0, phys); debug_desc(phys, desc); BUG_ON(phys & 0x1F); qmgr_put_entry(queue, phys); Loading Loading @@ -562,7 +537,7 @@ static int eth_poll(struct napi_struct *napi, int budget) #endif if (!skb) { port->stat.rx_dropped++; dev->stats.rx_dropped++; /* put the desc back on RX-ready queue */ desc->buf_len = MAX_MRU; desc->pkt_len = 0; Loading @@ -588,8 +563,8 @@ static int eth_poll(struct napi_struct *napi, int budget) debug_pkt(dev, "eth_poll", skb->data, skb->len); skb->protocol = eth_type_trans(skb, dev); port->stat.rx_packets++; port->stat.rx_bytes += skb->len; dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; netif_receive_skb(skb); /* put the new buffer on RX-free queue */ Loading Loading @@ -617,7 +592,7 @@ static void eth_txdone_irq(void *unused) #if DEBUG_TX printk(KERN_DEBUG DRV_NAME ": eth_txdone_irq\n"); #endif while ((phys = queue_get_entry(TXDONE_QUEUE)) != 0) { while ((phys = qmgr_get_entry(TXDONE_QUEUE)) != 0) { u32 npe_id, n_desc; struct port *port; struct desc *desc; Loading @@ -634,8 +609,8 @@ static void eth_txdone_irq(void *unused) debug_desc(phys, desc); if (port->tx_buff_tab[n_desc]) { /* not the draining packet */ port->stat.tx_packets++; port->stat.tx_bytes += desc->pkt_len; port->netdev->stats.tx_packets++; port->netdev->stats.tx_bytes += desc->pkt_len; dma_unmap_tx(port, desc); #if DEBUG_TX Loading Loading @@ -673,7 +648,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len > MAX_MRU)) { dev_kfree_skb(skb); port->stat.tx_errors++; dev->stats.tx_errors++; return NETDEV_TX_OK; } Loading @@ -689,7 +664,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) bytes = ALIGN(offset + len, 4); if (!(mem = kmalloc(bytes, GFP_ATOMIC))) { dev_kfree_skb(skb); port->stat.tx_dropped++; dev->stats.tx_dropped++; return NETDEV_TX_OK; } memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4); Loading @@ -703,7 +678,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) #else kfree(mem); #endif port->stat.tx_dropped++; dev->stats.tx_dropped++; return NETDEV_TX_OK; } Loading Loading @@ -746,12 +721,6 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) } static struct net_device_stats *eth_stats(struct net_device *dev) { struct port *port = netdev_priv(dev); return &port->stat; } static void eth_set_mcast_list(struct net_device *dev) { struct port *port = netdev_priv(dev); Loading Loading @@ -785,41 +754,80 @@ static void eth_set_mcast_list(struct net_device *dev) static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd) { struct port *port = netdev_priv(dev); unsigned int duplex_chg; int err; if (!netif_running(dev)) return -EINVAL; err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg); if (duplex_chg) eth_set_duplex(port); return err; return phy_mii_ioctl(port->phydev, if_mii(req), cmd); } /* ethtool support */ static void ixp4xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct port *port = netdev_priv(dev); strcpy(info->driver, DRV_NAME); snprintf(info->fw_version, sizeof(info->fw_version), "%u:%u:%u:%u", port->firmware[0], port->firmware[1], port->firmware[2], port->firmware[3]); strcpy(info->bus_info, "internal"); } static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct port *port = netdev_priv(dev); 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); return phy_ethtool_sset(port->phydev, cmd); } static int ixp4xx_nway_reset(struct net_device *dev) { struct port *port = netdev_priv(dev); return phy_start_aneg(port->phydev); } static struct ethtool_ops ixp4xx_ethtool_ops = { .get_drvinfo = ixp4xx_get_drvinfo, .get_settings = ixp4xx_get_settings, .set_settings = ixp4xx_set_settings, .nway_reset = ixp4xx_nway_reset, .get_link = ethtool_op_get_link, }; static int request_queues(struct port *port) { int err; err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0); err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0, "%s:RX-free", port->netdev->name); if (err) return err; err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0); err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0, "%s:RX", port->netdev->name); if (err) goto rel_rxfree; err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0); err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0, "%s:TX", port->netdev->name); if (err) goto rel_rx; err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0); err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0, "%s:TX-ready", port->netdev->name); if (err) goto rel_tx; /* TX-done queue handles skbs sent out by the NPEs */ if (!ports_open) { err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0); err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0, "%s:TX-done", DRV_NAME); if (err) goto rel_txready; } Loading Loading @@ -943,10 +951,12 @@ static int eth_open(struct net_device *dev) npe_name(npe)); return -EIO; } port->firmware[0] = msg.byte4; port->firmware[1] = msg.byte5; port->firmware[2] = msg.byte6; port->firmware[3] = msg.byte7; } mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr); memset(&msg, 0, sizeof(msg)); msg.cmd = NPE_VLAN_SETRXQOSENTRY; msg.eth_id = port->id; Loading Loading @@ -984,6 +994,9 @@ static int eth_open(struct net_device *dev) return err; } port->speed = 0; /* force "link up" message */ phy_start(port->phydev); for (i = 0; i < ETH_ALEN; i++) __raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]); __raw_writel(0x08, &port->regs->random_seed); Loading Loading @@ -1011,10 +1024,8 @@ static int eth_open(struct net_device *dev) __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]); napi_enable(&port->napi); phy_check_media(port, 1); eth_set_mcast_list(dev); netif_start_queue(dev); schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL); qmgr_set_irq(port->plat->rxq, QUEUE_IRQ_SRC_NOT_EMPTY, eth_rx_irq, dev); Loading Loading @@ -1105,25 +1116,31 @@ static int eth_close(struct net_device *dev) printk(KERN_CRIT "%s: unable to disable loopback\n", dev->name); port->mii_bmcr = mdio_read(dev, port->plat->phy, MII_BMCR) & ~(BMCR_RESET | BMCR_PDOWN); /* may have been altered */ mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN); phy_stop(port->phydev); if (!ports_open) qmgr_disable_irq(TXDONE_QUEUE); cancel_rearming_delayed_work(&port->mdio_thread); destroy_queues(port); release_queues(port); return 0; } static const struct net_device_ops ixp4xx_netdev_ops = { .ndo_open = eth_open, .ndo_stop = eth_close, .ndo_start_xmit = eth_xmit, .ndo_set_multicast_list = eth_set_mcast_list, .ndo_do_ioctl = eth_ioctl, }; static int __devinit eth_init_one(struct platform_device *pdev) { struct port *port; 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)))) Loading Loading @@ -1152,12 +1169,8 @@ static int __devinit eth_init_one(struct platform_device *pdev) goto err_free; } dev->open = eth_open; dev->hard_start_xmit = eth_xmit; dev->stop = eth_close; dev->get_stats = eth_stats; dev->do_ioctl = eth_ioctl; dev->set_multicast_list = eth_set_mcast_list; dev->netdev_ops = &ixp4xx_netdev_ops; dev->ethtool_ops = &ixp4xx_ethtool_ops; dev->tx_queue_len = 100; netif_napi_add(dev, &port->napi, eth_poll, NAPI_WEIGHT); Loading Loading @@ -1190,22 +1203,19 @@ static int __devinit eth_init_one(struct platform_device *pdev) __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control); udelay(50); port->mii.dev = dev; port->mii.mdio_read = mdio_read; port->mii.mdio_write = mdio_write; port->mii.phy_id = plat->phy; port->mii.phy_id_mask = 0x1F; port->mii.reg_num_mask = 0x1F; 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); } port->phydev->irq = PHY_POLL; printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy, npe_name(port->npe)); phy_reset(dev, plat->phy); port->mii_bmcr = mdio_read(dev, plat->phy, MII_BMCR) & ~(BMCR_RESET | BMCR_PDOWN); mdio_write(dev, plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN); INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread); return 0; err_unreg: Loading @@ -1231,7 +1241,7 @@ static int __devexit eth_remove_one(struct platform_device *pdev) return 0; } static struct platform_driver drv = { static struct platform_driver ixp4xx_eth_driver = { .driver.name = DRV_NAME, .probe = eth_init_one, .remove = eth_remove_one, Loading @@ -1239,20 +1249,19 @@ static struct platform_driver drv = { static int __init eth_init_module(void) { int err; if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0)) return -ENOSYS; /* All MII PHY accesses use NPE-B Ethernet registers */ spin_lock_init(&mdio_lock); mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control); return platform_driver_register(&drv); if ((err = ixp4xx_mdio_register())) return err; return platform_driver_register(&ixp4xx_eth_driver); } static void __exit eth_cleanup_module(void) { platform_driver_unregister(&drv); platform_driver_unregister(&ixp4xx_eth_driver); ixp4xx_mdio_remove(); } MODULE_AUTHOR("Krzysztof Halasa"); Loading