]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/netxen/netxen_nic_main.c
netxen: improve msi support
[karo-tx-linux.git] / drivers / net / netxen / netxen_nic_main.c
index 454226f7baa86ad6a022b1eae1a941553d78a7e6..cd665da85c7f72978bafa2cfe92b90653ee558bf 100644 (file)
@@ -89,8 +89,8 @@ MODULE_DEVICE_TABLE(pci, netxen_pci_tbl);
 struct workqueue_struct *netxen_workq;
 static void netxen_watchdog(unsigned long);
 
-static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
-                                                       uint32_t crb_producer)
+static void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
+                                          uint32_t crb_producer)
 {
        switch (adapter->portnum) {
                case 0:
@@ -118,8 +118,8 @@ static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter
        }
 }
 
-static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter,
-                                                       u32 crb_consumer)
+static void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter,
+                                          u32 crb_consumer)
 {
        switch (adapter->portnum) {
                case 0:
@@ -148,35 +148,32 @@ static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter
 }
 
 #define        ADAPTER_LIST_SIZE 12
-int netxen_cards_found;
+
+static uint32_t msi_tgt_status[4] = {
+       ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1,
+       ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3
+};
+
+static uint32_t sw_int_mask[4] = {
+       CRB_SW_INT_MASK_0, CRB_SW_INT_MASK_1,
+       CRB_SW_INT_MASK_2, CRB_SW_INT_MASK_3
+};
 
 static void netxen_nic_disable_int(struct netxen_adapter *adapter)
 {
-       uint32_t        mask = 0x7ff;
+       u32 mask = 0x7ff;
        int retries = 32;
+       int port = adapter->portnum;
+       int pci_fn = adapter->ahw.pci_func;
 
-       DPRINTK(1, INFO, "Entered ISR Disable \n");
-
-       switch (adapter->portnum) {
-       case 0:
-               writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_0));
-               break;
-       case 1:
-               writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_1));
-               break;
-       case 2:
-               writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_2));
-               break;
-       case 3:
-               writel(0x0, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_3));
-               break;
+       if (adapter->msi_mode != MSI_MODE_MULTIFUNC) {
+               writel(0x0, NETXEN_CRB_NORMALIZE(adapter, sw_int_mask[port]));
        }
 
        if (adapter->intr_scheme != -1 &&
            adapter->intr_scheme != INTR_SCHEME_PERPORT)
                writel(mask,PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_MASK));
 
-       /* Window = 0 or 1 */
        if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
                do {
                        writel(0xffffffff,
@@ -191,14 +188,18 @@ static void netxen_nic_disable_int(struct netxen_adapter *adapter)
                        printk(KERN_NOTICE "%s: Failed to disable interrupt completely\n",
                                        netxen_nic_driver_name);
                }
+       } else {
+               if (adapter->msi_mode == MSI_MODE_MULTIFUNC) {
+                       writel(0xffffffff, PCI_OFFSET_SECOND_RANGE(adapter,
+                                               msi_tgt_status[pci_fn]));
+               }
        }
-
-       DPRINTK(1, INFO, "Done with Disable Int\n");
 }
 
 static void netxen_nic_enable_int(struct netxen_adapter *adapter)
 {
        u32 mask;
+       int port = adapter->portnum;
 
        DPRINTK(1, INFO, "Entered ISR Enable \n");
 
@@ -219,20 +220,7 @@ static void netxen_nic_enable_int(struct netxen_adapter *adapter)
                writel(mask, PCI_OFFSET_SECOND_RANGE(adapter, ISR_INT_MASK));
        }
 
