]> err.no Git - linux-2.6/blobdiff - drivers/net/s2io.c
Merge master.kernel.org:/home/rmk/linux-2.6-arm
[linux-2.6] / drivers / net / s2io.c
index f430ffe7d6f836e53281d80c5a2fafe9912d95e0..c829e6a2e8a681242b03fbcb6f26210c633aeb2e 100644 (file)
@@ -1,5 +1,5 @@
 /************************************************************************
- * s2io.c: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC
+ * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
  * Copyright(c) 2002-2005 Neterion Inc.
 
  * This software may be used and distributed according to the terms of
@@ -28,7 +28,7 @@
  * explaination of all the variables.
  * rx_ring_num : This can be used to program the number of receive rings used
  * in the driver.
- * rx_ring_len: This defines the number of descriptors each ring can have. This
+ * rx_ring_sz: This defines the number of descriptors each ring can have. This
  * is also an array of size 8.
  * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
  * tx_fifo_len: This too is an array of 8. Each element defines the number of
@@ -67,7 +67,7 @@
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
-static char s2io_driver_version[] = "Version 1.7.7";
+static char s2io_driver_version[] = "Version 2.0.8.1";
 
 static inline int RXD_IS_UP2DT(RxD_t *rxdp)
 {
@@ -210,14 +210,18 @@ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
 
 static u64 herc_act_dtx_cfg[] = {
        /* Set address */
-       0x80000515BA750000ULL, 0x80000515BA7500E0ULL,
+       0x8000051536750000ULL, 0x80000515367500E0ULL,
        /* Write data */
-       0x80000515BA750004ULL, 0x80000515BA7500E4ULL,
+       0x8000051536750004ULL, 0x80000515367500E4ULL,
        /* Set address */
        0x80010515003F0000ULL, 0x80010515003F00E0ULL,
        /* Write data */
        0x80010515003F0004ULL, 0x80010515003F00E4ULL,
        /* Set address */
+       0x801205150D440000ULL, 0x801205150D4400E0ULL,
+       /* Write data */
+       0x801205150D440004ULL, 0x801205150D4400E4ULL,
+       /* Set address */
        0x80020515F2100000ULL, 0x80020515F21000E0ULL,
        /* Write data */
        0x80020515F2100004ULL, 0x80020515F21000E4ULL,
@@ -301,6 +305,8 @@ static unsigned int bimodal = 0;
 #ifndef CONFIG_S2IO_NAPI
 static unsigned int indicate_max_pkts;
 #endif
