ixgbe: always enable vlan strip/insert when DCB is enabled
[safe/jmp/linux-2.6] / drivers / net / ethoc.c
index 91a9b1a..14cbde5 100644 (file)
 #include <linux/mii.h>
 #include <linux/phy.h>
 #include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
 #include <net/ethoc.h>
 
+static int buffer_size = 0x8000; /* 32 KBytes */
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
+
 /* register offsets */
 #define        MODER           0x00
 #define        INT_SOURCE      0x04
  * struct ethoc - driver-private device structure
  * @iobase:    pointer to I/O memory region
  * @membase:   pointer to buffer memory region
+ * @dma_alloc: dma allocated buffer size
  * @num_tx:    number of send buffers
  * @cur_tx:    last send buffer written
  * @dty_tx:    last buffer actually sent
 struct ethoc {
        void __iomem *iobase;
        void __iomem *membase;
+       int dma_alloc;
 
        unsigned int num_tx;
        unsigned int cur_tx;
@@ -216,24 +224,25 @@ struct ethoc_bd {
        u32 addr;
 };
 
-static u32 ethoc_read(struct ethoc *dev, loff_t offset)
+static inline u32 ethoc_read(struct ethoc *dev, loff_t offset)
 {
        return ioread32(dev->iobase + offset);
 }
 
-static void ethoc_write(struct ethoc *dev, loff_t offset, u32 data)
+static inline void ethoc_write(struct ethoc *dev, loff_t offset, u32 data)
 {
        iowrite32(data, dev->iobase + offset);
 }
 
-static void ethoc_read_bd(struct ethoc *dev, int index, struct ethoc_bd *bd)
+static inline void ethoc_read_bd(struct ethoc *dev, int index,
+               struct ethoc_bd *bd)
 {
        loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
        bd->stat = ethoc_read(dev, offset + 0);
        bd->addr = ethoc_read(dev, offset + 4);
 }
 
-static void ethoc_write_bd(struct ethoc *dev, int index,
+static inline void ethoc_write_bd(struct ethoc *dev, int index,
                const struct ethoc_bd *bd)
 {
        loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
@@ -241,33 +250,33 @@ static void ethoc_write_bd(struct ethoc *dev, int index,
        ethoc_write(dev, offset + 4, bd->addr);
 }
 
-static void ethoc_enable_irq(struct ethoc *dev, u32 mask)
+static inline void ethoc_enable_irq(struct ethoc *dev, u32 mask)
 {
        u32 imask = ethoc_read(dev, INT_MASK);
        imask |= mask;
        ethoc_write(dev, INT_MASK, imask);
 }
 
-static void ethoc_disable_irq(struct ethoc *dev, u32 mask)
+static inline void ethoc_disable_irq(struct ethoc *dev, u32 mask)
 {
        u32 imask = ethoc_read(dev, INT_MASK);
        imask &= ~mask;
        ethoc_write(dev, INT_MASK, imask);
 }
 
-static void ethoc_ack_irq(struct ethoc *dev, u32 mask)
+static inline void ethoc_ack_irq(struct ethoc *dev, u32 mask)
 {
        ethoc_write(dev, INT_SOURCE, mask);
 }
 
-static void ethoc_enable_rx_and_tx(struct ethoc *dev)
+static inline void ethoc_enable_rx_and_tx(struct ethoc *dev)
 {
        u32 mode = ethoc_read(dev, MODER);
        mode |= MODER_RXEN | MODER_TXEN;
        ethoc_write(dev, MODER, mode);
 }
 
-static void ethoc_disable_rx_and_tx(struct ethoc *dev)
+static inline void ethoc_disable_rx_and_tx(struct ethoc *dev)
 {
        u32 mode = ethoc_read(dev, MODER);
        mode &= ~(MODER_RXEN | MODER_TXEN);
@@ -284,7 +293,7 @@ static int ethoc_init_ring(struct ethoc *dev)
        dev->cur_rx = 0;
 
        /* setup transmission buffers */
-       bd.addr = 0;
+       bd.addr = virt_to_phys(dev->membase);
        bd.stat = TX_BD_IRQ | TX_BD_CRC;
 
        for (i = 0; i < dev->num_tx; i++) {
@@ -295,7 +304,6 @@ static int ethoc_init_ring(struct ethoc *dev)
                bd.addr += ETHOC_BUFSIZ;
        }
 
-       bd.addr = dev->num_tx * ETHOC_BUFSIZ;
        bd.stat = RX_BD_EMPTY | RX_BD_IRQ;
 
        for (i = 0; i < dev->num_rx; i++) {
@@ -399,12 +407,15 @@ static int ethoc_rx(struct net_device *dev, int limit)
 
                if (ethoc_update_rx_stats(priv, &bd) == 0) {
                        int size = bd.stat >> 16;
-                       struct sk_buff *skb = netdev_alloc_skb(dev, size);
+                       struct sk_buff *skb;
+
+                       size -= 4; /* strip the CRC */
+                       skb = netdev_alloc_skb_ip_align(dev, size);
+
                        if (likely(skb)) {
-                               void *src = priv->membase + bd.addr;
+                               void *src = phys_to_virt(bd.addr);
                                memcpy_fromio(skb_put(skb, size), src, size);
                                skb->protocol = eth_type_trans(skb, dev);
-                               dev->last_rx = jiffies;
                                priv->stats.rx_packets++;
                                priv->stats.rx_bytes += size;
                                netif_receive_skb(skb);
@@ -499,7 +510,7 @@ static irqreturn_t ethoc_interrupt(int irq, void *dev_id)
                return IRQ_NONE;
        }
 
-       ethoc_ack_irq(priv, INT_MASK_ALL);
+       ethoc_ack_irq(priv, pending);
 
        if (pending & INT_MASK_BUSY) {
                dev_err(&dev->dev, "packet dropped\n");
@@ -631,7 +642,7 @@ static int ethoc_mdio_probe(struct net_device *dev)
                return -ENXIO;
        }
 
-       phy = phy_connect(dev, dev_name(&phy->dev), &ethoc_mdio_poll, 0,
+       phy = phy_connect(dev, dev_name(&phy->dev), ethoc_mdio_poll, 0,
                        PHY_INTERFACE_MODE_GMII);
        if (IS_ERR(phy)) {
                dev_err(&dev->dev, "could not attach to PHY\n");
@@ -654,9 +665,10 @@ static int ethoc_open(struct net_device *dev)
        if (ret)
                return ret;
 
-       /* calculate the number of TX/RX buffers */
-       num_bd = (dev->mem_end - dev->mem_start + 1) / ETHOC_BUFSIZ;
-       priv->num_tx = min(min_tx, num_bd / 4);
+       /* calculate the number of TX/RX buffers, maximum 128 supported */
+       num_bd = min_t(unsigned int,
+               128, (dev->mem_end - dev->mem_start + 1) / ETHOC_BUFSIZ);
+       priv->num_tx = max(min_tx, num_bd / 4);
        priv->num_rx = num_bd - priv->num_tx;
        ethoc_write(priv, TX_BD_NUM, priv->num_tx);
 
@@ -744,7 +756,7 @@ static void ethoc_set_multicast_list(struct net_device *dev)
 {
        struct ethoc *priv = netdev_priv(dev);
        u32 mode = ethoc_read(priv, MODER);
-       struct dev_mc_list *mc = NULL;
+       struct netdev_hw_addr *ha;
        u32 hash[2] = { 0, 0 };
 
        /* set loopback mode if requested */
@@ -772,8 +784,8 @@ static void ethoc_set_multicast_list(struct net_device *dev)
                hash[0] = 0xffffffff;
                hash[1] = 0xffffffff;
        } else {
-               for (mc = dev->mc_list; mc; mc = mc->next) {
-                       u32 crc = ether_crc(mc->dmi_addrlen, mc->dmi_addr);
+               netdev_for_each_mc_addr(ha, dev) {
+                       u32 crc = ether_crc(ETH_ALEN, ha->addr);
                        int bit = (crc >> 26) & 0x3f;
                        hash[bit >> 5] |= 1 << (bit & 0x1f);
                }
@@ -802,7 +814,7 @@ static struct net_device_stats *ethoc_stats(struct net_device *dev)
        return &priv->stats;
 }
 
-static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct ethoc *priv = netdev_priv(dev);
        struct ethoc_bd bd;
@@ -811,7 +823,7 @@ static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (unlikely(skb->len > ETHOC_BUFSIZ)) {
                priv->stats.tx_errors++;
-               return -EMSGSIZE;
+               goto out;
        }
 
        entry = priv->cur_tx % priv->num_tx;
@@ -824,7 +836,7 @@ static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
        else
                bd.stat &= ~TX_BD_PAD;
 
-       dest = priv->membase + bd.addr;
+       dest = phys_to_virt(bd.addr);
        memcpy_toio(dest, skb->data, skb->len);
 
        bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK);
@@ -839,10 +851,9 @@ static int ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
                netif_stop_queue(dev);
        }
 
-       dev->trans_start = jiffies;
-       dev_kfree_skb(skb);
-
        spin_unlock_irq(&priv->lock);
+out:
+       dev_kfree_skb(skb);
        return NETDEV_TX_OK;
 }
 
@@ -893,8 +904,8 @@ static int ethoc_probe(struct platform_device *pdev)
        }
 
        mmio = devm_request_mem_region(&pdev->dev, res->start,
-                       res->end - res->start + 1, res->name);
-       if (!res) {
+                       resource_size(res), res->name);
+       if (!mmio) {
                dev_err(&pdev->dev, "cannot request I/O memory space\n");
                ret = -ENXIO;
                goto free;
@@ -904,22 +915,19 @@ static int ethoc_probe(struct platform_device *pdev)
 
        /* obtain buffer memory space */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (!res) {
-               dev_err(&pdev->dev, "cannot obtain memory space\n");
-               ret = -ENXIO;
-               goto free;
-       }
+       if (res) {
+               mem = devm_request_mem_region(&pdev->dev, res->start,
+                       resource_size(res), res->name);
+               if (!mem) {
+                       dev_err(&pdev->dev, "cannot request memory space\n");
+                       ret = -ENXIO;
+                       goto free;
+               }
 
-       mem = devm_request_mem_region(&pdev->dev, res->start,
-                       res->end - res->start + 1, res->name);
-       if (!mem) {
-               dev_err(&pdev->dev, "cannot request memory space\n");
-               ret = -ENXIO;
-               goto free;
+               netdev->mem_start = mem->start;
+               netdev->mem_end   = mem->end;
        }
 
-       netdev->mem_start = mem->start;
-       netdev->mem_end   = mem->end;
 
        /* obtain device IRQ number */
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -934,21 +942,37 @@ static int ethoc_probe(struct platform_device *pdev)
        /* setup driver-private data */
        priv = netdev_priv(netdev);
        priv->netdev = netdev;
+       priv->dma_alloc = 0;
 
        priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr,
-                       mmio->end - mmio->start + 1);
+                       resource_size(mmio));
        if (!priv->iobase) {
                dev_err(&pdev->dev, "cannot remap I/O memory space\n");
                ret = -ENXIO;
                goto error;
        }
 
-       priv->membase = devm_ioremap_nocache(&pdev->dev, netdev->mem_start,
-                       mem->end - mem->start + 1);
-       if (!priv->membase) {
-               dev_err(&pdev->dev, "cannot remap memory space\n");
-               ret = -ENXIO;
-               goto error;
+       if (netdev->mem_end) {
+               priv->membase = devm_ioremap_nocache(&pdev->dev,
+                       netdev->mem_start, resource_size(mem));
+               if (!priv->membase) {
+                       dev_err(&pdev->dev, "cannot remap memory space\n");
+                       ret = -ENXIO;
+                       goto error;
+               }
+       } else {
+               /* Allocate buffer memory */
+               priv->membase = dma_alloc_coherent(NULL,
+                       buffer_size, (void *)&netdev->mem_start,
+                       GFP_KERNEL);
+               if (!priv->membase) {
+                       dev_err(&pdev->dev, "cannot allocate %dB buffer\n",
+                               buffer_size);
+                       ret = -ENOMEM;
+                       goto error;
+               }
+               netdev->mem_end = netdev->mem_start + buffer_size;
+               priv->dma_alloc = buffer_size;
        }
 
        /* Allow the platform setup code to pass in a MAC address. */
@@ -1015,7 +1039,6 @@ static int ethoc_probe(struct platform_device *pdev)
        netdev->features |= 0;
 
        /* setup NAPI */
-       memset(&priv->napi, 0, sizeof(priv->napi));
        netif_napi_add(netdev, &priv->napi, ethoc_poll, 64);
 
        spin_lock_init(&priv->rx_lock);
@@ -1035,6 +1058,9 @@ free_mdio:
        kfree(priv->mdio->irq);
        mdiobus_free(priv->mdio);
 free:
+       if (priv->dma_alloc)
+               dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
+                       netdev->mem_start);
        free_netdev(netdev);
 out:
        return ret;
@@ -1060,7 +1086,9 @@ static int ethoc_remove(struct platform_device *pdev)
                        kfree(priv->mdio->irq);
                        mdiobus_free(priv->mdio);
                }
-
+               if (priv->dma_alloc)
+                       dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
+                               netdev->mem_start);
                unregister_netdev(netdev);
                free_netdev(netdev);
        }