rndis_host: Poll status channel before control channel
[safe/jmp/linux-2.6] / drivers / net / enic / enic_main.c
index 019b148..1232887 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,16 +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 netdev_hw_addr *ha;
        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)
@@ -793,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(ha, netdev) {
+               if (i == mc_count)
+                       break;
+               memcpy(mc_addr[i++], ha->addr, ETH_ALEN);
        }
 
        for (i = 0; i < enic->mc_count; i++) {
@@ -1766,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;
        }
 
@@ -1990,12 +2051,14 @@ 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;
 
-       netdev->features |= NETIF_F_HW_VLAN_TX |
-               NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
+       netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
        if (ENIC_SETTING(enic, TXCSUM))
                netdev->features |= NETIF_F_SG | NETIF_F_HW_CSUM;
        if (ENIC_SETTING(enic, TSO))