+/* Frequency of Rx desc syncs expressed as power of 2 */
+static unsigned int rxsync_frequency = 3;
 
 /*
  * S2IO device table.
@@ -348,7 +354,7 @@ static int init_shared_mem(struct s2io_nic *nic)
        int lst_size, lst_per_page;
        struct net_device *dev = nic->dev;
 #ifdef CONFIG_2BUFF_MODE
-       u64 tmp;
+       unsigned long tmp;
        buffAdd_t *ba;
 #endif
 
@@ -365,10 +371,9 @@ static int init_shared_mem(struct s2io_nic *nic)
                size += config->tx_cfg[i].fifo_len;
        }
        if (size > MAX_AVAILABLE_TXDS) {
-               DBG_PRINT(ERR_DBG, "%s: Total number of Tx FIFOs ",
-                         dev->name);
-               DBG_PRINT(ERR_DBG, "exceeds the maximum value ");
-               DBG_PRINT(ERR_DBG, "that can be used\n");
+               DBG_PRINT(ERR_DBG, "%s: Requested TxDs too high, ",
+                         __FUNCTION__);
+               DBG_PRINT(ERR_DBG, "Requested: %d, max supported: 8192\n", size);
                return FAILURE;
        }
 
@@ -399,7 +404,7 @@ static int init_shared_mem(struct s2io_nic *nic)
                    config->tx_cfg[i].fifo_len - 1;
                mac_control->fifos[i].fifo_no = i;
                mac_control->fifos[i].nic = nic;
-               mac_control->fifos[i].max_txds = MAX_SKB_FRAGS;
+               mac_control->fifos[i].max_txds = MAX_SKB_FRAGS + 1;
 
                for (j = 0; j < page_num; j++) {
                        int k = 0;
@@ -413,6 +418,26 @@ static int init_shared_mem(struct s2io_nic *nic)
                                DBG_PRINT(ERR_DBG, "failed for TxDL\n");
                                return -ENOMEM;
                        }
+                       /* If we got a zero DMA address(can happen on
+                        * certain platforms like PPC), reallocate.
+                        * Store virtual address of page we don't want,
+                        * to be freed later.
+                        */
+                       if (!tmp_p) {
+                               mac_control->zerodma_virt_addr = tmp_v;
+                               DBG_PRINT(INIT_DBG, 
+                               "%s: Zero DMA address for TxDL. ", dev->name);
+                               DBG_PRINT(INIT_DBG, 
+                               "Virtual address %llx\n", (u64)tmp_v);
+                               tmp_v = pci_alloc_consistent(nic->pdev,
+                                                    PAGE_SIZE, &tmp_p);
+                               if (!tmp_v) {
+                                       DBG_PRINT(ERR_DBG,
+                                         "pci_alloc_consistent ");
+                                       DBG_PRINT(ERR_DBG, "failed for TxDL\n");
+                                       return -ENOMEM;
+                               }
+                       }
                        while (k < lst_per_page) {
                                int l = (j * lst_per_page) + k;
                                if (l == config->tx_cfg[i].fifo_len)
@@ -537,18 +562,18 @@ static int init_shared_mem(struct s2io_nic *nic)
                                    (BUF0_LEN + ALIGN_SIZE, GFP_KERNEL);
                                if (!ba->ba_0_org)
                                        return -ENOMEM;
-                               tmp = (u64) ba->ba_0_org;
+                               tmp = (unsigned long) ba->ba_0_org;
                                tmp += ALIGN_SIZE;
-                               tmp &= ~((u64) ALIGN_SIZE);
+                               tmp &= ~((unsigned long) ALIGN_SIZE);
                                ba->ba_0 = (void *) tmp;
 
                                ba->ba_1_org = (void *) kmalloc
                                    (BUF1_LEN + ALIGN_SIZE, GFP_KERNEL);
                                if (!ba->ba_1_org)
                                        return -ENOMEM;
-                               tmp = (u64) ba->ba_1_org;
+                               tmp = (unsigned long) ba->ba_1_org;
                                tmp += ALIGN_SIZE;
-                               tmp &= ~((u64) ALIGN_SIZE);
+                               tmp &= ~((unsigned long) ALIGN_SIZE);
                                ba->ba_1 = (void *) tmp;
                                k++;
                        }
@@ -595,7 +620,7 @@ static void free_shared_mem(struct s2io_nic *nic)
        mac_info_t *mac_control;
        struct config_param *config;
        int lst_size, lst_per_page;
-
+       struct net_device *dev = nic->dev;
 
        if (!nic)
                return;
@@ -611,8 +636,10 @@ static void free_shared_mem(struct s2io_nic *nic)
                                                lst_per_page);
                for (j = 0; j < page_num; j++) {
                        int mem_blks = (j * lst_per_page);
+                       if (!mac_control->fifos[i].list_info)
+                               return; 
                        if (!mac_control->fifos[i].list_info[mem_blks].
-                           list_virt_addr)
+                                list_virt_addr)
                                break;
                        pci_free_consistent(nic->pdev, PAGE_SIZE,
                                            mac_control->fifos[i].
@@ -622,6 +649,18 @@ static void free_shared_mem(struct s2io_nic *nic)
                                            list_info[mem_blks].
                                            list_phy_addr);
                }
+               /* If we got a zero DMA address during allocation,
+                * free the page now
+                */
+               if (mac_control->zerodma_virt_addr) {
+                       pci_free_consistent(nic->pdev, PAGE_SIZE,
+                                           mac_control->zerodma_virt_addr,
+                                           (dma_addr_t)0);
+                       DBG_PRINT(INIT_DBG, 
+                       "%s: Freeing TxDL with zero DMA addr. ", dev->name);
+                       DBG_PRINT(INIT_DBG, "Virtual address %llx\n",
+                       (u64)(mac_control->zerodma_virt_addr));
+               }
                kfree(mac_control->fifos[i].list_info);
        }
 
@@ -680,7 +719,7 @@ static void free_shared_mem(struct s2io_nic *nic)
 
 static int s2io_verify_pci_mode(nic_t *nic)
 {
-       XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+       XENA_dev_config_t __iomem *bar0 = nic->bar0;
        register u64 val64 = 0;
        int     mode;
 
@@ -698,7 +737,7 @@ static int s2io_verify_pci_mode(nic_t *nic)
  */
 static int s2io_print_pci_mode(nic_t *nic)
 {
-       XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+       XENA_dev_config_t __iomem *bar0 = nic->bar0;
        register u64 val64 = 0;
        int     mode;
        struct config_param *config = &nic->config;
@@ -837,7 +876,7 @@ static int init_nic(struct s2io_nic *nic)
         */
        if (nic->device_type & XFRAME_II_DEVICE) {
                while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) {
-                       SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt],
+                       SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt],
                                          &bar0->dtx_control, UF);
                        if (dtx_cnt & 0x1)
                                msleep(1); /* Necessary!! */