-       switch (adapter->portnum) {
-       case 0:
-               writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_0));
-               break;
-       case 1:
-               writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_1));
-               break;
-       case 2:
-               writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_2));
-               break;
-       case 3:
-               writel(0x1, NETXEN_CRB_NORMALIZE(adapter, CRB_SW_INT_MASK_3));
-               break;
-       }
+       writel(0x1, NETXEN_CRB_NORMALIZE(adapter, sw_int_mask[port]));
 
        if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) {
                mask = 0xbff;
@@ -278,7 +266,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct netxen_recv_context *recv_ctx = NULL;
        struct netxen_rcv_desc_ctx *rcv_desc = NULL;
        struct netxen_cmd_buffer *cmd_buf_arr = NULL;
-       u64 mac_addr[FLASH_NUM_PORTS + 1];
+       __le64 mac_addr[FLASH_NUM_PORTS + 1];
        int valid_mac = 0;
        u32 val;
        int pci_func_id = PCI_FUNC(pdev->devfn);
@@ -287,7 +275,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        printk(KERN_INFO "%s \n", netxen_nic_driver_string);
 
        if (pdev->class != 0x020000) {
-               printk(KERN_ERR"NetXen function %d, class %x will not"
+               printk(KERN_ERR"NetXen function %d, class %x will not "
                                "be enabled.\n",pci_func_id, pdev->class);
                return -ENODEV;
        }
@@ -351,12 +339,12 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                first_page_group_start = 0;
                first_page_group_end   = 0;
        } else {
-               err = -EIO; 
+               err = -EIO;
                goto err_out_free_netdev;
        }
 
-       if (((mem_ptr0 == 0UL) && (mem_len == NETXEN_PCI_128MB_SIZE)) ||
-                       (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) {
+       if ((!mem_ptr0 && mem_len == NETXEN_PCI_128MB_SIZE) ||
+                       !mem_ptr1 || !mem_ptr2) {
                DPRINTK(ERR,
                        "Cannot remap adapter memory aborting.:"
                        "0 -> %p, 1 -> %p, 2 -> %p\n",
@@ -402,6 +390,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        /* this will be read from FW later */
        adapter->intr_scheme = -1;
+       adapter->msi_mode = -1;
 
        /* This will be reset for mezz cards  */
        adapter->portnum = pci_func_id;
@@ -411,7 +400,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        netdev->open               = netxen_nic_open;
        netdev->stop               = netxen_nic_close;
        netdev->hard_start_xmit    = netxen_nic_xmit_frame;
-       netdev->get_stats          = netxen_nic_get_stats;      
+       netdev->get_stats          = netxen_nic_get_stats;
        netdev->set_multicast_list = netxen_nic_set_multi;
        netdev->set_mac_address    = netxen_nic_set_mac;
        netdev->change_mtu         = netxen_nic_change_mtu;
@@ -458,8 +447,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS_HOST;
        if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB35_4G) ||
-                       (adapter->ahw.boardcfg.board_type == 
-                        NETXEN_BRDTYPE_P2_SB31_2G)) 
+                       (adapter->ahw.boardcfg.board_type ==
+                        NETXEN_BRDTYPE_P2_SB31_2G))
                adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
        else
                adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS;
@@ -511,7 +500,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                            vmalloc(RCV_BUFFSIZE);
 
                        if (rcv_desc->rx_buf_arr == NULL) {
-                               printk(KERN_ERR "%s: Could not allocate"
+                               printk(KERN_ERR "%s: Could not allocate "
                                       "rcv_desc->rx_buf_arr memory:%d\n",
                                       netxen_nic_driver_name,
                                       (int)RCV_BUFFSIZE);
@@ -584,9 +573,9 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        if (adapter->portnum == 0) {
                err = netxen_initialize_adapter_offload(adapter);
-               if (err) 
+               if (err)
                        goto err_out_free_rx_buffer;
-               val = readl(NETXEN_CRB_NORMALIZE(adapter, 
+               val = readl(NETXEN_CRB_NORMALIZE(adapter,
                                        NETXEN_CAM_RAM(0x1fc)));
                if (val == 0x55555555) {
                    /* This is the first boot after power up */
@@ -620,7 +609,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                /*
                 * Tell the hardware our version number.
                 */
-               i = (_NETXEN_NIC_LINUX_MAJOR << 16) 
+               i = (_NETXEN_NIC_LINUX_MAJOR << 16)
                        | ((_NETXEN_NIC_LINUX_MINOR << 8))
                        | (_NETXEN_NIC_LINUX_SUBVERSION);
                writel(i, NETXEN_CRB_NORMALIZE(adapter, CRB_DRIVER_VERSION));
@@ -660,7 +649,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                        break;
 
                case NETXEN_NIC_XGBE:
-                       printk(KERN_INFO "%s: XGbE board initialized\n", 
+                       printk(KERN_INFO "%s: XGbE board initialized\n",
                                        netxen_nic_driver_name);
                        break;
        }
@@ -732,11 +721,6 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
 
        unregister_netdev(netdev);
 
-       if (adapter->stop_port)
-               adapter->stop_port(adapter);
-
-       netxen_nic_disable_int(adapter);
-
        if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
                init_firmware_done++;
                netxen_free_hw_resources(adapter);
@@ -919,6 +903,9 @@ static int netxen_nic_close(struct net_device *netdev)
        netif_stop_queue(netdev);
        napi_disable(&adapter->napi);
 
+       if (adapter->stop_port)
+               adapter->stop_port(adapter);
+
        netxen_nic_disable_int(adapter);
 
        cmd_buff = adapter->cmd_buf_arr;
@@ -933,7 +920,7 @@ static int netxen_nic_close(struct net_device *netdev)
                        buffrag++;
                        if (buffrag->dma) {
                                pci_unmap_page(adapter->pdev, buffrag->dma,
-                                              buffrag->length, 
+                                              buffrag->length,
                                               PCI_DMA_TODEVICE);
                                buffrag->dma = 0ULL;
                        }
@@ -983,7 +970,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        }
 
        if (frag_count > MAX_BUFFERS_PER_CMD) {
-               printk("%s: %s netxen_nic_xmit_frame: frag_count (%d)"
+               printk("%s: %s netxen_nic_xmit_frame: frag_count (%d) "
                       "too large, can handle only %d frags\n",
                       netxen_nic_driver_name, netdev->name,
                       frag_count, MAX_BUFFERS_PER_CMD);
@@ -996,28 +983,6 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                return NETDEV_TX_OK;
        }
 
-       /*
-        * Everything is set up. Now, we just need to transmit it out.
-        * Note that we have to copy the contents of buffer over to
-        * right place. Later on, this can be optimized out by de-coupling the
-        * producer index from the buffer index.
-        */
-      retry_getting_window:
-       spin_lock_bh(&adapter->tx_lock);
-       if (adapter->total_threads >= MAX_XMIT_PRODUCERS) {
-               spin_unlock_bh(&adapter->tx_lock);
-               /*
-                * Yield CPU
-                */
-               if (!in_atomic())
-                       schedule();
-               else {
-                       for (i = 0; i < 20; i++)
-                               cpu_relax();    /*This a nop instr on i386 */
-               }
-               goto retry_getting_window;
-       }
-       local_producer = adapter->cmd_producer;
        /* There 4 fragments per descriptor */
        no_of_desc = (frag_count + 3) >> 2;
        if (netdev->features & NETIF_F_TSO) {
@@ -1031,16 +996,19 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                        }
                }
        }
+
+       spin_lock_bh(&adapter->tx_lock);
+       if (adapter->total_threads >= MAX_XMIT_PRODUCERS) {
+               goto out_requeue;
+       }
+       local_producer = adapter->cmd_producer;
        k = adapter->cmd_producer;
        max_tx_desc_count = adapter->max_tx_desc_count;
        last_cmd_consumer = adapter->last_cmd_consumer;
        if ((k + no_of_desc) >=
            ((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count :
             last_cmd_consumer)) {
-               netif_stop_queue(netdev);
-               adapter->flags |= NETXEN_NETDEV_STATUS;
-               spin_unlock_bh(&adapter->tx_lock);
-               return NETDEV_TX_BUSY;
+               goto out_requeue;
        }
        k = get_index_range(k, max_tx_desc_count, no_of_desc);
        adapter->cmd_producer = k;
@@ -1093,6 +1061,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                                                  adapter->max_tx_desc_count);
                        hwdesc = &hw->cmd_desc_head[producer];
                        memset(hwdesc, 0, sizeof(struct cmd_desc_type0));
+                       pbuf = &adapter->cmd_buf_arr[producer];
+                       pbuf->skb = NULL;
                }
                frag = &skb_shinfo(skb)->frags[i - 1];
                len = frag->size;
@@ -1148,6 +1118,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                }
                /* copy the MAC/IP/TCP headers to the cmd descriptor list */
                hwdesc = &hw->cmd_desc_head[producer];
+               pbuf = &adapter->cmd_buf_arr[producer];
+               pbuf->skb = NULL;
 
                /* copy the first 64 bytes */
                memcpy(((void *)hwdesc) + 2,
@@ -1156,6 +1128,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
                if (more_hdr) {
                        hwdesc = &hw->cmd_desc_head[producer];
+                       pbuf = &adapter->cmd_buf_arr[producer];
+                       pbuf->skb = NULL;
                        /* copy the next 64 bytes - should be enough except
                         * for pathological case
                         */
@@ -1167,16 +1141,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                }
        }
 
-       i = netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]);
-
-       hw->cmd_desc_head[saved_producer].flags_opcode =
-               cpu_to_le16(hw->cmd_desc_head[saved_producer].flags_opcode);
-       hw->cmd_desc_head[saved_producer].num_of_buffers_total_length =
-         cpu_to_le32(hw->cmd_desc_head[saved_producer].
-                         num_of_buffers_total_length);
-
        spin_lock_bh(&adapter->tx_lock);
-       adapter->stats.txbytes += i;
+       adapter->stats.txbytes += skb->len;
 
        /* Code to update the adapter considering how many producer threads
           are currently working */
@@ -1189,14 +1155,17 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        }
 
        adapter->stats.xmitfinished++;
-       spin_unlock_bh(&adapter->tx_lock);
-
        netdev->trans_start = jiffies;
 
-       DPRINTK(INFO, "wrote CMD producer %x to phantom\n", producer);
-
-       DPRINTK(INFO, "Done. Send\n");
+       spin_unlock_bh(&adapter->tx_lock);
        return NETDEV_TX_OK;
+
+out_requeue:
+       netif_stop_queue(netdev);
+       adapter->flags |= NETXEN_NETDEV_STATUS;
+
+       spin_unlock_bh(&adapter->tx_lock);
+       return NETDEV_TX_BUSY;
 }
 
 static void netxen_watchdog(unsigned long v)
@@ -1215,7 +1184,7 @@ static void netxen_tx_timeout(struct net_device *netdev)
 
 static void netxen_tx_timeout_task(struct work_struct *work)
 {
-       struct netxen_adapter *adapter = 
+       struct netxen_adapter *adapter =
                container_of(work, struct netxen_adapter, tx_timeout_task);
 
        printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
@@ -1358,7 +1327,7 @@ static struct pci_driver netxen_driver = {
 
 static int __init netxen_init_module(void)
 {
-       if ((netxen_workq = create_singlethread_workqueue("netxen")) == 0)
+       if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL)
                return -ENOMEM;
 
        return pci_register_driver(&netxen_driver);