]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/net/enic/enic_main.c
net: convert multiple drivers to use netdev_for_each_mc_addr, part4
[mv-sheeva.git] / drivers / net / enic / enic_main.c
index f875751af15e59547988f49358aea3160197f678..cf098bb636b802a48e0187218744e6461173d4ec 100644 (file)
@@ -51,7 +51,7 @@
 #define PCI_DEVICE_ID_CISCO_VIC_ENET         0x0043  /* ethernet vnic */
 
 /* Supported devices */
-static struct pci_device_id enic_id_table[] = {
+static DEFINE_PCI_DEVICE_TABLE(enic_id_table) = {
        { PCI_VDEVICE(CISCO, PCI_DEVICE_ID_CISCO_VIC_ENET) },
        { 0, }  /* end of table */
 };
@@ -261,6 +261,62 @@ static void enic_set_msglevel(struct net_device *netdev, u32 value)
        enic->msg_enable = value;
 }
 
+static int enic_get_coalesce(struct net_device *netdev,
+       struct ethtool_coalesce *ecmd)
+{
+       struct enic *enic = netdev_priv(netdev);
+
+       ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
+       ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
+
+       return 0;
+}
+
+static int enic_set_coalesce(struct net_device *netdev,
+       struct ethtool_coalesce *ecmd)
+{
+       struct enic *enic = netdev_priv(netdev);
+       u32 tx_coalesce_usecs;
+       u32 rx_coalesce_usecs;
+
+       tx_coalesce_usecs = min_t(u32,
+               INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
+               ecmd->tx_coalesce_usecs);
+       rx_coalesce_usecs = min_t(u32,
+               INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
+               ecmd->rx_coalesce_usecs);
+
+       switch (vnic_dev_get_intr_mode(enic->vdev)) {
+       case VNIC_DEV_INTR_MODE_INTX:
+               if (tx_coalesce_usecs != rx_coalesce_usecs)
+                       return -EINVAL;
+
+               vnic_intr_coalescing_timer_set(&enic->intr[ENIC_INTX_WQ_RQ],
+                       INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+               break;
+       case VNIC_DEV_INTR_MODE_MSI:
+               if (tx_coalesce_usecs != rx_coalesce_usecs)
+                       return -EINVAL;
+
+               vnic_intr_coalescing_timer_set(&enic->intr[0],
+                       INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+               break;
+       case VNIC_DEV_INTR_MODE_MSIX:
+               vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_WQ],
+                       INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
+               vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_RQ],
+                       INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs));
+               break;
+       default:
+               break;
+       }
+
+       enic->tx_coalesce_usecs = tx_coalesce_usecs;
+       enic->rx_coalesce_usecs = rx_coalesce_usecs;
+
+       return 0;
+}
+
 static const struct ethtool_ops enic_ethtool_ops = {
        .get_settings = enic_get_settings,
        .get_drvinfo = enic_get_drvinfo,
@@ -278,6 +334,8 @@ static const struct ethtool_ops enic_ethtool_ops = {
        .set_sg = ethtool_op_set_sg,
        .get_tso = ethtool_op_get_tso,
        .set_tso = enic_set_tso,
+       .get_coalesce = enic_get_coalesce,
+       .set_coalesce = enic_set_coalesce,
        .get_flags = ethtool_op_get_flags,
        .set_flags = ethtool_op_set_flags,
 };
@@ -363,12 +421,12 @@ static void enic_mtu_check(struct enic *enic)
        u32 mtu = vnic_dev_mtu(enic->vdev);
 
        if (mtu && mtu != enic->port_mtu) {
+               enic->port_mtu = mtu;
                if (mtu < enic->netdev->mtu)
                        printk(KERN_WARNING PFX
                                "%s: interface MTU (%d) set higher "
                                "than switch port MTU (%d)\n",
                                enic->netdev->name, enic->netdev->mtu, mtu);
-               enic->port_mtu = mtu;
        }
 }
 