@@ -1397,7 +1436,7 @@ static int init_nic(struct s2io_nic *nic)
        writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);
 
        /* Disable RMAC PAD STRIPPING */
-       add = (void *) &bar0->mac_cfg;
+       add = &bar0->mac_cfg;
        val64 = readq(&bar0->mac_cfg);
        val64 &= ~(MAC_CFG_RMAC_STRIP_PAD);
        writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
@@ -1456,8 +1495,28 @@ static int init_nic(struct s2io_nic *nic)
                writeq(val64, &bar0->wreq_split_mask);
        }
 
+       /* Setting Link stability period to 64 ms */ 
+       if (nic->device_type == XFRAME_II_DEVICE) {
+               val64 = MISC_LINK_STABILITY_PRD(3);
+               writeq(val64, &bar0->misc_control);
+       }
+
        return SUCCESS;
 }
+#define LINK_UP_DOWN_INTERRUPT         1
+#define MAC_RMAC_ERR_TIMER             2
+
+#if defined(CONFIG_MSI_MODE) || defined(CONFIG_MSIX_MODE)
+#define s2io_link_fault_indication(x) MAC_RMAC_ERR_TIMER
+#else
+int s2io_link_fault_indication(nic_t *nic)
+{
+       if (nic->device_type == XFRAME_II_DEVICE)
+               return LINK_UP_DOWN_INTERRUPT;
+       else
+               return MAC_RMAC_ERR_TIMER;
+}
+#endif
 
 /**
  *  en_dis_able_nic_intrs - Enable or Disable the interrupts
@@ -1485,11 +1544,22 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                        temp64 &= ~((u64) val64);
                        writeq(temp64, &bar0->general_int_mask);
                        /*
-                        * Disabled all PCIX, Flash, MDIO, IIC and GPIO
+                        * If Hercules adapter enable GPIO otherwise
+                        * disabled all PCIX, Flash, MDIO, IIC and GPIO
                         * interrupts for now.
                         * TODO
                         */
-                       writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
+                       if (s2io_link_fault_indication(nic) ==
+                                       LINK_UP_DOWN_INTERRUPT ) {
+                               temp64 = readq(&bar0->pic_int_mask);
+                               temp64 &= ~((u64) PIC_INT_GPIO);
+                               writeq(temp64, &bar0->pic_int_mask);
+                               temp64 = readq(&bar0->gpio_int_mask);
+                               temp64 &= ~((u64) GPIO_INT_MASK_LINK_UP);
+                               writeq(temp64, &bar0->gpio_int_mask);
+                       } else {
+                               writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
+                       }
                        /*
                         * No MSI Support is available presently, so TTI and
                         * RTI interrupts are also disabled.
@@ -1580,17 +1650,8 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                        writeq(temp64, &bar0->general_int_mask);
                        /*
                         * All MAC block error interrupts are disabled for now
-                        * except the link status change interrupt.
                         * TODO
                         */
-                       val64 = MAC_INT_STATUS_RMAC_INT;
-                       temp64 = readq(&bar0->mac_int_mask);
-                       temp64 &= ~((u64) val64);
-                       writeq(temp64, &bar0->mac_int_mask);
-
-                       val64 = readq(&bar0->mac_rmac_err_mask);
-                       val64 &= ~((u64) RMAC_LINK_STATE_CHANGE_INT);
-                       writeq(val64, &bar0->mac_rmac_err_mask);
                } else if (flag == DISABLE_INTRS) {
                        /*
                         * Disable MAC Intrs in the general intr mask register
@@ -1879,8 +1940,10 @@ static int start_nic(struct s2io_nic *nic)
        }
 
        /*  Enable select interrupts */
-       interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR | TX_MAC_INTR |
-           RX_MAC_INTR | MC_INTR;
+       interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
+       interruptible |= TX_PIC_INTR | RX_PIC_INTR;
+       interruptible |= TX_MAC_INTR | RX_MAC_INTR;
+
        en_dis_able_nic_intrs(nic, interruptible, ENABLE_INTRS);
 
        /*
@@ -1904,7 +1967,7 @@ static int start_nic(struct s2io_nic *nic)
                val64 |= 0x0000800000000000ULL;
                writeq(val64, &bar0->gpio_control);
                val64 = 0x0411040400000000ULL;
-               writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700));
+               writeq(val64, (void __iomem *)bar0 + 0x2700);
        }
 
        /*
@@ -2004,8 +2067,9 @@ static void stop_nic(struct s2io_nic *nic)
        config = &nic->config;
 
        /*  Disable all interrupts */
-       interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR | TX_MAC_INTR |
-           RX_MAC_INTR | MC_INTR;
+       interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR;
+       interruptible |= TX_PIC_INTR | RX_PIC_INTR;
+       interruptible |= TX_MAC_INTR | RX_MAC_INTR;
        en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS);
 
        /*  Disable PRCs */
