]> err.no Git - linux-2.6/blobdiff - drivers/net/netxen/netxen_nic_main.c
Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / drivers / net / netxen / netxen_nic_main.c
index 7615c715e66efd0b3cffb33d1c103f79c1c50916..32bb47adbe39b3db3b2c44b083c73ece4fbd3b9a 100644 (file)
@@ -149,76 +149,18 @@ static uint32_t msi_tgt_status[8] = {
 
 static struct netxen_legacy_intr_set legacy_intr[] = NX_LEGACY_INTR_CONFIG;
 
-static void netxen_nic_disable_int(struct netxen_adapter *adapter)
+static inline void netxen_nic_disable_int(struct netxen_adapter *adapter)
 {
-       u32 mask = 0x7ff;
-       int retries = 32;
-       int pci_fn = adapter->ahw.pci_func;
-
-       if (adapter->msi_mode != MSI_MODE_MULTIFUNC)
-               adapter->pci_write_normalize(adapter,
-                               adapter->crb_intr_mask, 0);
-
-       if (adapter->intr_scheme != -1 &&
-           adapter->intr_scheme != INTR_SCHEME_PERPORT)
-               adapter->pci_write_immediate(adapter, ISR_INT_MASK, mask);
-
-       if (!NETXEN_IS_MSI_FAMILY(adapter)) {
-               do {
-                       adapter->pci_write_immediate(adapter,
-                                       adapter->legacy_intr.tgt_status_reg,
-                                       0xffffffff);
-                       mask = adapter->pci_read_immediate(adapter,
-                                       ISR_INT_VECTOR);
-                       if (!(mask & 0x80))
-                               break;
-                       udelay(10);
-               } while (--retries);
-
-               if (!retries) {
-                       printk(KERN_NOTICE "%s: Failed to disable interrupt\n",
-                                       netxen_nic_driver_name);
-               }
-       } else {
-               if (adapter->msi_mode == MSI_MODE_MULTIFUNC) {
-                       adapter->pci_write_immediate(adapter,
-                                       msi_tgt_status[pci_fn], 0xffffffff);
-               }
-       }
+       adapter->pci_write_normalize(adapter, adapter->crb_intr_mask, 0);
 }
 
-static void netxen_nic_enable_int(struct netxen_adapter *adapter)
+static inline void netxen_nic_enable_int(struct netxen_adapter *adapter)
 {
-       u32 mask;
-
-       if (adapter->intr_scheme != -1 &&
-               adapter->intr_scheme != INTR_SCHEME_PERPORT) {
-               switch (adapter->ahw.board_type) {
-               case NETXEN_NIC_GBE:
-                       mask  =  0x77b;
-                       break;
-               case NETXEN_NIC_XGBE:
-                       mask  =  0x77f;
-                       break;
-               default:
-                       mask  =  0x7ff;
-                       break;
-               }
-
-               adapter->pci_write_immediate(adapter, ISR_INT_MASK, mask);
-       }
-
        adapter->pci_write_normalize(adapter, adapter->crb_intr_mask, 0x1);
 
-       if (!NETXEN_IS_MSI_FAMILY(adapter)) {
-               mask = 0xbff;
-               if (adapter->intr_scheme == INTR_SCHEME_PERPORT)
-                       adapter->pci_write_immediate(adapter,
-                               adapter->legacy_intr.tgt_mask_reg, mask);
-               else
-                       adapter->pci_write_normalize(adapter,
-                                       CRB_INT_VECTOR, 0);
-       }
+       if (!NETXEN_IS_MSI_FAMILY(adapter))
+               adapter->pci_write_immediate(adapter,
+                               adapter->legacy_intr.tgt_mask_reg, 0xfbff);
 }
 
 static int nx_set_dma_mask(struct netxen_adapter *adapter, uint8_t revision_id)
@@ -501,6 +443,44 @@ static void netxen_init_msix_entries(struct netxen_adapter *adapter)
                adapter->msix_entries[i].entry = i;
 }
 
