]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/s2io.c
Merge branch 'fixes-jgarzik' of git://git.kernel.org/pub/scm/linux/kernel/git/linvill...
[linux-2.6-omap-h63xx.git] / drivers / net / s2io.c
index b8c0e7b4ca1cdd0e0d4d3a9251af47cff784a326..9d80f1cf73acbbe70a9eb8df62ef6a9c2f6be871 100644 (file)
@@ -84,7 +84,7 @@
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.26.5"
+#define DRV_VERSION "2.0.26.10"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
@@ -1081,7 +1081,7 @@ static int init_nic(struct s2io_nic *nic)
        /* to set the swapper controle on the card */
        if(s2io_set_swapper(nic)) {
                DBG_PRINT(ERR_DBG,"ERROR: Setting Swapper failed\n");
-               return -1;
+               return -EIO;
        }
 
        /*
@@ -1100,6 +1100,20 @@ static int init_nic(struct s2io_nic *nic)
        msleep(500);
        val64 = readq(&bar0->sw_reset);
 
+       /* Ensure that it's safe to access registers by checking
+        * RIC_RUNNING bit is reset. Check is valid only for XframeII.
+        */
+       if (nic->device_type == XFRAME_II_DEVICE) {
+               for (i = 0; i < 50; i++) {
+                       val64 = readq(&bar0->adapter_status);
+                       if (!(val64 & ADAPTER_STATUS_RIC_RUNNING))
+                               break;
+                       msleep(10);
+               }
+               if (i == 50)
+                       return -ENODEV;
+       }
+
        /*  Enable Receiving broadcasts */
        add = &bar0->mac_cfg;
        val64 = readq(&bar0->mac_cfg);
@@ -1503,7 +1517,7 @@ static int init_nic(struct s2io_nic *nic)
                        DBG_PRINT(ERR_DBG, "%s: failed rts ds steering",
                                dev->name);
                        DBG_PRINT(ERR_DBG, "set on codepoint %d\n", i);
-                       return FAILURE;
+                       return -ENODEV;
                }
        }
 
@@ -1570,7 +1584,7 @@ static int init_nic(struct s2io_nic *nic)
                if (time > 10) {
                        DBG_PRINT(ERR_DBG, "%s: TTI init Failed\n",
                                  dev->name);
-                       return -1;
+                       return -ENODEV;
                }
                msleep(50);
                time++;
@@ -1623,7 +1637,7 @@ static int init_nic(struct s2io_nic *nic)
                        if (time > 10) {
                                DBG_PRINT(ERR_DBG, "%s: RTI init Failed\n",
                                          dev->name);
-                               return -1;
+                               return -ENODEV;
                        }
                        time++;
                        msleep(50);
@@ -3723,7 +3737,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic)
 }
 
 /* Handle software interrupt used during MSI(X) test */
-static irqreturn_t __devinit s2io_test_intr(int irq, void *dev_id)
+static irqreturn_t s2io_test_intr(int irq, void *dev_id)
 {
        struct s2io_nic *sp = dev_id;
 
@@ -3734,7 +3748,7 @@ static irqreturn_t __devinit s2io_test_intr(int irq, void *dev_id)
 }
 
 /* Test interrupt path by forcing a a software IRQ */
-static int __devinit s2io_test_msi(struct s2io_nic *sp)
+static int s2io_test_msi(struct s2io_nic *sp)
 {
        struct pci_dev *pdev = sp->pdev;
        struct XENA_dev_config __iomem *bar0 = sp->bar0;
@@ -3775,6 +3789,40 @@ static int __devinit s2io_test_msi(struct s2io_nic *sp)
 
        return err;
 }
+
+static void remove_msix_isr(struct s2io_nic *sp)
+{
+       int i;
+       u16 msi_control;
+
+       for (i = 0; i < MAX_REQUESTED_MSI_X; i++) {
+               if (sp->s2io_entries[i].in_use ==
+                       MSIX_REGISTERED_SUCCESS) {
+                       int vector = sp->entries[i].vector;
+                       void *arg = sp->s2io_entries[i].arg;
+                       free_irq(vector, arg);
+               }
+       }
+
+       kfree(sp->entries);
+       kfree(sp->s2io_entries);
+       sp->entries = NULL;
+       sp->s2io_entries = NULL;
+
+       pci_read_config_word(sp->pdev, 0x42, &msi_control);
+       msi_control &= 0xFFFE; /* Disable MSI */
+       pci_write_config_word(sp->pdev, 0x42, msi_control);
+
+       pci_disable_msix(sp->pdev);
+}
+
+static void remove_inta_isr(struct s2io_nic *sp)
+{
+       struct net_device *dev = sp->dev;
+
+       free_irq(sp->pdev->irq, dev);
+}
+
 /* ********************************************************* *
  * Functions defined below concern the OS part of the driver *
  * ********************************************************* */