@@ -2058,6 +2122,7 @@ int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
 #ifndef CONFIG_S2IO_NAPI
        unsigned long flags;
 #endif
+       RxD_t *first_rxdp = NULL;
 
        mac_control = &nic->mac_control;
        config = &nic->config;
@@ -2177,6 +2242,10 @@ int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                if (!skb) {
                        DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name);
                        DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n");
+                       if (first_rxdp) {
+                               wmb();
+                               first_rxdp->Control_1 |= RXD_OWN_XENA;
+                       }
                        return -ENOMEM;
                }
 #ifndef        CONFIG_2BUFF_MODE
@@ -2187,7 +2256,8 @@ int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                rxdp->Control_2 &= (~MASK_BUFFER0_SIZE);
                rxdp->Control_2 |= SET_BUFFER0_SIZE(size);
                rxdp->Host_Control = (unsigned long) (skb);
-               rxdp->Control_1 |= RXD_OWN_XENA;
+               if (alloc_tab & ((1 << rxsync_frequency) - 1))
+                       rxdp->Control_1 |= RXD_OWN_XENA;
                off++;
                off %= (MAX_RXDS_PER_BLOCK + 1);
                mac_control->rings[ring_no].rx_curr_put_info.offset = off;
@@ -2214,17 +2284,34 @@ int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                rxdp->Control_2 |= SET_BUFFER1_SIZE(1); /* dummy. */
                rxdp->Control_2 |= BIT(0);      /* Set Buffer_Empty bit. */
                rxdp->Host_Control = (u64) ((unsigned long) (skb));
-               rxdp->Control_1 |= RXD_OWN_XENA;
+               if (alloc_tab & ((1 << rxsync_frequency) - 1))
+                       rxdp->Control_1 |= RXD_OWN_XENA;
                off++;
                mac_control->rings[ring_no].rx_curr_put_info.offset = off;
 #endif
                rxdp->Control_2 |= SET_RXD_MARKER;
 
+               if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
+                       if (first_rxdp) {
+                               wmb();
+                               first_rxdp->Control_1 |= RXD_OWN_XENA;
+                       }
+                       first_rxdp = rxdp;
+               }
                atomic_inc(&nic->rx_bufs_left[ring_no]);
                alloc_tab++;
        }
 
       end:
+       /* Transfer ownership of first descriptor to adapter just before
+        * exiting. Before that, use memory barrier so that ownership
+        * and other fields are seen by adapter correctly.
+        */
+       if (first_rxdp) {
+               wmb();
+               first_rxdp->Control_1 |= RXD_OWN_XENA;
+       }
+
        return SUCCESS;
 }
 
@@ -2341,7 +2428,7 @@ static int s2io_poll(struct net_device *dev, int *budget)
        int pkt_cnt = 0, org_pkts_to_process;
        mac_info_t *mac_control;
        struct config_param *config;
-       XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0;
+       XENA_dev_config_t __iomem *bar0 = nic->bar0;
        u64 val64;
        int i;
 
@@ -2425,9 +2512,10 @@ static void rx_intr_handler(ring_info_t *ring_data)
 #endif
        spin_lock(&nic->rx_lock);
        if (atomic_read(&nic->card_state) == CARD_DOWN) {
-               DBG_PRINT(ERR_DBG, "%s: %s going down for reset\n",
+               DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
                          __FUNCTION__, dev->name);
                spin_unlock(&nic->rx_lock);
+               return;
        }
 
        get_info = ring_data->rx_curr_get_info;