+static int
+netxen_read_mac_addr(struct netxen_adapter *adapter)
+{
+       int i;
+       unsigned char *p;
+       __le64 mac_addr;
+       DECLARE_MAC_BUF(mac);
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+
+       if (netxen_is_flash_supported(adapter) != 0)
+               return -EIO;
+
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+               if (netxen_p3_get_mac_addr(adapter, &mac_addr) != 0)
+                       return -EIO;
+       } else {
+               if (netxen_get_flash_mac_addr(adapter, &mac_addr) != 0)
+                       return -EIO;
+       }
+
+       p = (unsigned char *)&mac_addr;
+       for (i = 0; i < 6; i++)
+               netdev->dev_addr[i] = *(p + 5 - i);
+
+       memcpy(netdev->perm_addr, netdev->dev_addr, netdev->addr_len);
+
+       /* set station address */
+
+       if (!is_valid_ether_addr(netdev->perm_addr)) {
+               dev_warn(&pdev->dev, "Bad MAC address %s.\n",
+                               print_mac(mac, netdev->dev_addr));
+       } else
+               adapter->macaddr_set(adapter, netdev->dev_addr);
+
+       return 0;
+}
+
 /*
  * netxen_nic_probe()
  *
@@ -529,10 +509,8 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        unsigned long mem_base, mem_len, db_base, db_len, pci_len0 = 0;
        int i = 0, err;
        int first_driver, first_boot;
-       __le64 mac_addr[FLASH_NUM_PORTS + 1];
        u32 val;
        int pci_func_id = PCI_FUNC(pdev->devfn);
-       DECLARE_MAC_BUF(mac);
        struct netxen_legacy_intr_set *legacy_intrp;
        uint8_t revision_id;
 
@@ -545,6 +523,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                return -ENODEV;
        }
 
+       if (pdev->revision >= NX_P3_A0 && pdev->revision < NX_P3_B1) {
+               printk(KERN_WARNING "NetXen chip revisions between 0x%x-0x%x"
+                               "will not be enabled.\n",
+                               NX_P3_A0, NX_P3_B1);
+               return -ENODEV;
+       }
+
        if ((err = pci_enable_device(pdev)))
                return err;
 
@@ -898,34 +883,14 @@ request_msi:
                goto err_out_disable_msi;
 
        init_timer(&adapter->watchdog_timer);
-       adapter->ahw.linkup = 0;
        adapter->watchdog_timer.function = &netxen_watchdog;
        adapter->watchdog_timer.data = (unsigned long)adapter;
        INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task);
        INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task);
 
-       if (netxen_is_flash_supported(adapter) == 0 &&
-                       netxen_get_flash_mac_addr(adapter, mac_addr) == 0) {
-               unsigned char *p;
-
-               p = (unsigned char *)&mac_addr[adapter->portnum];
-               netdev->dev_addr[0] = *(p + 5);
-               netdev->dev_addr[1] = *(p + 4);
-               netdev->dev_addr[2] = *(p + 3);
-               netdev->dev_addr[3] = *(p + 2);
-               netdev->dev_addr[4] = *(p + 1);
-               netdev->dev_addr[5] = *(p + 0);
-
-               memcpy(netdev->perm_addr, netdev->dev_addr,
-                       netdev->addr_len);
-               if (!is_valid_ether_addr(netdev->perm_addr)) {
-                       printk(KERN_ERR "%s: Bad MAC address %s.\n",
-                                       netxen_nic_driver_name,
-                                       print_mac(mac, netdev->dev_addr));
-               } else {
-                       adapter->macaddr_set(adapter, netdev->dev_addr);
-               }
-       }
+       err = netxen_read_mac_addr(adapter);
+       if (err)
+               dev_warn(&pdev->dev, "failed to read mac addr\n");
 
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
@@ -1000,6 +965,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
 
        if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
                netxen_free_hw_resources(adapter);
+               netxen_release_rx_buffers(adapter);
                netxen_free_sw_resources(adapter);
        }
 
@@ -1069,6 +1035,15 @@ static int netxen_nic_open(struct net_device *netdev)
                        goto err_out_free_sw;
                }
 
+               if ((adapter->msi_mode != MSI_MODE_MULTIFUNC) ||
+                       (adapter->intr_scheme != INTR_SCHEME_PERPORT)) {
+                       printk(KERN_ERR "%s: Firmware interrupt scheme is "
+                                       "incompatible with driver\n",
+                                       netdev->name);
+                       adapter->driver_mismatch = 1;
+                       goto err_out_free_hw;
+               }
+
                if (adapter->fw_major < 4) {
                        adapter->crb_addr_cmd_producer =
                                crb_cmd_producer[adapter->portnum];
@@ -1094,7 +1069,7 @@ static int netxen_nic_open(struct net_device *netdev)
                                  flags, netdev->name, adapter);
                if (err) {
                        printk(KERN_ERR "request_irq failed with: %d\n", err);
-                       goto err_out_free_hw;
+                       goto err_out_free_rxbuf;
                }
 
                adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
@@ -1116,6 +1091,7 @@ static int netxen_nic_open(struct net_device *netdev)
        if (adapter->set_mtu)
                adapter->set_mtu(adapter, netdev->mtu);
 
+       adapter->ahw.linkup = 0;
        mod_timer(&adapter->watchdog_timer, jiffies);
 
        napi_enable(&adapter->napi);
@@ -1127,6 +1103,8 @@ static int netxen_nic_open(struct net_device *netdev)
 
 err_out_free_irq:
        free_irq(adapter->irq, adapter);
+err_out_free_rxbuf:
+       netxen_release_rx_buffers(adapter);
 err_out_free_hw:
        netxen_free_hw_resources(adapter);
 err_out_free_sw:
@@ -1152,10 +1130,8 @@ static int netxen_nic_close(struct net_device *netdev)
 
        netxen_release_tx_buffers(adapter);
 
-       if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
-               FLUSH_SCHEDULED_WORK();
-               del_timer_sync(&adapter->watchdog_timer);
-       }
+       FLUSH_SCHEDULED_WORK();
+       del_timer_sync(&adapter->watchdog_timer);
 
        return 0;
 }
@@ -1458,7 +1434,8 @@ void netxen_watchdog_task(struct work_struct *work)
 
        netxen_nic_handle_phy_intr(adapter);
 
-       mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+       if (netif_running(adapter->netdev))
+               mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
 }
 
 static void netxen_tx_timeout(struct net_device *netdev)
@@ -1518,18 +1495,9 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
        return stats;
 }
 
-static inline void
-netxen_handle_int(struct netxen_adapter *adapter)
-{
-       netxen_nic_disable_int(adapter);
-       napi_schedule(&adapter->napi);
-}
-
 static irqreturn_t netxen_intr(int irq, void *data)
 {
        struct netxen_adapter *adapter = data;
-       u32 our_int = 0;
-
        u32 status = 0;
 
        status = adapter->pci_read_immediate(adapter, ISR_INT_VECTOR);
@@ -1544,22 +1512,32 @@ static irqreturn_t netxen_intr(int irq, void *data)
                if (!ISR_LEGACY_INT_TRIGGERED(status))
                        return IRQ_NONE;
 
-       } else if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
+       } else {
+               unsigned long our_int = 0;
 
                our_int = adapter->pci_read_normalize(adapter, CRB_INT_VECTOR);
+
                /* not our interrupt */