@@ -673,7 +731,7 @@ static inline void enic_queue_wq_skb(struct enic *enic,
 
 /* netif_tx_lock held, process context with BHs disabled, or BH */
 static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
-                                             struct net_device *netdev)
+       struct net_device *netdev)
 {
        struct enic *enic = netdev_priv(netdev);
        struct vnic_wq *wq = &enic->wq[0];
@@ -764,15 +822,16 @@ static int enic_set_mac_addr(struct net_device *netdev, char *addr)
 static void enic_set_multicast_list(struct net_device *netdev)
 {
        struct enic *enic = netdev_priv(netdev);
-       struct dev_mc_list *list = netdev->mc_list;
+       struct dev_mc_list *list;
        int directed = 1;
        int multicast = (netdev->flags & IFF_MULTICAST) ? 1 : 0;
        int broadcast = (netdev->flags & IFF_BROADCAST) ? 1 : 0;
        int promisc = (netdev->flags & IFF_PROMISC) ? 1 : 0;
+       unsigned int mc_count = netdev_mc_count(netdev);
        int allmulti = (netdev->flags & IFF_ALLMULTI) ||
-           (netdev->mc_count > ENIC_MULTICAST_PERFECT_FILTERS);
+                      mc_count > ENIC_MULTICAST_PERFECT_FILTERS;
+       unsigned int flags = netdev->flags | (allmulti ? IFF_ALLMULTI : 0);
        u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
-       unsigned int mc_count = netdev->mc_count;
        unsigned int i, j;
 
        if (mc_count > ENIC_MULTICAST_PERFECT_FILTERS)
@@ -780,8 +839,11 @@ static void enic_set_multicast_list(struct net_device *netdev)
 
        spin_lock(&enic->devcmd_lock);
 
-       vnic_dev_packet_filter(enic->vdev, directed,
-               multicast, broadcast, promisc, allmulti);
+       if (enic->flags != flags) {
+               enic->flags = flags;
+               vnic_dev_packet_filter(enic->vdev, directed,
+                       multicast, broadcast, promisc, allmulti);
+       }
 
        /* Is there an easier way?  Trying to minimize to
         * calls to add/del multicast addrs.  We keep the
@@ -789,9 +851,11 @@ static void enic_set_multicast_list(struct net_device *netdev)
         * look for changes to add/del.
         */
 
-       for (i = 0; list && i < mc_count; i++) {
-               memcpy(mc_addr[i], list->dmi_addr, ETH_ALEN);
-               list = list->next;
+       i = 0;
+       netdev_for_each_mc_addr(list, netdev) {
+               if (i == mc_count)
+                       break;
+               memcpy(mc_addr[i++], list->dmi_addr, ETH_ALEN);
        }
 
        for (i = 0; i < enic->mc_count; i++) {
@@ -1084,34 +1148,6 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc,
        return 0;
 }
 
-static void enic_rq_drop_buf(struct vnic_rq *rq,
-       struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
-       int skipped, void *opaque)
-{
-       struct enic *enic = vnic_dev_priv(rq->vdev);
-       struct sk_buff *skb = buf->os_buf;
-
-       if (skipped)
-               return;
-
-       pci_unmap_single(enic->pdev, buf->dma_addr,
-               buf->len, PCI_DMA_FROMDEVICE);
-
-       dev_kfree_skb_any(skb);
-}
-
-static int enic_rq_service_drop(struct vnic_dev *vdev, struct cq_desc *cq_desc,
-       u8 type, u16 q_number, u16 completed_index, void *opaque)
-{
-       struct enic *enic = vnic_dev_priv(vdev);
-
-       vnic_rq_service(&enic->rq[q_number], cq_desc,
-               completed_index, VNIC_RQ_RETURN_DESC,
-               enic_rq_drop_buf, opaque);
-
-       return 0;
-}
-
 static int enic_poll(struct napi_struct *napi, int budget)
 {
        struct enic *enic = container_of(napi, struct enic, napi);
@@ -1119,6 +1155,7 @@ static int enic_poll(struct napi_struct *napi, int budget)
        unsigned int rq_work_to_do = budget;
        unsigned int wq_work_to_do = -1; /* no limit */
        unsigned int  work_done, rq_work_done, wq_work_done;
+       int err;
 
        /* Service RQ (first) and WQ
         */
@@ -1142,16 +1179,19 @@ static int enic_poll(struct napi_struct *napi, int budget)
                        0 /* don't unmask intr */,
                        0 /* don't reset intr timer */);
 
-       if (rq_work_done > 0) {
+       err = vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
 
-               /* Replenish RQ
-                */
+       /* Buffer allocation failed. Stay in polling
+        * mode so we can try to fill the ring again.
+        */
 
-               vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
+       if (err)
+               rq_work_done = rq_work_to_do;
 
-       } else {
+       if (rq_work_done < rq_work_to_do) {
 
-               /* If no work done, flush all LROs and exit polling
+               /* Some work done, but not enough to stay in polling,
+                * flush all LROs and exit polling
                 */
 
                if (netdev->features & NETIF_F_LRO)
@@ -1170,6 +1210,7 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
        struct net_device *netdev = enic->netdev;
        unsigned int work_to_do = budget;
        unsigned int work_done;
+       int err;
 
        /* Service RQ
         */
@@ -1177,25 +1218,30 @@ static int enic_poll_msix(struct napi_struct *napi, int budget)
        work_done = vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
                work_to_do, enic_rq_service, NULL);
 
-       if (work_done > 0) {
-
-               /* Replenish RQ
-                */
-
-               vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
-
-               /* Return intr event credits for this polling
-                * cycle.  An intr event is the completion of a
-                * RQ packet.
-                */
+       /* Return intr event credits for this polling
+        * cycle.  An intr event is the completion of a
+        * RQ packet.
+        */
 
+       if (work_done > 0)
                vnic_intr_return_credits(&enic->intr[ENIC_MSIX_RQ],
                        work_done,
                        0 /* don't unmask intr */,
                        0 /* don't reset intr timer */);
-       } else {
 
-               /* If no work done, flush all LROs and exit polling
+       err = vnic_rq_fill(&enic->rq[0], enic->rq_alloc_buf);
+
+       /* Buffer allocation failed. Stay in polling mode
+        * so we can try to fill the ring again.
+        */
+
+       if (err)
+               work_done = work_to_do;
+
+       if (work_done < work_to_do) {
+
+               /* Some work done, but not enough to stay in polling,
+                * flush all LROs and exit polling
                 */
 
                if (netdev->features & NETIF_F_LRO)
@@ -1304,6 +1350,24 @@ static int enic_request_intr(struct enic *enic)
        return err;
 }
 
+static void enic_synchronize_irqs(struct enic *enic)
+{
+       unsigned int i;
+
+       switch (vnic_dev_get_intr_mode(enic->vdev)) {
+       case VNIC_DEV_INTR_MODE_INTX:
+       case VNIC_DEV_INTR_MODE_MSI:
+               synchronize_irq(enic->pdev->irq);
+               break;
+       case VNIC_DEV_INTR_MODE_MSIX:
+               for (i = 0; i < enic->intr_count; i++)
+                       synchronize_irq(enic->msix_entry[i].vector);
+               break;
+       default:
+               break;
+       }
+}
+
 static int enic_notify_set(struct enic *enic)
 {
        int err;
@@ -1360,11 +1424,13 @@ static int enic_open(struct net_device *netdev)
        }
 
        for (i = 0; i < enic->rq_count; i++) {
-               err = vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf);
-               if (err) {
+               vnic_rq_fill(&enic->rq[i], enic->rq_alloc_buf);
+               /* Need at least one buffer on ring to get going */
+               if (vnic_rq_desc_used(&enic->rq[i]) == 0) {
                        printk(KERN_ERR PFX
                                "%s: Unable to alloc receive buffers.\n",
                                netdev->name);
+                       err = -ENOMEM;
                        goto err_out_notify_unset;
                }
        }
@@ -1409,16 +1475,19 @@ static int enic_stop(struct net_device *netdev)
        unsigned int i;
        int err;
 
+       for (i = 0; i < enic->intr_count; i++)
+               vnic_intr_mask(&enic->intr[i]);
+
+       enic_synchronize_irqs(enic);
+
        del_timer_sync(&enic->notify_timer);
 
        spin_lock(&enic->devcmd_lock);
        vnic_dev_disable(enic->vdev);
        spin_unlock(&enic->devcmd_lock);
        napi_disable(&enic->napi);
-       netif_stop_queue(netdev);
-
-       for (i = 0; i < enic->intr_count; i++)
-               vnic_intr_mask(&enic->intr[i]);
+       netif_carrier_off(netdev);
+       netif_tx_disable(netdev);
 
        for (i = 0; i < enic->wq_count; i++) {
                err = vnic_wq_disable(&enic->wq[i]);
@@ -1436,11 +1505,6 @@ static int enic_stop(struct net_device *netdev)
        spin_unlock(&enic->devcmd_lock);
        enic_free_intr(enic);
 
-       (void)vnic_cq_service(&enic->cq[ENIC_CQ_RQ],
-               -1, enic_rq_service_drop, NULL);
-       (void)vnic_cq_service(&enic->cq[ENIC_CQ_WQ],
-               -1, enic_wq_service, NULL);
-
        for (i = 0; i < enic->wq_count; i++)
                vnic_wq_clean(&enic->wq[i], enic_free_wq_buf);
        for (i = 0; i < enic->rq_count; i++)
@@ -1762,7 +1826,8 @@ int enic_dev_init(struct enic *enic)
        err = enic_set_intr_mode(enic);
        if (err) {
                printk(KERN_ERR PFX
-                       "Failed to set intr mode, aborting.\n");
+                       "Failed to set intr mode based on resource "
+                       "counts and system capabilities, aborting.\n");
                return err;
        }
 
@@ -1986,6 +2051,9 @@ static int __devinit enic_probe(struct pci_dev *pdev,
                goto err_out_dev_deinit;
        }
 
+       enic->tx_coalesce_usecs = enic->config.intr_timer_usec;
+       enic->rx_coalesce_usecs = enic->tx_coalesce_usecs;
+
        netdev->netdev_ops = &enic_netdev_ops;
        netdev->watchdog_timeo = 2 * HZ;
        netdev->ethtool_ops = &enic_ethtool_ops;