@@ -2542,8 +2630,14 @@ static void tx_intr_handler(fifo_info_t *fifo_data)
                if (txdlp->Control_1 & TXD_T_CODE) {
                        unsigned long long err;
                        err = txdlp->Control_1 & TXD_T_CODE;
-                       DBG_PRINT(ERR_DBG, "***TxD error %llx\n",
-                                 err);
+                       if ((err >> 48) == 0xA) {
+                               DBG_PRINT(TX_DBG, "TxD returned due \
+                                               to loss of link\n");
+                       }
+                       else {
+                               DBG_PRINT(ERR_DBG, "***TxD error \
+                                               %llx\n", err);
+                       }
                }
 
                skb = (struct sk_buff *) ((unsigned long)
@@ -2569,6 +2663,8 @@ static void tx_intr_handler(fifo_info_t *fifo_data)
                        for (j = 0; j < frg_cnt; j++, txdlp++) {
                                skb_frag_t *frag =
                                    &skb_shinfo(skb)->frags[j];
+                               if (!txdlp->Buffer_Pointer)
+                                       break;
                                pci_unmap_page(nic->pdev,
                                               (dma_addr_t)
                                               txdlp->
@@ -2618,10 +2714,12 @@ static void alarm_intr_handler(struct s2io_nic *nic)
        register u64 val64 = 0, err_reg = 0;
 
        /* Handling link status change error Intr */
-       err_reg = readq(&bar0->mac_rmac_err_reg);
-       writeq(err_reg, &bar0->mac_rmac_err_reg);
-       if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
-               schedule_work(&nic->set_link_task);
+       if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
+               err_reg = readq(&bar0->mac_rmac_err_reg);
+               writeq(err_reg, &bar0->mac_rmac_err_reg);
+               if (err_reg & RMAC_LINK_STATE_CHANGE_INT) {
+                       schedule_work(&nic->set_link_task);
+               }
        }
 
        /* Handling Ecc errors */
@@ -2631,11 +2729,17 @@ static void alarm_intr_handler(struct s2io_nic *nic)
                if (val64 & MC_ERR_REG_ECC_ALL_DBL) {
                        nic->mac_control.stats_info->sw_stat.
                                double_ecc_errs++;
-                       DBG_PRINT(ERR_DBG, "%s: Device indicates ",
+                       DBG_PRINT(INIT_DBG, "%s: Device indicates ",
                                  dev->name);
-                       DBG_PRINT(ERR_DBG, "double ECC error!!\n");
-                       netif_stop_queue(dev);
-                       schedule_work(&nic->rst_timer_task);
+                       DBG_PRINT(INIT_DBG, "double ECC error!!\n");
+                       if (nic->device_type != XFRAME_II_DEVICE) {
+                               /* Reset XframeI only if critical error */
+                               if (val64 & (MC_ERR_REG_MIRI_ECC_DB_ERR_0 |
+                                            MC_ERR_REG_MIRI_ECC_DB_ERR_1)) {
+                                       netif_stop_queue(dev);
+                                       schedule_work(&nic->rst_timer_task);
+                               }
+                       }
                } else {
                        nic->mac_control.stats_info->sw_stat.
                                single_ecc_errs++;
@@ -2646,7 +2750,8 @@ static void alarm_intr_handler(struct s2io_nic *nic)
        val64 = readq(&bar0->serr_source);
        if (val64 & SERR_SOURCE_ANY) {
                DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name);
-               DBG_PRINT(ERR_DBG, "serious error!!\n");
+               DBG_PRINT(ERR_DBG, "serious error %llx!!\n", 
+                         (unsigned long long)val64);
                netif_stop_queue(dev);
                schedule_work(&nic->rst_timer_task);
        }
@@ -2717,6 +2822,9 @@ void s2io_reset(nic_t * sp)
        u64 val64;
        u16 subid, pci_cmd;
 
+       /* Back up  the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
+       pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
+
        val64 = SW_RESET_ALL;
        writeq(val64, &bar0->sw_reset);
 
@@ -2734,12 +2842,10 @@ void s2io_reset(nic_t * sp)
         */
        msleep(250);
 
-       if (!(sp->device_type & XFRAME_II_DEVICE)) {
-       /* Restore the PCI state saved during initializarion. */
-               pci_restore_state(sp->pdev);
-       } else {
-               pci_set_master(sp->pdev);
-       }
+       /* Restore the PCI state saved during initialization. */
+       pci_restore_state(sp->pdev);
+       pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
+                                    pci_cmd);
        s2io_init_pci(sp);
 
        msleep(250);
@@ -2748,16 +2854,16 @@ void s2io_reset(nic_t * sp)
        s2io_set_swapper(sp);
 
        /* Clear certain PCI/PCI-X fields after reset */
-       pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd);
-       pci_cmd &= 0x7FFF; /* Clear parity err detect bit */
-       pci_write_config_word(sp->pdev, PCI_COMMAND, pci_cmd);
+       if (sp->device_type == XFRAME_II_DEVICE) {
+               /* Clear parity err detect bit */
+               pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000);
 
-       val64 = readq(&bar0->txpic_int_reg);
-       val64 &= ~BIT(62); /* Clearing PCI_STATUS error reflected here */
-       writeq(val64, &bar0->txpic_int_reg);
+               /* Clearing PCIX Ecc status register */
+               pci_write_config_dword(sp->pdev, 0x68, 0x7C);
 
-       /* Clearing PCIX Ecc status register */
-       pci_write_config_dword(sp->pdev, 0x68, 0);
+               /* Clearing PCI_STATUS error reflected here */
+               writeq(BIT(62), &bar0->txpic_int_reg);
+       }
 
        /* Reset device statistics maintained by OS */
        memset(&sp->stats, 0, sizeof (struct net_device_stats));
