if (phydev->duplex)
reg |= MACB_BIT(FD);
- if (phydev->speed)
+ if (phydev->speed == SPEED_100)
reg |= MACB_BIT(SPD);
macb_writel(bp, NCFGR, reg);
/* 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.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.dev = &bp->dev->dev;
pdata = bp->pdev->dev.platform_data;
(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);
+
+ 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;
}
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);
+ struct net_device *dev = bp->dev;
+ 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);
+ netif_rx_complete(dev, 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);
+ netif_rx_complete(dev, 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)
+ netif_rx_complete(dev, napi);
/*
* We've done what we can to clean the buffers. Make sure we
/* TODO: Handle errors */
- return retval;
+ return work_done;
}
static irqreturn_t macb_interrupt(int irq, void *dev_id)
}
if (status & MACB_RX_INT_FLAGS) {
- if (netif_rx_schedule_prep(dev)) {
+ if (netif_rx_schedule_prep(dev, &bp->napi)) {
/*
* There's no point taking any more interrupts
* until we have processed the buffers
macb_writel(bp, IDR, MACB_RX_INT_FLAGS);
dev_dbg(&bp->pdev->dev,
"scheduling RX softirq\n");
- __netif_rx_schedule(dev);
+ __netif_rx_schedule(dev, &bp->napi);
}
}
}
+/*
+ * 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);
return err;
}
+ napi_enable(&bp->napi);
+
macb_init_rings(bp);
macb_init_hw(bp);
unsigned long flags;
netif_stop_queue(dev);
+ napi_disable(&bp->napi);
if (bp->phy_dev)
phy_stop(bp->phy_dev);
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;
unsigned long pclk_hz;
u32 config;
int err = -ENXIO;
+ DECLARE_MAC_BUF(mac);
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
goto err_out;
}
- SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
/* TODO: Actually, we have some interesting features... */
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;
platform_set_drvdata(pdev, dev);
printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d "
- "(%02x:%02x:%02x:%02x:%02x:%02x)\n",
+ "(%s)\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]);
+ print_mac(mac, dev->dev_addr));
phydev = bp->phy_dev;
printk(KERN_INFO "%s: attached PHY driver [%s] "
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;
if (dev) {
bp = netdev_priv(dev);
+ if (bp->phy_dev)
+ phy_disconnect(bp->phy_dev);
mdiobus_unregister(&bp->mii_bus);
kfree(bp->mii_bus.irq);
unregister_netdev(dev);
}
static struct platform_driver macb_driver = {
- .probe = macb_probe,
- .remove = __devexit_p(macb_remove),
+ .remove = __exit_p(macb_remove),
.driver = {
.name = "macb",
},
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)