-               if ((our_int & (0x80 << adapter->portnum)) == 0)
+               if (!test_and_clear_bit((7 + adapter->portnum), &our_int))
                        return IRQ_NONE;
 
-               if (adapter->intr_scheme == INTR_SCHEME_PERPORT) {
-                       /* claim interrupt */
-                       adapter->pci_write_normalize(adapter,
-                               CRB_INT_VECTOR,
-                               our_int & ~((u32)(0x80 << adapter->portnum)));
-               }
+               /* claim interrupt */
+               adapter->pci_write_normalize(adapter,
+                               CRB_INT_VECTOR, (our_int & 0xffffffff));
        }
 
-       netxen_handle_int(adapter);
+       /* clear interrupt */
+       if (adapter->fw_major < 4)
+               netxen_nic_disable_int(adapter);
+
+       adapter->pci_write_immediate(adapter,
+                       adapter->legacy_intr.tgt_status_reg,
+                       0xffffffff);
+       /* read twice to ensure write is flushed */
+       adapter->pci_read_immediate(adapter, ISR_INT_VECTOR);
+       adapter->pci_read_immediate(adapter, ISR_INT_VECTOR);
+
+       napi_schedule(&adapter->napi);
 
        return IRQ_HANDLED;
 }
@@ -1568,7 +1546,11 @@ static irqreturn_t netxen_msi_intr(int irq, void *data)
 {
        struct netxen_adapter *adapter = data;
 
-       netxen_handle_int(adapter);
+       /* clear interrupt */
+       adapter->pci_write_immediate(adapter,
+                       msi_tgt_status[adapter->ahw.pci_func], 0xffffffff);
+
+       napi_schedule(&adapter->napi);
        return IRQ_HANDLED;
 }