@@ -2770,7 +2876,7 @@ void s2io_reset(nic_t * sp)
                val64 |= 0x0000800000000000ULL;
                writeq(val64, &bar0->gpio_control);
                val64 = 0x0411040400000000ULL;
-               writeq(val64, (void __iomem *) ((u8 *) bar0 + 0x2700));
+               writeq(val64, (void __iomem *)bar0 + 0x2700);
        }
 
        /*
@@ -2947,7 +3053,7 @@ int s2io_open(struct net_device *dev)
         * Nic is initialized
         */
        netif_carrier_off(dev);
-       sp->last_link_state = 0; /* Unkown link state */
+       sp->last_link_state = 0;
 
        /* Initialize H/W and enable interrupts */
        if (s2io_card_up(sp)) {
@@ -3069,12 +3175,21 @@ int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
        /* Avoid "put" pointer going beyond "get" pointer */
        if (txdp->Host_Control || (((put_off + 1) % queue_len) == get_off)) {
-               DBG_PRINT(ERR_DBG, "Error in xmit, No free TXDs.\n");
+               DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n");
                netif_stop_queue(dev);
                dev_kfree_skb(skb);
                spin_unlock_irqrestore(&sp->tx_lock, flags);
                return 0;
        }
+
+       /* A buffer with no data will be dropped */
+       if (!skb->len) {
+               DBG_PRINT(TX_DBG, "%s:Buffer has no data..\n", dev->name);
+               dev_kfree_skb(skb);
+               spin_unlock_irqrestore(&sp->tx_lock, flags);
+               return 0;
+       }
+
 #ifdef NETIF_F_TSO
        mss = skb_shinfo(skb)->tso_size;
        if (mss) {
@@ -3109,6 +3224,9 @@ int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        /* For fragmented SKB. */
        for (i = 0; i < frg_cnt; i++) {
                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+               /* A '0' length fragment will be ignored */
+               if (!frag->size)
+                       continue;
                txdp++;
                txdp->Buffer_Pointer = (u64) pci_map_page
                    (sp->pdev, frag->page, frag->page_offset,
@@ -3121,8 +3239,6 @@ int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        val64 = mac_control->fifos[queue].list_info[put_off].list_phy_addr;
        writeq(val64, &tx_fifo->TxDL_Pointer);
 
-       wmb();
-
        val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST |
                 TX_FIFO_LAST_LIST);
 
@@ -3132,6 +3248,8 @@ int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 #endif
        writeq(val64, &tx_fifo->List_Control);
 
+       mmiowb();
+
        put_off++;
        put_off %= mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
        mac_control->fifos[queue].tx_curr_put_info.offset = put_off;
@@ -3159,6 +3277,53 @@ s2io_alarm_handle(unsigned long data)
        mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
 }
 
+static void s2io_txpic_intr_handle(nic_t *sp)
+{
+       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       u64 val64;
+
+       val64 = readq(&bar0->pic_int_status);
+       if (val64 & PIC_INT_GPIO) {
+               val64 = readq(&bar0->gpio_int_reg);
+               if ((val64 & GPIO_INT_REG_LINK_DOWN) &&
+                   (val64 & GPIO_INT_REG_LINK_UP)) {
+                       val64 |=  GPIO_INT_REG_LINK_DOWN;
+                       val64 |= GPIO_INT_REG_LINK_UP;
+                       writeq(val64, &bar0->gpio_int_reg);
+                       goto masking;
+               }
+
+               if (((sp->last_link_state == LINK_UP) &&
+                       (val64 & GPIO_INT_REG_LINK_DOWN)) ||
+               ((sp->last_link_state == LINK_DOWN) &&
+               (val64 & GPIO_INT_REG_LINK_UP))) {
+                       val64 = readq(&bar0->gpio_int_mask);
+                       val64 |=  GPIO_INT_MASK_LINK_DOWN;
+                       val64 |= GPIO_INT_MASK_LINK_UP;
+                       writeq(val64, &bar0->gpio_int_mask);
+                       s2io_set_link((unsigned long)sp);
+               }
+masking:
+               if (sp->last_link_state == LINK_UP) {
+                       /*enable down interrupt */
+                       val64 = readq(&bar0->gpio_int_mask);
+                       /* unmasks link down intr */
+                       val64 &=  ~GPIO_INT_MASK_LINK_DOWN;
+                       /* masks link up intr */
+                       val64 |= GPIO_INT_MASK_LINK_UP;
+                       writeq(val64, &bar0->gpio_int_mask);
+               } else {
+                       /*enable UP Interrupt */
+                       val64 = readq(&bar0->gpio_int_mask);
+                       /* unmasks link up interrupt */
+                       val64 &= ~GPIO_INT_MASK_LINK_UP;
+                       /* masks link down interrupt */
+                       val64 |=  GPIO_INT_MASK_LINK_DOWN;
+                       writeq(val64, &bar0->gpio_int_mask);
+               }
+       }
+}
+
 /**
  *  s2io_isr - ISR handler of the device .
  *  @irq: the irq of the device.
@@ -3241,6 +3406,8 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
                        tx_intr_handler(&mac_control->fifos[i]);
        }
 
+       if (reason & GEN_INTR_TXPIC)
+               s2io_txpic_intr_handle(sp);
        /*
         * If the Rx buffer count is below the panic threshold then
         * reallocate the buffers from the interrupt handler itself,
@@ -3406,7 +3573,7 @@ static void s2io_set_multicast(struct net_device *dev)
 
                val64 = readq(&bar0->mac_cfg);
                sp->promisc_flg = 1;
-               DBG_PRINT(ERR_DBG, "%s: entered promiscuous mode\n",
+               DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n",
                          dev->name);
        } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) {
                /*  Remove the NIC from promiscuous mode */
@@ -3421,7 +3588,7 @@ static void s2io_set_multicast(struct net_device *dev)
 
                val64 = readq(&bar0->mac_cfg);
                sp->promisc_flg = 0;
-               DBG_PRINT(ERR_DBG, "%s: left promiscuous mode\n",
+               DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n",
                          dev->name);
        }
 
@@ -4644,11 +4811,13 @@ static void s2io_set_link(unsigned long data)
        }
 
        subid = nic->pdev->subsystem_device;
