|
@@ -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;
|
|
|
}
|
|
|
|