@@ -3809,28 +3857,9 @@ static int s2io_open(struct net_device *dev)
                int ret = s2io_enable_msi_x(sp);
 
                if (!ret) {
-                       u16 msi_control;
-
                        ret = s2io_test_msi(sp);
-
                        /* rollback MSI-X, will re-enable during add_isr() */
-                       kfree(sp->entries);
-                       sp->mac_control.stats_info->sw_stat.mem_freed +=
-                               (MAX_REQUESTED_MSI_X *
-                               sizeof(struct msix_entry));
-                       kfree(sp->s2io_entries);
-                       sp->mac_control.stats_info->sw_stat.mem_freed +=
-                               (MAX_REQUESTED_MSI_X *
-                               sizeof(struct s2io_msix_entry));
-                       sp->entries = NULL;
-                       sp->s2io_entries = NULL;
-
-                       pci_read_config_word(sp->pdev, 0x42, &msi_control);
-                       msi_control &= 0xFFFE; /* Disable MSI */
-                       pci_write_config_word(sp->pdev, 0x42, msi_control);
-
-                       pci_disable_msix(sp->pdev);
-
+                       remove_msix_isr(sp);
                }
                if (ret) {
 
@@ -3899,6 +3928,12 @@ static int s2io_close(struct net_device *dev)
 {
        struct s2io_nic *sp = dev->priv;
 
+       /* Return if the device is already closed               *
+       *  Can happen when s2io_card_up failed in change_mtu    *
+       */
+       if (!is_s2io_card_up(sp))
+               return 0;
+
        netif_stop_queue(dev);
        napi_disable(&sp->napi);
        /* Reset card, kill tasklet and free Tx and Rx buffers. */
@@ -6340,6 +6375,7 @@ static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 static int s2io_change_mtu(struct net_device *dev, int new_mtu)
 {
        struct s2io_nic *sp = dev->priv;
+       int ret = 0;
 
        if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
                DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
@@ -6351,9 +6387,11 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
        if (netif_running(dev)) {
                s2io_card_down(sp);
                netif_stop_queue(dev);
-               if (s2io_card_up(sp)) {
+               ret = s2io_card_up(sp);
+               if (ret) {
                        DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
                                  __FUNCTION__);
+                       return ret;
                }
                if (netif_queue_stopped(dev))
                        netif_wake_queue(dev);
@@ -6364,7 +6402,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
                writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
        }
 
-       return 0;
+       return ret;
 }
 
 /**
@@ -6719,15 +6757,22 @@ static int s2io_add_isr(struct s2io_nic * sp)
                                }
                        }
                        if (err) {
+                               remove_msix_isr(sp);
                                DBG_PRINT(ERR_DBG,"%s:MSI-X-%d registration "
                                          "failed\n", dev->name, i);
-                               DBG_PRINT(ERR_DBG, "Returned: %d\n", err);
-                               return -1;
+                               DBG_PRINT(ERR_DBG, "%s: defaulting to INTA\n",
+                                                dev->name);
+                               sp->config.intr_type = INTA;
+                               break;
                        }
                        sp->s2io_entries[i].in_use = MSIX_REGISTERED_SUCCESS;
                }
-               printk("MSI-X-TX %d entries enabled\n",msix_tx_cnt);
-               printk("MSI-X-RX %d entries enabled\n",msix_rx_cnt);
+               if (!err) {
+                       printk(KERN_INFO "MSI-X-TX %d entries enabled\n",
+                               msix_tx_cnt);
+                       printk(KERN_INFO "MSI-X-RX %d entries enabled\n",
+                               msix_rx_cnt);
+               }
        }
        if (sp->config.intr_type == INTA) {
                err = request_irq((int) sp->pdev->irq, s2io_isr, IRQF_SHARED,
@@ -6742,40 +6787,10 @@ static int s2io_add_isr(struct s2io_nic * sp)
 }
 static void s2io_rem_isr(struct s2io_nic * sp)
 {
-       struct net_device *dev = sp->dev;
-       struct swStat *stats = &sp->mac_control.stats_info->sw_stat;
-
-       if (sp->config.intr_type == MSI_X) {
-               int i;
-               u16 msi_control;
-
-               for (i=1; (sp->s2io_entries[i].in_use ==
-                       MSIX_REGISTERED_SUCCESS); i++) {
-                       int vector = sp->entries[i].vector;
-                       void *arg = sp->s2io_entries[i].arg;
-
-                       synchronize_irq(vector);
-                       free_irq(vector, arg);
-               }
-
-               kfree(sp->entries);
-               stats->mem_freed +=
-                       (MAX_REQUESTED_MSI_X * sizeof(struct msix_entry));
-               kfree(sp->s2io_entries);
-               stats->mem_freed +=
-                       (MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry));
-               sp->entries = NULL;
-               sp->s2io_entries = NULL;
-
-               pci_read_config_word(sp->pdev, 0x42, &msi_control);
-               msi_control &= 0xFFFE; /* Disable MSI */
-               pci_write_config_word(sp->pdev, 0x42, msi_control);
-
-               pci_disable_msix(sp->pdev);
-       } else {
-               synchronize_irq(sp->pdev->irq);
-               free_irq(sp->pdev->irq, dev);
-       }
+       if (sp->config.intr_type == MSI_X)
+               remove_msix_isr(sp);
+       else
+               remove_inta_isr(sp);
 }
 
 static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
@@ -6785,6 +6800,9 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io)
        unsigned long flags;
        register u64 val64 = 0;
 
+       if (!is_s2io_card_up(sp))
+               return;
+
        del_timer_sync(&sp->alarm_timer);
        /* If s2io_set_link task is executing, wait till it completes. */
        while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) {
@@ -6858,11 +6876,13 @@ static int s2io_card_up(struct s2io_nic * sp)
        u16 interruptible;
 
        /* Initialize the H/W I/O registers */
-       if (init_nic(sp) != 0) {
+       ret = init_nic(sp);
+       if (ret != 0) {
                DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
                          dev->name);
-               s2io_reset(sp);
-               return -ENODEV;
+               if (ret != -EIO)
+                       s2io_reset(sp);
+               return ret;
        }
 
        /*