X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fnet%2Fmacb.c;h=f50501013b1c6cf49a92310da219998a5e5ad9a6;hb=df04baf1e6a62ff232fa224504ccaa987b5be230;hp=83c35fd91e0ff14af9386cad05be0b277e139062;hpb=6c36a7074436e181fb3df41f66bbdaf53980951e;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 83c35fd..f505010 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -21,8 +21,8 @@ #include #include -#include -#include +#include +#include #include "macb.h" @@ -80,8 +80,12 @@ static void __init macb_get_hwaddr(struct macb *bp) addr[4] = top & 0xff; addr[5] = (top >> 8) & 0xff; - if (is_valid_ether_addr(addr)) + if (is_valid_ether_addr(addr)) { memcpy(bp->dev->dev_addr, addr, sizeof(addr)); + } else { + dev_info(&bp->pdev->dev, "invalid hw address, using random\n"); + random_ether_addr(bp->dev->dev_addr); + } } static int macb_mdio_read(struct mii_bus *bus, int mii_id, int regnum) @@ -148,7 +152,7 @@ static void macb_handle_link_change(struct net_device *dev) if (phydev->duplex) reg |= MACB_BIT(FD); - if (phydev->speed) + if (phydev->speed == SPEED_100) reg |= MACB_BIT(SPD); macb_writel(bp, NCFGR, reg); @@ -160,9 +164,7 @@ static void macb_handle_link_change(struct net_device *dev) } if (phydev->link != bp->link) { - if (phydev->link) - netif_schedule(dev); - else { + if (!phydev->link) { bp->speed = 0; bp->duplex = -1; } @@ -193,8 +195,8 @@ static int macb_mii_probe(struct net_device *dev) /* find the first phy */ for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { - if (bp->mii_bus.phy_map[phy_addr]) { - phydev = bp->mii_bus.phy_map[phy_addr]; + if (bp->mii_bus->phy_map[phy_addr]) { + phydev = bp->mii_bus->phy_map[phy_addr]; break; } } @@ -209,10 +211,10 @@ static int macb_mii_probe(struct net_device *dev) /* attach the mac to the phy */ if (pdata && pdata->is_rmii) { - phydev = phy_connect(dev, phydev->dev.bus_id, + phydev = phy_connect(dev, dev_name(&phydev->dev), &macb_handle_link_change, 0, PHY_INTERFACE_MODE_RMII); } else { - phydev = phy_connect(dev, phydev->dev.bus_id, + phydev = phy_connect(dev, dev_name(&phydev->dev), &macb_handle_link_change, 0, PHY_INTERFACE_MODE_MII); } @@ -242,30 +244,36 @@ static int macb_mii_init(struct macb *bp) /* Enable managment port */ macb_writel(bp, NCR, MACB_BIT(MPE)); - bp->mii_bus.name = "MACB_mii_bus", - bp->mii_bus.read = &macb_mdio_read, - bp->mii_bus.write = &macb_mdio_write, - bp->mii_bus.reset = &macb_mdio_reset, - bp->mii_bus.id = bp->pdev->id, - bp->mii_bus.priv = bp, - bp->mii_bus.dev = &bp->dev->dev; + bp->mii_bus = mdiobus_alloc(); + if (bp->mii_bus == NULL) { + err = -ENOMEM; + goto err_out; + } + + bp->mii_bus->name = "MACB_mii_bus"; + bp->mii_bus->read = &macb_mdio_read; + bp->mii_bus->write = &macb_mdio_write; + bp->mii_bus->reset = &macb_mdio_reset; + snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", bp->pdev->id); + bp->mii_bus->priv = bp; + bp->mii_bus->parent = &bp->dev->dev; pdata = bp->pdev->dev.platform_data; if (pdata) - bp->mii_bus.phy_mask = pdata->phy_mask; + bp->mii_bus->phy_mask = pdata->phy_mask; - bp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); - if (!bp->mii_bus.irq) { + bp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + if (!bp->mii_bus->irq) { err = -ENOMEM; - goto err_out; + goto err_out_free_mdiobus; } for (i = 0; i < PHY_MAX_ADDR; i++) - bp->mii_bus.irq[i] = PHY_POLL; + bp->mii_bus->irq[i] = PHY_POLL; - platform_set_drvdata(bp->dev, &bp->mii_bus); + platform_set_drvdata(bp->dev, bp->mii_bus); - if (mdiobus_register(&bp->mii_bus)) + if (mdiobus_register(bp->mii_bus)) goto err_out_free_mdio_irq; if (macb_mii_probe(bp->dev) != 0) { @@ -275,9 +283,11 @@ static int macb_mii_init(struct macb *bp) return 0; err_out_unregister_bus: - mdiobus_unregister(&bp->mii_bus); + mdiobus_unregister(bp->mii_bus); err_out_free_mdio_irq: - kfree(bp->mii_bus.irq); + kfree(bp->mii_bus->irq); +err_out_free_mdiobus: + mdiobus_free(bp->mii_bus); err_out: return err; } @@ -307,9 +317,40 @@ static void macb_tx(struct macb *bp) (unsigned long)status); if (status & MACB_BIT(UND)) { + int i; printk(KERN_ERR "%s: TX underrun, resetting buffers\n", - bp->dev->name); + bp->dev->name); + + /* Transfer ongoing, disable transmitter, to avoid confusion */ + if (status & MACB_BIT(TGO)) + macb_writel(bp, NCR, macb_readl(bp, NCR) & ~MACB_BIT(TE)); + + head = bp->tx_head; + + /*Mark all the buffer as used to avoid sending a lost buffer*/ + for (i = 0; i < TX_RING_SIZE; i++) + bp->tx_ring[i].ctrl = MACB_BIT(TX_USED); + + /* free transmit buffer in upper layer*/ + for (tail = bp->tx_tail; tail != head; tail = NEXT_TX(tail)) { + struct ring_info *rp = &bp->tx_skb[tail]; + struct sk_buff *skb = rp->skb; + + BUG_ON(skb == NULL); + + rmb(); + + dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len, + DMA_TO_DEVICE); + rp->skb = NULL; + dev_kfree_skb_irq(skb); + } + bp->tx_head = bp->tx_tail = 0; + + /* Enable the transmitter again */ + if (status & MACB_BIT(TGO)) + macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TE)); } if (!(status & MACB_BIT(COMP))) @@ -402,7 +443,6 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, bp->stats.rx_packets++; bp->stats.rx_bytes += len; - bp->dev->last_rx = jiffies; dev_dbg(&bp->pdev->dev, "received skb of length %u, csum: %08x\n", skb->len, skb->csum); netif_receive_skb(skb); @@ -470,47 +510,40 @@ static int macb_rx(struct macb *bp, int budget) return received; } -static int macb_poll(struct net_device *dev, int *budget) +static int macb_poll(struct napi_struct *napi, int budget) { - struct macb *bp = netdev_priv(dev); - int orig_budget, work_done, retval = 0; + struct macb *bp = container_of(napi, struct macb, napi); + int work_done; u32 status; status = macb_readl(bp, RSR); macb_writel(bp, RSR, status); + work_done = 0; if (!status) { /* * This may happen if an interrupt was pending before * this function was called last time, and no packets * have been received since. */ - netif_rx_complete(dev); + napi_complete(napi); goto out; } dev_dbg(&bp->pdev->dev, "poll: status = %08lx, budget = %d\n", - (unsigned long)status, *budget); + (unsigned long)status, budget); if (!(status & MACB_BIT(REC))) { dev_warn(&bp->pdev->dev, "No RX buffers complete, status = %02lx\n", (unsigned long)status); - netif_rx_complete(dev); + napi_complete(napi); goto out; } - orig_budget = *budget; - if (orig_budget > dev->quota) - orig_budget = dev->quota; - - work_done = macb_rx(bp, orig_budget); - if (work_done < orig_budget) { - netif_rx_complete(dev); - retval = 0; - } else { - retval = 1; - } + work_done = macb_rx(bp, budget); + if (work_done < budget) + napi_complete(napi); /* * We've done what we can to clean the buffers. Make sure we @@ -521,7 +554,7 @@ out: /* TODO: Handle errors */ - return retval; + return work_done; } static irqreturn_t macb_interrupt(int irq, void *dev_id) @@ -545,7 +578,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) } if (status & MACB_RX_INT_FLAGS) { - if (netif_rx_schedule_prep(dev)) { + if (napi_schedule_prep(&bp->napi)) { /* * There's no point taking any more interrupts * until we have processed the buffers @@ -553,7 +586,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) macb_writel(bp, IDR, MACB_RX_INT_FLAGS); dev_dbg(&bp->pdev->dev, "scheduling RX softirq\n"); - __netif_rx_schedule(dev); + __napi_schedule(&bp->napi); } } @@ -796,6 +829,125 @@ static void macb_init_hw(struct macb *bp) } +/* + * The hash address register is 64 bits long and takes up two + * locations in the memory map. The least significant bits are stored + * in EMAC_HSL and the most significant bits in EMAC_HSH. + * + * The unicast hash enable and the multicast hash enable bits in the + * network configuration register enable the reception of hash matched + * frames. The destination address is reduced to a 6 bit index into + * the 64 bit hash register using the following hash function. The + * hash function is an exclusive or of every sixth bit of the + * destination address. + * + * hi[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] + * hi[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] + * hi[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] + * hi[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] + * hi[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] + * hi[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] + * + * da[0] represents the least significant bit of the first byte + * received, that is, the multicast/unicast indicator, and da[47] + * represents the most significant bit of the last byte received. If + * the hash index, hi[n], points to a bit that is set in the hash + * register then the frame will be matched according to whether the + * frame is multicast or unicast. A multicast match will be signalled + * if the multicast hash enable bit is set, da[0] is 1 and the hash + * index points to a bit set in the hash register. A unicast match + * will be signalled if the unicast hash enable bit is set, da[0] is 0 + * and the hash index points to a bit set in the hash register. To + * receive all multicast frames, the hash register should be set with + * all ones and the multicast hash enable bit should be set in the + * network configuration register. + */ + +static inline int hash_bit_value(int bitnr, __u8 *addr) +{ + if (addr[bitnr / 8] & (1 << (bitnr % 8))) + return 1; + return 0; +} + +/* + * Return the hash index value for the specified address. + */ +static int hash_get_index(__u8 *addr) +{ + int i, j, bitval; + int hash_index = 0; + + for (j = 0; j < 6; j++) { + for (i = 0, bitval = 0; i < 8; i++) + bitval ^= hash_bit_value(i*6 + j, addr); + + hash_index |= (bitval << j); + } + + return hash_index; +} + +/* + * Add multicast addresses to the internal multicast-hash table. + */ +static void macb_sethashtable(struct net_device *dev) +{ + struct dev_mc_list *curr; + unsigned long mc_filter[2]; + unsigned int i, bitnr; + struct macb *bp = netdev_priv(dev); + + mc_filter[0] = mc_filter[1] = 0; + + curr = dev->mc_list; + for (i = 0; i < dev->mc_count; i++, curr = curr->next) { + if (!curr) break; /* unexpected end of list */ + + bitnr = hash_get_index(curr->dmi_addr); + mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); + } + + macb_writel(bp, HRB, mc_filter[0]); + macb_writel(bp, HRT, mc_filter[1]); +} + +/* + * Enable/Disable promiscuous and multicast modes. + */ +static void macb_set_rx_mode(struct net_device *dev) +{ + unsigned long cfg; + struct macb *bp = netdev_priv(dev); + + cfg = macb_readl(bp, NCFGR); + + if (dev->flags & IFF_PROMISC) + /* Enable promiscuous mode */ + cfg |= MACB_BIT(CAF); + else if (dev->flags & (~IFF_PROMISC)) + /* Disable promiscuous mode */ + cfg &= ~MACB_BIT(CAF); + + if (dev->flags & IFF_ALLMULTI) { + /* Enable all multicast mode */ + macb_writel(bp, HRB, -1); + macb_writel(bp, HRT, -1); + cfg |= MACB_BIT(NCFGR_MTI); + } else if (dev->mc_count > 0) { + /* Enable specific multicasts */ + macb_sethashtable(dev); + cfg |= MACB_BIT(NCFGR_MTI); + } else if (dev->flags & (~IFF_ALLMULTI)) { + /* Disable all multicast mode */ + macb_writel(bp, HRB, 0); + macb_writel(bp, HRT, 0); + cfg &= ~MACB_BIT(NCFGR_MTI); + } + + macb_writel(bp, NCFGR, cfg); +} + static int macb_open(struct net_device *dev) { struct macb *bp = netdev_priv(dev); @@ -818,6 +970,8 @@ static int macb_open(struct net_device *dev) return err; } + napi_enable(&bp->napi); + macb_init_rings(bp); macb_init_hw(bp); @@ -835,6 +989,7 @@ static int macb_close(struct net_device *dev) unsigned long flags; netif_stop_queue(dev); + napi_disable(&bp->napi); if (bp->phy_dev) phy_stop(bp->phy_dev); @@ -921,7 +1076,7 @@ static void macb_get_drvinfo(struct net_device *dev, strcpy(info->driver, bp->pdev->dev.driver->name); strcpy(info->version, "$Revision: 1.14 $"); - strcpy(info->bus_info, bp->pdev->dev.bus_id); + strcpy(info->bus_info, dev_name(&bp->pdev->dev)); } static struct ethtool_ops macb_ethtool_ops = { @@ -945,7 +1100,7 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return phy_mii_ioctl(phydev, if_mii(rq), cmd); } -static int __devinit macb_probe(struct platform_device *pdev) +static int __init macb_probe(struct platform_device *pdev) { struct eth_platform_data *pdata; struct resource *regs; @@ -969,7 +1124,6 @@ static int __devinit macb_probe(struct platform_device *pdev) goto err_out; } - SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); /* TODO: Actually, we have some interesting features... */ @@ -1025,9 +1179,9 @@ static int __devinit macb_probe(struct platform_device *pdev) dev->stop = macb_close; dev->hard_start_xmit = macb_start_xmit; dev->get_stats = macb_get_stats; + dev->set_multicast_list = macb_set_rx_mode; dev->do_ioctl = macb_ioctl; - dev->poll = macb_poll; - dev->weight = 64; + netif_napi_add(dev, &bp->napi, macb_poll, 64); dev->ethtool_ops = &macb_ethtool_ops; dev->base_addr = regs->start; @@ -1074,16 +1228,13 @@ static int __devinit macb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d " - "(%02x:%02x:%02x:%02x:%02x:%02x)\n", - dev->name, dev->base_addr, dev->irq, - dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], - dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d (%pM)\n", + dev->name, dev->base_addr, dev->irq, dev->dev_addr); phydev = bp->phy_dev; printk(KERN_INFO "%s: attached PHY driver [%s] " - "(mii_bus:phy_addr=%s, irq=%d)\n", - dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq); + "(mii_bus:phy_addr=%s, irq=%d)\n", dev->name, + phydev->drv->name, dev_name(&phydev->dev), phydev->irq); return 0; @@ -1110,7 +1261,7 @@ err_out: return err; } -static int __devexit macb_remove(struct platform_device *pdev) +static int __exit macb_remove(struct platform_device *pdev) { struct net_device *dev; struct macb *bp; @@ -1119,8 +1270,11 @@ static int __devexit macb_remove(struct platform_device *pdev) if (dev) { bp = netdev_priv(dev); - mdiobus_unregister(&bp->mii_bus); - kfree(bp->mii_bus.irq); + if (bp->phy_dev) + phy_disconnect(bp->phy_dev); + mdiobus_unregister(bp->mii_bus); + kfree(bp->mii_bus->irq); + mdiobus_free(bp->mii_bus); unregister_netdev(dev); free_irq(dev->irq, dev); iounmap(bp->regs); @@ -1137,17 +1291,54 @@ static int __devexit macb_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int macb_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *netdev = platform_get_drvdata(pdev); + struct macb *bp = netdev_priv(netdev); + + netif_device_detach(netdev); + +#ifndef CONFIG_ARCH_AT91 + clk_disable(bp->hclk); +#endif + clk_disable(bp->pclk); + + return 0; +} + +static int macb_resume(struct platform_device *pdev) +{ + struct net_device *netdev = platform_get_drvdata(pdev); + struct macb *bp = netdev_priv(netdev); + + clk_enable(bp->pclk); +#ifndef CONFIG_ARCH_AT91 + clk_enable(bp->hclk); +#endif + + netif_device_attach(netdev); + + return 0; +} +#else +#define macb_suspend NULL +#define macb_resume NULL +#endif + static struct platform_driver macb_driver = { - .probe = macb_probe, - .remove = __devexit_p(macb_remove), + .remove = __exit_p(macb_remove), + .suspend = macb_suspend, + .resume = macb_resume, .driver = { .name = "macb", + .owner = THIS_MODULE, }, }; static int __init macb_init(void) { - return platform_driver_register(&macb_driver); + return platform_driver_probe(&macb_driver, macb_probe); } static void __exit macb_exit(void) @@ -1161,3 +1352,4 @@ module_exit(macb_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Atmel MACB Ethernet driver"); MODULE_AUTHOR("Haavard Skinnemoen "); +MODULE_ALIAS("platform:macb");