-       /*
-        * Allow a small delay for the NICs self initiated
-        * cleanup to complete.
-        */
-       msleep(100);
+       if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) {
+               /*
+                * Allow a small delay for the NICs self initiated
+                * cleanup to complete.
+                */
+               msleep(100);
+       }
 
        val64 = readq(&bar0->adapter_status);
        if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
@@ -4666,13 +4835,16 @@ static void s2io_set_link(unsigned long data)
                                val64 |= ADAPTER_LED_ON;
                                writeq(val64, &bar0->adapter_control);
                        }
-                       val64 = readq(&bar0->adapter_status);
-                       if (!LINK_IS_UP(val64)) {
-                               DBG_PRINT(ERR_DBG, "%s:", dev->name);
-                               DBG_PRINT(ERR_DBG, " Link down");
-                               DBG_PRINT(ERR_DBG, "after ");
-                               DBG_PRINT(ERR_DBG, "enabling ");
-                               DBG_PRINT(ERR_DBG, "device \n");
+                       if (s2io_link_fault_indication(nic) ==
+                                               MAC_RMAC_ERR_TIMER) {
+                               val64 = readq(&bar0->adapter_status);
+                               if (!LINK_IS_UP(val64)) {
+                                       DBG_PRINT(ERR_DBG, "%s:", dev->name);
+                                       DBG_PRINT(ERR_DBG, " Link down");
+                                       DBG_PRINT(ERR_DBG, "after ");
+                                       DBG_PRINT(ERR_DBG, "enabling ");
+                                       DBG_PRINT(ERR_DBG, "device \n");
+                               }
                        }
                        if (nic->device_enabled_once == FALSE) {
                                nic->device_enabled_once = TRUE;
@@ -5071,6 +5243,7 @@ module_param(bimodal, bool, 0);
 #ifndef CONFIG_S2IO_NAPI
 module_param(indicate_max_pkts, int, 0);
 #endif
+module_param(rxsync_frequency, int, 0);
 
 /**
  *  s2io_init_nic - Initialization of the adapter .
@@ -5176,7 +5349,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        config = &sp->config;
 
        /* Tx side parameters. */
-       tx_fifo_len[0] = DEFAULT_FIFO_LEN;      /* Default value. */
+       if (tx_fifo_len[0] == 0)
+               tx_fifo_len[0] = DEFAULT_FIFO_LEN; /* Default value. */
        config->tx_fifo_num = tx_fifo_num;
        for (i = 0; i < MAX_TX_FIFOS; i++) {
                config->tx_cfg[i].fifo_len = tx_fifo_len[i];
@@ -5196,10 +5370,11 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
                        break;
                }
        }
-       config->max_txds = MAX_SKB_FRAGS;
+       config->max_txds = MAX_SKB_FRAGS + 1;
 
        /* Rx side parameters. */
-       rx_ring_sz[0] = SMALL_BLK_CNT;  /* Default value. */
+       if (rx_ring_sz[0] == 0)
+               rx_ring_sz[0] = SMALL_BLK_CNT; /* Default value. */
        config->rx_ring_num = rx_ring_num;
        for (i = 0; i < MAX_RX_RINGS; i++) {
                config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
@@ -5229,7 +5404,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        /*  initialize the shared memory used by the NIC and the host */
        if (init_shared_mem(sp)) {
                DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
-                         dev->name);
+                         __FUNCTION__);
                ret = -ENOMEM;
                goto mem_alloc_failed;
        }
@@ -5297,9 +5472,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        INIT_WORK(&sp->set_link_task,
                  (void (*)(void *)) s2io_set_link, sp);
 
-       if (!(sp->device_type & XFRAME_II_DEVICE)) {
-               pci_save_state(sp->pdev);
-       }
+       pci_save_state(sp->pdev);
 
        /* Setting swapper control on the NIC, for proper reset operation */
        if (s2io_set_swapper(sp)) {
@@ -5397,9 +5570,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        if (sp->device_type & XFRAME_II_DEVICE) {
                DBG_PRINT(ERR_DBG, "%s: Neterion Xframe II 10GbE adapter ",
                          dev->name);
-               DBG_PRINT(ERR_DBG, "(rev %d), Driver %s\n",
+               DBG_PRINT(ERR_DBG, "(rev %d), %s",
                                get_xena_rev_id(sp->pdev),
                                s2io_driver_version);
+#ifdef CONFIG_2BUFF_MODE
+               DBG_PRINT(ERR_DBG, ", Buffer mode %d",2);
+#endif
+
+               DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
                DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
                          sp->def_mac_addr[0].mac_addr[0],
                          sp->def_mac_addr[0].mac_addr[1],
@@ -5407,7 +5585,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
                          sp->def_mac_addr[0].mac_addr[3],
                          sp->def_mac_addr[0].mac_addr[4],
                          sp->def_mac_addr[0].mac_addr[5]);
-               int mode = s2io_print_pci_mode(sp);
+               mode = s2io_print_pci_mode(sp);
                if (mode < 0) {
                        DBG_PRINT(ERR_DBG, " Unsupported PCI bus mode ");
                        ret = -EBADSLT;
@@ -5416,9 +5594,13 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        } else {
                DBG_PRINT(ERR_DBG, "%s: Neterion Xframe I 10GbE adapter ",
                          dev->name);
-               DBG_PRINT(ERR_DBG, "(rev %d), Driver %s\n",
+               DBG_PRINT(ERR_DBG, "(rev %d), %s",
                                        get_xena_rev_id(sp->pdev),
                                        s2io_driver_version);
+#ifdef CONFIG_2BUFF_MODE
+               DBG_PRINT(ERR_DBG, ", Buffer mode %d",2);
+#endif
+               DBG_PRINT(ERR_DBG, "\nCopyright(c) 2002-2005 Neterion Inc.\n");
                DBG_PRINT(ERR_DBG, "MAC ADDR: %02x:%02x:%02x:%02x:%02x:%02x\n",
                          sp->def_mac_addr[0].mac_addr[0],
                          sp->def_mac_addr[0].mac_addr[1],