Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
authorDavid S. Miller <davem@davemloft.net>
Fri, 14 Aug 2009 02:59:44 +0000 (19:59 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 14 Aug 2009 02:59:44 +0000 (19:59 -0700)
Conflicts:
drivers/net/netxen/netxen_nic_main.c

1  2 
drivers/net/8139cp.c
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_init.c
drivers/net/netxen/netxen_nic_main.c

diff --combined drivers/net/8139cp.c
@@@ -515,7 -515,7 +515,7 @@@ rx_status_loop
                dma_addr_t mapping;
                struct sk_buff *skb, *new_skb;
                struct cp_desc *desc;
-               unsigned buflen;
+               const unsigned buflen = cp->rx_buf_sz;
  
                skb = cp->rx_skb[rx_tail];
                BUG_ON(!skb);
                        pr_debug("%s: rx slot %d status 0x%x len %d\n",
                               dev->name, rx_tail, status, len);
  
-               buflen = cp->rx_buf_sz + NET_IP_ALIGN;
-               new_skb = netdev_alloc_skb(dev, buflen);
+               new_skb = netdev_alloc_skb(dev, buflen + NET_IP_ALIGN);
                if (!new_skb) {
                        dev->stats.rx_dropped++;
                        goto rx_next;
@@@ -891,7 -890,7 +890,7 @@@ static int cp_start_xmit (struct sk_buf
        cpw8(TxPoll, NormalTxPoll);
        dev->trans_start = jiffies;
  
 -      return 0;
 +      return NETDEV_TX_OK;
  }
  
  /* Set or clear the multicast filter for this adaptor.
@@@ -1440,7 -1440,7 +1440,7 @@@ static int ixgbe_setup_desc_rings(struc
                goto err_nomem;
        }
  
 -      tx_ring->size = tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc);
 +      tx_ring->size = tx_ring->count * sizeof(union ixgbe_adv_tx_desc);
        tx_ring->size = ALIGN(tx_ring->size, 4096);
        if (!(tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size,
                                                   &tx_ring->dma))) {
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDBAH(0),
                        ((u64) tx_ring->dma >> 32));
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDLEN(0),
 -                      tx_ring->count * sizeof(struct ixgbe_legacy_tx_desc));
 +                      tx_ring->count * sizeof(union ixgbe_adv_tx_desc));
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDH(0), 0);
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_TDT(0), 0);
  
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_TXDCTL(0), reg_data);
  
        for (i = 0; i < tx_ring->count; i++) {
 -              struct ixgbe_legacy_tx_desc *desc = IXGBE_TX_DESC(*tx_ring, i);
 +              union ixgbe_adv_tx_desc *desc = IXGBE_TX_DESC_ADV(*tx_ring, i);
                struct sk_buff *skb;
                unsigned int size = 1024;
  
                tx_ring->tx_buffer_info[i].length = skb->len;
                tx_ring->tx_buffer_info[i].dma =
                        pci_map_single(pdev, skb->data, skb->len,
 -                                      PCI_DMA_TODEVICE);
 -              desc->buffer_addr = cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
 -              desc->lower.data = cpu_to_le32(skb->len);
 -              desc->lower.data |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
 -                                              IXGBE_TXD_CMD_IFCS |
 -                                              IXGBE_TXD_CMD_RS);
 -              desc->upper.data = 0;
 +                                     PCI_DMA_TODEVICE);
 +              desc->read.buffer_addr =
 +                                  cpu_to_le64(tx_ring->tx_buffer_info[i].dma);
 +              desc->read.cmd_type_len = cpu_to_le32(skb->len);
 +              desc->read.cmd_type_len |= cpu_to_le32(IXGBE_TXD_CMD_EOP |
 +                                                     IXGBE_TXD_CMD_IFCS |
 +                                                     IXGBE_TXD_CMD_RS);
 +              desc->read.olinfo_status = 0;
 +              if (adapter->hw.mac.type == ixgbe_mac_82599EB)
 +                      desc->read.olinfo_status |=
 +                                      (skb->len << IXGBE_ADVTXD_PAYLEN_SHIFT);
 +
        }
  
        /* Setup Rx Descriptor ring and Rx buffers */
                goto err_nomem;
        }
  
 -      rx_ring->size = rx_ring->count * sizeof(struct ixgbe_legacy_rx_desc);
 +      rx_ring->size = rx_ring->count * sizeof(union ixgbe_adv_rx_desc);
        rx_ring->size = ALIGN(rx_ring->size, 4096);
        if (!(rx_ring->desc = pci_alloc_consistent(pdev, rx_ring->size,
                                                   &rx_ring->dma))) {
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXCTRL, rctl);
  
        for (i = 0; i < rx_ring->count; i++) {
 -              struct ixgbe_legacy_rx_desc *rx_desc =
 -                                      IXGBE_RX_DESC(*rx_ring, i);
 +              union ixgbe_adv_rx_desc *rx_desc =
 +                                               IXGBE_RX_DESC_ADV(*rx_ring, i);
                struct sk_buff *skb;
  
                skb = alloc_skb(IXGBE_RXBUFFER_2048 + NET_IP_ALIGN, GFP_KERNEL);
                rx_ring->rx_buffer_info[i].dma =
                        pci_map_single(pdev, skb->data, IXGBE_RXBUFFER_2048,
                                       PCI_DMA_FROMDEVICE);
 -              rx_desc->buffer_addr =
 +              rx_desc->read.pkt_addr =
                                cpu_to_le64(rx_ring->rx_buffer_info[i].dma);
                memset(skb->data, 0x00, skb->len);
        }
@@@ -1953,6 -1948,7 +1953,7 @@@ static int ixgbe_set_coalesce(struct ne
                                struct ethtool_coalesce *ec)
  {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_q_vector *q_vector;
        int i;
  
        if (ec->tx_max_coalesced_frames_irq)
                adapter->itr_setting = 0;
        }
  
-       for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
-               struct ixgbe_q_vector *q_vector = adapter->q_vector[i];
-               if (q_vector->txr_count && !q_vector->rxr_count)
-                       /* tx vector gets half the rate */
-                       q_vector->eitr = (adapter->eitr_param >> 1);
-               else
-                       /* rx only or mixed */
-                       q_vector->eitr = adapter->eitr_param;
+       /* MSI/MSIx Interrupt Mode */
+       if (adapter->flags &
+           (IXGBE_FLAG_MSIX_ENABLED | IXGBE_FLAG_MSI_ENABLED)) {
+               int num_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
+               for (i = 0; i < num_vectors; i++) {
+                       q_vector = adapter->q_vector[i];
+                       if (q_vector->txr_count && !q_vector->rxr_count)
+                               /* tx vector gets half the rate */
+                               q_vector->eitr = (adapter->eitr_param >> 1);
+                       else
+                               /* rx only or mixed */
+                               q_vector->eitr = adapter->eitr_param;
+                       ixgbe_write_eitr(q_vector);
+               }
+       /* Legacy Interrupt Mode */
+       } else {
+               q_vector = adapter->q_vector[0];
+               q_vector->eitr = adapter->eitr_param;
                ixgbe_write_eitr(q_vector);
        }
  
@@@ -57,8 -57,8 +57,8 @@@
  
  #define _NETXEN_NIC_LINUX_MAJOR 4
  #define _NETXEN_NIC_LINUX_MINOR 0
 -#define _NETXEN_NIC_LINUX_SUBVERSION 30
 -#define NETXEN_NIC_LINUX_VERSIONID  "4.0.30"
 +#define _NETXEN_NIC_LINUX_SUBVERSION 41
 +#define NETXEN_NIC_LINUX_VERSIONID  "4.0.41"
  
  #define NETXEN_VERSION_CODE(a, b, c)  (((a) << 24) + ((b) << 16) + (c))
  #define _major(v)     (((v) >> 24) & 0xff)
  #define NX_ETHERMTU                    1500
  #define NX_MAX_ETHERHDR                32 /* This contains some padding */
  
 -#define NX_RX_NORMAL_BUF_MAX_LEN       (NX_MAX_ETHERHDR + NX_ETHERMTU)
 +#define NX_P2_RX_BUF_MAX_LEN           1760
 +#define NX_P3_RX_BUF_MAX_LEN           (NX_MAX_ETHERHDR + NX_ETHERMTU)
  #define NX_P2_RX_JUMBO_BUF_MAX_LEN     (NX_MAX_ETHERHDR + P2_MAX_MTU)
  #define NX_P3_RX_JUMBO_BUF_MAX_LEN     (NX_MAX_ETHERHDR + P3_MAX_MTU)
  #define NX_CT_DEFAULT_RX_BUF_LEN      2048
  
 -#define MAX_RX_BUFFER_LENGTH          1760
 -#define MAX_RX_JUMBO_BUFFER_LENGTH    8062
 -#define MAX_RX_LRO_BUFFER_LENGTH      (8062)
 -#define RX_DMA_MAP_LEN                        (MAX_RX_BUFFER_LENGTH - 2)
 -#define RX_JUMBO_DMA_MAP_LEN  \
 -      (MAX_RX_JUMBO_BUFFER_LENGTH - 2)
 -#define RX_LRO_DMA_MAP_LEN            (MAX_RX_LRO_BUFFER_LENGTH - 2)
 +#define NX_RX_LRO_BUFFER_LENGTH               (8060)
  
  /*
   * Maximum number of ring contexts
  #define RCV_RING_JUMBO        1
  #define RCV_RING_LRO  2
  
 -#define MAX_CMD_DESCRIPTORS           4096
 -#define MAX_RCV_DESCRIPTORS           16384
 -#define MAX_CMD_DESCRIPTORS_HOST      1024
 -#define MAX_RCV_DESCRIPTORS_1G                2048
 -#define MAX_RCV_DESCRIPTORS_10G               4096
 -#define MAX_JUMBO_RCV_DESCRIPTORS     1024
 +#define MIN_CMD_DESCRIPTORS           64
 +#define MIN_RCV_DESCRIPTORS           64
 +#define MIN_JUMBO_DESCRIPTORS         32
 +
 +#define MAX_CMD_DESCRIPTORS           1024
 +#define MAX_RCV_DESCRIPTORS_1G                4096
 +#define MAX_RCV_DESCRIPTORS_10G               8192
 +#define MAX_JUMBO_RCV_DESCRIPTORS_1G  512
 +#define MAX_JUMBO_RCV_DESCRIPTORS_10G 1024
  #define MAX_LRO_RCV_DESCRIPTORS               8
 +
 +#define DEFAULT_RCV_DESCRIPTORS_1G    2048
 +#define DEFAULT_RCV_DESCRIPTORS_10G   4096
 +
  #define NETXEN_CTX_SIGNATURE  0xdee0
  #define NETXEN_CTX_SIGNATURE_V2       0x0002dee0
  #define NETXEN_CTX_RESET      0xbad0
@@@ -304,10 -302,6 +304,10 @@@ struct netxen_ring_ctx 
  #define FLAGS_IPSEC_SA_ADD    0x04
  #define FLAGS_IPSEC_SA_DELETE 0x08
  #define FLAGS_VLAN_TAGGED     0x10
 +#define FLAGS_VLAN_OOB                0x40
 +
 +#define netxen_set_tx_vlan_tci(cmd_desc, v)   \
 +      (cmd_desc)->vlan_TCI = cpu_to_le16(v);
  
  #define netxen_set_cmd_desc_port(cmd_desc, var)       \
        ((cmd_desc)->port_ctxid |= ((var) & 0x0F))
        cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7))
  
  #define netxen_set_tx_frags_len(_desc, _frags, _len) \
 -      (_desc)->num_of_buffers_total_length = \
 +      (_desc)->nfrags__length = \
        cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8))
  
  struct cmd_desc_type0 {
        u8 tcp_hdr_offset;      /* For LSO only */
        u8 ip_hdr_offset;       /* For LSO only */
 -      /* Bit pattern: 0-6 flags, 7-12 opcode, 13-15 unused */
 -      __le16 flags_opcode;
 -      /* Bit pattern: 0-7 total number of segments,
 -         8-31 Total size of the packet */
 -      __le32 num_of_buffers_total_length;
 -      union {
 -              struct {
 -                      __le32 addr_low_part2;
 -                      __le32 addr_high_part2;
 -              };
 -              __le64 addr_buffer2;
 -      };
 +      __le16 flags_opcode;    /* 15:13 unused, 12:7 opcode, 6:0 flags */
 +      __le32 nfrags__length;  /* 31:8 total len, 7:0 frag count */
 +
 +      __le64 addr_buffer2;
  
 -      __le16 reference_handle;        /* changed to u16 to add mss */
 -      __le16 mss;             /* passed by NDIS_PACKET for LSO */
 -      /* Bit pattern 0-3 port, 0-3 ctx id */
 -      u8 port_ctxid;
 +      __le16 reference_handle;
 +      __le16 mss;
 +      u8 port_ctxid;          /* 7:4 ctxid 3:0 port */
        u8 total_hdr_length;    /* LSO only : MAC+IP+TCP Hdr size */
        __le16 conn_id;         /* IPSec offoad only */
  
 -      union {
 -              struct {
 -                      __le32 addr_low_part3;
 -                      __le32 addr_high_part3;
 -              };
 -              __le64 addr_buffer3;
 -      };
 -      union {
 -              struct {
 -                      __le32 addr_low_part1;
 -                      __le32 addr_high_part1;
 -              };
 -              __le64 addr_buffer1;
 -      };
 +      __le64 addr_buffer3;
 +      __le64 addr_buffer1;
  
        __le16 buffer_length[4];
  
 -      union {
 -              struct {
 -                      __le32 addr_low_part4;
 -                      __le32 addr_high_part4;
 -              };
 -              __le64 addr_buffer4;
 -      };
 +      __le64 addr_buffer4;
  
 -      __le64 unused;
 +      __le16 vlan_TCI;
 +      __le16 reserved;
 +      __le32 reserved2;
  
  } __attribute__ ((aligned(64)));
  
@@@ -361,11 -380,9 +361,11 @@@ struct rcv_desc 
  };
  
  /* opcode field in status_desc */
 +#define NETXEN_NIC_SYN_OFFLOAD  0x03
  #define NETXEN_NIC_RXPKT_DESC  0x04
  #define NETXEN_OLD_RXPKT_DESC  0x3f
  #define NETXEN_NIC_RESPONSE_DESC 0x05
 +#define NETXEN_NIC_LRO_DESC   0x12
  
  /* for status field in status_desc */
  #define STATUS_NEED_CKSUM     (1)
  #define netxen_get_sts_opcode(sts_data)       \
        (((sts_data) >> 58) & 0x03F)
  
 +#define netxen_get_lro_sts_refhandle(sts_data)        \
 +      ((sts_data) & 0x0FFFF)
 +#define netxen_get_lro_sts_length(sts_data)   \
 +      (((sts_data) >> 16) & 0x0FFFF)
 +#define netxen_get_lro_sts_l2_hdr_offset(sts_data)    \
 +      (((sts_data) >> 32) & 0x0FF)
 +#define netxen_get_lro_sts_l4_hdr_offset(sts_data)    \
 +      (((sts_data) >> 40) & 0x0FF)
 +#define netxen_get_lro_sts_timestamp(sts_data)        \
 +      (((sts_data) >> 48) & 0x1)
 +#define netxen_get_lro_sts_type(sts_data)     \
 +      (((sts_data) >> 49) & 0x7)
 +#define netxen_get_lro_sts_push_flag(sts_data)                \
 +      (((sts_data) >> 52) & 0x1)
 +#define netxen_get_lro_sts_seq_number(sts_data)               \
 +      ((sts_data) & 0x0FFFFFFFF)
 +
 +
  struct status_desc {
        __le64 status_desc_data[2];
  } __attribute__ ((aligned(16)));
  #define NETXEN_BRDTYPE_P3_10G_XFP     0x0032
  #define NETXEN_BRDTYPE_P3_10G_TP      0x0080
  
 -struct netxen_board_info {
 -      u32 header_version;
 -
 -      u32 board_mfg;
 -      u32 board_type;
 -      u32 board_num;
 -      u32 chip_id;
 -      u32 chip_minor;
 -      u32 chip_major;
 -      u32 chip_pkg;
 -      u32 chip_lot;
 -
 -      u32 port_mask;          /* available niu ports */
 -      u32 peg_mask;           /* available pegs */
 -      u32 icache_ok;          /* can we run with icache? */
 -      u32 dcache_ok;          /* can we run with dcache? */
 -      u32 casper_ok;
 -
 -      u32 mac_addr_lo_0;
 -      u32 mac_addr_lo_1;
 -      u32 mac_addr_lo_2;
 -      u32 mac_addr_lo_3;
 -
 -      /* MN-related config */
 -      u32 mn_sync_mode;       /* enable/ sync shift cclk/ sync shift mclk */
 -      u32 mn_sync_shift_cclk;
 -      u32 mn_sync_shift_mclk;
 -      u32 mn_wb_en;
 -      u32 mn_crystal_freq;    /* in MHz */
 -      u32 mn_speed;           /* in MHz */
 -      u32 mn_org;
 -      u32 mn_depth;
 -      u32 mn_ranks_0;         /* ranks per slot */
 -      u32 mn_ranks_1;         /* ranks per slot */
 -      u32 mn_rd_latency_0;
 -      u32 mn_rd_latency_1;
 -      u32 mn_rd_latency_2;
 -      u32 mn_rd_latency_3;
 -      u32 mn_rd_latency_4;
 -      u32 mn_rd_latency_5;
 -      u32 mn_rd_latency_6;
 -      u32 mn_rd_latency_7;
 -      u32 mn_rd_latency_8;
 -      u32 mn_dll_val[18];
 -      u32 mn_mode_reg;        /* MIU DDR Mode Register */
 -      u32 mn_ext_mode_reg;    /* MIU DDR Extended Mode Register */
 -      u32 mn_timing_0;        /* MIU Memory Control Timing Rgister */
 -      u32 mn_timing_1;        /* MIU Extended Memory Ctrl Timing Register */
 -      u32 mn_timing_2;        /* MIU Extended Memory Ctrl Timing2 Register */
 -
 -      /* SN-related config */
 -      u32 sn_sync_mode;       /* enable/ sync shift cclk / sync shift mclk */
 -      u32 sn_pt_mode;         /* pass through mode */
 -      u32 sn_ecc_en;
 -      u32 sn_wb_en;
 -      u32 sn_crystal_freq;
 -      u32 sn_speed;
 -      u32 sn_org;
 -      u32 sn_depth;
 -      u32 sn_dll_tap;
 -      u32 sn_rd_latency;
 -
 -      u32 mac_addr_hi_0;
 -      u32 mac_addr_hi_1;
 -      u32 mac_addr_hi_2;
 -      u32 mac_addr_hi_3;
 -
 -      u32 magic;              /* indicates flash has been initialized */
 -
 -      u32 mn_rdimm;
 -      u32 mn_dll_override;
 -
 -};
 -
 -#define FLASH_NUM_PORTS               (4)
 -
 -struct netxen_flash_mac_addr {
 -      u32 flash_addr[32];
 -};
 -
 -struct netxen_user_old_info {
 -      u8 flash_md5[16];
 -      u8 crbinit_md5[16];
 -      u8 brdcfg_md5[16];
 -      /* bootloader */
 -      u32 bootld_version;
 -      u32 bootld_size;
 -      u8 bootld_md5[16];
 -      /* image */
 -      u32 image_version;
 -      u32 image_size;
 -      u8 image_md5[16];
 -      /* primary image status */
 -      u32 primary_status;
 -      u32 secondary_present;
 -
 -      /* MAC address , 4 ports */
 -      struct netxen_flash_mac_addr mac_addr[FLASH_NUM_PORTS];
 -};
 -#define FLASH_NUM_MAC_PER_PORT        32
 -struct netxen_user_info {
 -      u8 flash_md5[16 * 64];
 -      /* bootloader */
 -      u32 bootld_version;
 -      u32 bootld_size;
 -      /* image */
 -      u32 image_version;
 -      u32 image_size;
 -      /* primary image status */
 -      u32 primary_status;
 -      u32 secondary_present;
 -
 -      /* MAC address , 4 ports, 32 address per port */
 -      u64 mac_addr[FLASH_NUM_PORTS * FLASH_NUM_MAC_PER_PORT];
 -      u32 sub_sys_id;
 -      u8 serial_num[32];
 -
 -      /* Any user defined data */
 -};
 -
 -/*
 - * Flash Layout - new format.
 - */
 -struct netxen_new_user_info {
 -      u8 flash_md5[16 * 64];
 -      /* bootloader */
 -      u32 bootld_version;
 -      u32 bootld_size;
 -      /* image */
 -      u32 image_version;
 -      u32 image_size;
 -      /* primary image status */
 -      u32 primary_status;
 -      u32 secondary_present;
 -
 -      /* MAC address , 4 ports, 32 address per port */
 -      u64 mac_addr[FLASH_NUM_PORTS * FLASH_NUM_MAC_PER_PORT];
 -      u32 sub_sys_id;
 -      u8 serial_num[32];
 -
 -      /* Any user defined data */
 -};
 -
 -#define SECONDARY_IMAGE_PRESENT 0xb3b4b5b6
 -#define SECONDARY_IMAGE_ABSENT        0xffffffff
 -#define PRIMARY_IMAGE_GOOD    0x5a5a5a5a
 -#define PRIMARY_IMAGE_BAD     0xffffffff
 -
  /* Flash memory map */
  #define NETXEN_CRBINIT_START  0       /* crbinit section */
  #define NETXEN_BRDCFG_START   0x4000  /* board config */
  #define NETXEN_PXE_START      0x3E0000        /* PXE boot rom */
  #define NETXEN_USER_START     0x3E8000        /* Firmare info */
  #define NETXEN_FIXED_START    0x3F0000        /* backup of crbinit */
 +#define NETXEN_USER_START_OLD NETXEN_PXE_START /* very old flash */
  
 +#define NX_OLD_MAC_ADDR_OFFSET        (NETXEN_USER_START)
  #define NX_FW_VERSION_OFFSET  (NETXEN_USER_START+0x408)
  #define NX_FW_SIZE_OFFSET     (NETXEN_USER_START+0x40c)
 +#define NX_FW_MAC_ADDR_OFFSET (NETXEN_USER_START+0x418)
 +#define NX_FW_SERIAL_NUM_OFFSET       (NETXEN_USER_START+0x81c)
  #define NX_BIOS_VERSION_OFFSET        (NETXEN_USER_START+0x83c)
 +
 +#define NX_HDR_VERSION_OFFSET (NETXEN_BRDCFG_START)
 +#define NX_BRDTYPE_OFFSET     (NETXEN_BRDCFG_START+0x8)
  #define NX_FW_MAGIC_OFFSET    (NETXEN_BRDCFG_START+0x128)
 +
  #define NX_FW_MIN_SIZE                (0x3fffff)
  #define NX_P2_MN_ROMIMAGE     0
  #define NX_P3_CT_ROMIMAGE     1
  #define NX_P3_MN_ROMIMAGE     2
  #define NX_FLASH_ROMIMAGE     3
  
 -#define NETXEN_USER_START_OLD NETXEN_PXE_START        /* for backward compatibility */
 -
 -#define NETXEN_FLASH_START            (NETXEN_CRBINIT_START)
 -#define NETXEN_INIT_SECTOR            (0)
 -#define NETXEN_PRIMARY_START          (NETXEN_BOOTLD_START)
 -#define NETXEN_FLASH_CRBINIT_SIZE     (0x4000)
 -#define NETXEN_FLASH_BRDCFG_SIZE      (sizeof(struct netxen_board_info))
 -#define NETXEN_FLASH_USER_SIZE                (sizeof(struct netxen_user_info)/sizeof(u32))
 -#define NETXEN_FLASH_SECONDARY_SIZE   (NETXEN_USER_START-NETXEN_SECONDARY_START)
 -#define NETXEN_NUM_PRIMARY_SECTORS    (0x20)
 -#define NETXEN_NUM_CONFIG_SECTORS     (1)
  extern char netxen_nic_driver_name[];
  
  /* Number of status descriptors to handle per interrupt */
@@@ -731,7 -881,6 +731,7 @@@ struct netxen_recv_context 
  #define NX_CAP0_LSO                   NX_CAP_BIT(0, 6)
  #define NX_CAP0_JUMBO_CONTIGUOUS      NX_CAP_BIT(0, 7)
  #define NX_CAP0_LRO_CONTIGUOUS                NX_CAP_BIT(0, 8)
 +#define NX_CAP0_HW_LRO                        NX_CAP_BIT(0, 10)
  
  /*
   * Context state
@@@ -929,9 -1078,6 +929,9 @@@ typedef struct 
  
  #define NX_MAC_EVENT          0x1
  
 +#define NX_IP_UP              2
 +#define NX_IP_DOWN            3
 +
  /*
   * Driver --> Firmware
   */
  
  #define NX_FW_CAPABILITY_LINK_NOTIFICATION    (1 << 5)
  #define NX_FW_CAPABILITY_SWITCHING            (1 << 6)
 +#define NX_FW_CAPABILITY_PEXQ                 (1 << 7)
 +#define NX_FW_CAPABILITY_BDG                  (1 << 8)
 +#define NX_FW_CAPABILITY_FVLANTX              (1 << 9)
 +#define NX_FW_CAPABILITY_HW_LRO                       (1 << 10)
  
  /* module types */
  #define LINKEVENT_MODULE_NOT_PRESENT                  1
@@@ -1112,7 -1254,7 +1112,7 @@@ struct netxen_adapter 
        u8 mc_enabled;
        u8 max_mc_count;
        u8 rss_supported;
-       u8 resv2;
+       u8 link_changed;
        u32 resv3;
  
        u8 has_link_events;
  
        nx_nic_intr_coalesce_t coal;
  
 -      u32 fw_major;
 +      u32 resv5;
        u32 fw_version;
        const struct firmware *fw;
  };
  
 -/*
 - * NetXen dma watchdog control structure
 - *
 - *    Bit 0           : enabled => R/O: 1 watchdog active, 0 inactive
 - *    Bit 1           : disable_request => 1 req disable dma watchdog
 - *    Bit 2           : enable_request =>  1 req enable dma watchdog
 - *    Bit 3-31        : unused
 - */
 -
 -#define netxen_set_dma_watchdog_disable_req(config_word) \
 -      _netxen_set_bits(config_word, 1, 1, 1)
 -#define netxen_set_dma_watchdog_enable_req(config_word) \
 -      _netxen_set_bits(config_word, 2, 1, 1)
 -#define netxen_get_dma_watchdog_enabled(config_word) \
 -      ((config_word) & 0x1)
 -#define netxen_get_dma_watchdog_disabled(config_word) \
 -      (((config_word) >> 1) & 0x1)
 -
  int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter);
  int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter);
  int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter);
@@@ -1238,9 -1398,8 +1238,9 @@@ unsigned long netxen_nic_pci_set_window
                unsigned long long addr);
  
  /* Functions from netxen_nic_init.c */
 -void netxen_free_adapter_offload(struct netxen_adapter *adapter);
 -int netxen_initialize_adapter_offload(struct netxen_adapter *adapter);
 +int netxen_init_dummy_dma(struct netxen_adapter *adapter);
 +void netxen_free_dummy_dma(struct netxen_adapter *adapter);
 +
  int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val);
  int netxen_load_firmware(struct netxen_adapter *adapter);
  int netxen_need_fw_reset(struct netxen_adapter *adapter);
@@@ -1284,7 -1443,6 +1284,7 @@@ void netxen_p3_free_mac_list(struct net
  int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32);
  int netxen_config_intr_coalesce(struct netxen_adapter *adapter);
  int netxen_config_rss(struct netxen_adapter *adapter, int enable);
 +int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd);
  int netxen_linkevent_request(struct netxen_adapter *adapter, int enable);
  void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup);
  
@@@ -1297,9 -1455,6 +1297,9 @@@ struct net_device_stats *netxen_nic_get
  void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
                struct nx_host_tx_ring *tx_ring);
  
 +/* Functions from netxen_nic_main.c */
 +int netxen_nic_reset_context(struct netxen_adapter *);
 +
  /*
   * NetXen Board information
   */
@@@ -1350,6 -1505,56 +1350,6 @@@ static inline void get_brd_name_by_type
                name = "Unknown";
  }
  
 -static inline int
 -dma_watchdog_shutdown_request(struct netxen_adapter *adapter)
 -{
 -      u32 ctrl;
 -
 -      /* check if already inactive */
 -      ctrl = adapter->hw_read_wx(adapter,
 -                      NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
 -
 -      if (netxen_get_dma_watchdog_enabled(ctrl) == 0)
 -              return 1;
 -
 -      /* Send the disable request */
 -      netxen_set_dma_watchdog_disable_req(ctrl);
 -      NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl);
 -
 -      return 0;
 -}
 -
 -static inline int
 -dma_watchdog_shutdown_poll_result(struct netxen_adapter *adapter)
 -{
 -      u32 ctrl;
 -
 -      ctrl = adapter->hw_read_wx(adapter,
 -                      NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
 -
 -      return (netxen_get_dma_watchdog_enabled(ctrl) == 0);
 -}
 -
 -static inline int
 -dma_watchdog_wakeup(struct netxen_adapter *adapter)
 -{
 -      u32 ctrl;
 -
 -      ctrl = adapter->hw_read_wx(adapter,
 -                      NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL));
 -
 -      if (netxen_get_dma_watchdog_enabled(ctrl))
 -              return 1;
 -
 -      /* send the wakeup request */
 -      netxen_set_dma_watchdog_enable_req(ctrl);
 -
 -      NXWR32(adapter, NETXEN_CAM_RAM(NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL), ctrl);
 -
 -      return 0;
 -}
 -
 -
  static inline u32 netxen_tx_avail(struct nx_host_tx_ring *tx_ring)
  {
        smp_mb();
@@@ -184,13 -184,6 +184,6 @@@ void netxen_free_sw_resources(struct ne
        kfree(recv_ctx->rds_rings);
  
  skip_rds:
-       if (recv_ctx->sds_rings == NULL)
-               goto skip_sds;
-       for(ring = 0; ring < adapter->max_sds_rings; ring++)
-               recv_ctx->sds_rings[ring].consumer = 0;
- skip_sds:
        if (adapter->tx_ring == NULL)
                return;
  
@@@ -254,14 -247,9 +247,14 @@@ int netxen_alloc_sw_resources(struct ne
                                rds_ring->skb_size =
                                        NX_CT_DEFAULT_RX_BUF_LEN;
                        } else {
 -                              rds_ring->dma_size = RX_DMA_MAP_LEN;
 +                              if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
 +                                      rds_ring->dma_size =
 +                                              NX_P3_RX_BUF_MAX_LEN;
 +                              else
 +                                      rds_ring->dma_size =
 +                                              NX_P2_RX_BUF_MAX_LEN;
                                rds_ring->skb_size =
 -                                      MAX_RX_BUFFER_LENGTH;
 +                                      rds_ring->dma_size + NET_IP_ALIGN;
                        }
                        break;
  
  
                case RCV_RING_LRO:
                        rds_ring->num_desc = adapter->num_lro_rxd;
 -                      rds_ring->dma_size = RX_LRO_DMA_MAP_LEN;
 -                      rds_ring->skb_size = MAX_RX_LRO_BUFFER_LENGTH;
 +                      rds_ring->dma_size = NX_RX_LRO_BUFFER_LENGTH;
 +                      rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN;
                        break;
  
                }
@@@ -892,10 -880,22 +885,10 @@@ netxen_validate_firmware(struct netxen_
        return 0;
  }
  
 -void netxen_request_firmware(struct netxen_adapter *adapter)
 +static int
 +netxen_p3_has_mn(struct netxen_adapter *adapter)
  {
        u32 capability, flashed_ver;
 -      u8 fw_type;
 -      struct pci_dev *pdev = adapter->pdev;
 -      int rc = 0;
 -
 -      if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
 -              fw_type = NX_P2_MN_ROMIMAGE;
 -              goto request_fw;
 -      } else {
 -              fw_type = NX_P3_CT_ROMIMAGE;
 -              goto request_fw;
 -      }
 -
 -request_mn:
        capability = 0;
  
        netxen_rom_fast_read(adapter,
        flashed_ver = NETXEN_DECODE_VERSION(flashed_ver);
  
        if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {
 +
                capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY);
 -              if (capability & NX_PEG_TUNE_MN_PRESENT) {
 -                      fw_type = NX_P3_MN_ROMIMAGE;
 -                      goto request_fw;
 -              }
 +              if (capability & NX_PEG_TUNE_MN_PRESENT)
 +                      return 1;
        }
 +      return 0;
 +}
  
 -      fw_type = NX_FLASH_ROMIMAGE;
 -      adapter->fw = NULL;
 -      goto done;
 +void netxen_request_firmware(struct netxen_adapter *adapter)
 +{
 +      u8 fw_type;
 +      struct pci_dev *pdev = adapter->pdev;
 +      int rc = 0;
 +
 +      if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
 +              fw_type = NX_P2_MN_ROMIMAGE;
 +              goto request_fw;
 +      }
 +
 +      fw_type = netxen_p3_has_mn(adapter) ?
 +              NX_P3_MN_ROMIMAGE : NX_P3_CT_ROMIMAGE;
  
  request_fw:
        rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev);
        if (rc != 0) {
 -              if (fw_type == NX_P3_CT_ROMIMAGE) {
 +              if (fw_type == NX_P3_MN_ROMIMAGE) {
                        msleep(1);
 -                      goto request_mn;
 +                      fw_type = NX_P3_CT_ROMIMAGE;
 +                      goto request_fw;
                }
  
                fw_type = NX_FLASH_ROMIMAGE;
        if (rc != 0) {
                release_firmware(adapter->fw);
  
 -              if (fw_type == NX_P3_CT_ROMIMAGE) {
 +              if (fw_type == NX_P3_MN_ROMIMAGE) {
                        msleep(1);
 -                      goto request_mn;
 +                      fw_type = NX_P3_CT_ROMIMAGE;
 +                      goto request_fw;
                }
  
                fw_type = NX_FLASH_ROMIMAGE;
@@@ -966,20 -953,19 +959,20 @@@ netxen_release_firmware(struct netxen_a
                release_firmware(adapter->fw);
  }
  
 -int netxen_initialize_adapter_offload(struct netxen_adapter *adapter)
 +int netxen_init_dummy_dma(struct netxen_adapter *adapter)
  {
 -      uint64_t addr;
 -      uint32_t hi;
 -      uint32_t lo;
 +      u64 addr;
 +      u32 hi, lo;
 +
 +      if (!NX_IS_REVISION_P2(adapter->ahw.revision_id))
 +              return 0;
  
 -      adapter->dummy_dma.addr =
 -          pci_alloc_consistent(adapter->pdev,
 +      adapter->dummy_dma.addr = pci_alloc_consistent(adapter->pdev,
                                 NETXEN_HOST_DUMMY_DMA_SIZE,
                                 &adapter->dummy_dma.phys_addr);
        if (adapter->dummy_dma.addr == NULL) {
 -              printk("%s: ERROR: Could not allocate dummy DMA memory\n",
 -                     __func__);
 +              dev_err(&adapter->pdev->dev,
 +                      "ERROR: Could not allocate dummy DMA memory\n");
                return -ENOMEM;
        }
  
        NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi);
        NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo);
  
 -      if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
 -              uint32_t temp = 0;
 -              NXWR32(adapter, CRB_HOST_DUMMY_BUF, temp);
 -      }
 -
        return 0;
  }
  
 -void netxen_free_adapter_offload(struct netxen_adapter *adapter)
 +/*
 + * NetXen DMA watchdog control:
 + *
 + *    Bit 0           : enabled => R/O: 1 watchdog active, 0 inactive
 + *    Bit 1           : disable_request => 1 req disable dma watchdog
 + *    Bit 2           : enable_request =>  1 req enable dma watchdog
 + *    Bit 3-31        : unused
 + */
 +void netxen_free_dummy_dma(struct netxen_adapter *adapter)
  {
        int i = 100;
 +      u32 ctrl;
 +
 +      if (!NX_IS_REVISION_P2(adapter->ahw.revision_id))
 +              return;
  
        if (!adapter->dummy_dma.addr)
                return;
  
 -      if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
 -              do {
 -                      if (dma_watchdog_shutdown_request(adapter) == 1)
 -                              break;
 +      ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL);
 +      if ((ctrl & 0x1) != 0) {
 +              NXWR32(adapter, NETXEN_DMA_WATCHDOG_CTRL, (ctrl | 0x2));
 +
 +              while ((ctrl & 0x1) != 0) {
 +
                        msleep(50);
 -                      if (dma_watchdog_shutdown_poll_result(adapter) == 1)
 +
 +                      ctrl = NXRD32(adapter, NETXEN_DMA_WATCHDOG_CTRL);
 +
 +                      if (--i == 0)
                                break;
 -              } while (--i);
 +              };
        }
  
        if (i) {
                            adapter->dummy_dma.addr,
                            adapter->dummy_dma.phys_addr);
                adapter->dummy_dma.addr = NULL;
 -      } else {
 -              printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
 -                              adapter->netdev->name);
 -      }
 +      } else
 +              dev_err(&adapter->pdev->dev, "dma_watchdog_shutdown failed\n");
  }
  
  int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
@@@ -1107,6 -1083,10 +1100,6 @@@ int netxen_init_firmware(struct netxen_
        NXWR32(adapter, CRB_MPORT_MODE, MPORT_MULTI_FUNCTION_MODE);
        NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK);
  
 -      if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) {
 -              adapter->capabilities = NXRD32(adapter, CRB_FW_CAPABILITIES_1);
 -      }
 -
        return err;
  }
  
@@@ -1242,31 -1222,20 +1235,31 @@@ no_skb
  
  static struct netxen_rx_buffer *
  netxen_process_rcv(struct netxen_adapter *adapter,
 -              int ring, int index, int length, int cksum, int pkt_offset,
 -              struct nx_host_sds_ring *sds_ring)
 +              struct nx_host_sds_ring *sds_ring,
 +              int ring, u64 sts_data0)
  {
        struct net_device *netdev = adapter->netdev;
        struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
        struct netxen_rx_buffer *buffer;
        struct sk_buff *skb;
 -      struct nx_host_rds_ring *rds_ring = &recv_ctx->rds_rings[ring];
 +      struct nx_host_rds_ring *rds_ring;
 +      int index, length, cksum, pkt_offset;
  
 -      if (unlikely(index > rds_ring->num_desc))
 +      if (unlikely(ring >= adapter->max_rds_rings))
 +              return NULL;
 +
 +      rds_ring = &recv_ctx->rds_rings[ring];
 +
 +      index = netxen_get_sts_refhandle(sts_data0);
 +      if (unlikely(index >= rds_ring->num_desc))
                return NULL;
  
        buffer = &rds_ring->rx_buf_arr[index];
  
 +      length = netxen_get_sts_totallength(sts_data0);
 +      cksum  = netxen_get_sts_status(sts_data0);
 +      pkt_offset = netxen_get_sts_pkt_offset(sts_data0);
 +
        skb = netxen_process_rxbuf(adapter, rds_ring, index, cksum);
        if (!skb)
                return buffer;
        return buffer;
  }
  
 +#define TCP_HDR_SIZE            20
 +#define TCP_TS_OPTION_SIZE      12
 +#define TCP_TS_HDR_SIZE         (TCP_HDR_SIZE + TCP_TS_OPTION_SIZE)
 +
 +static struct netxen_rx_buffer *
 +netxen_process_lro(struct netxen_adapter *adapter,
 +              struct nx_host_sds_ring *sds_ring,
 +              int ring, u64 sts_data0, u64 sts_data1)
 +{
 +      struct net_device *netdev = adapter->netdev;
 +      struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
 +      struct netxen_rx_buffer *buffer;
 +      struct sk_buff *skb;
 +      struct nx_host_rds_ring *rds_ring;
 +      struct iphdr *iph;
 +      struct tcphdr *th;
 +      bool push, timestamp;
 +      int l2_hdr_offset, l4_hdr_offset;
 +      int index;
 +      u16 lro_length, length, data_offset;
 +      u32 seq_number;
 +
 +      if (unlikely(ring > adapter->max_rds_rings))
 +              return NULL;
 +
 +      rds_ring = &recv_ctx->rds_rings[ring];
 +
 +      index = netxen_get_lro_sts_refhandle(sts_data0);
 +      if (unlikely(index > rds_ring->num_desc))
 +              return NULL;
 +
 +      buffer = &rds_ring->rx_buf_arr[index];
 +
 +      timestamp = netxen_get_lro_sts_timestamp(sts_data0);
 +      lro_length = netxen_get_lro_sts_length(sts_data0);
 +      l2_hdr_offset = netxen_get_lro_sts_l2_hdr_offset(sts_data0);
 +      l4_hdr_offset = netxen_get_lro_sts_l4_hdr_offset(sts_data0);
 +      push = netxen_get_lro_sts_push_flag(sts_data0);
 +      seq_number = netxen_get_lro_sts_seq_number(sts_data1);
 +
 +      skb = netxen_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
 +      if (!skb)
 +              return buffer;
 +
 +      if (timestamp)
 +              data_offset = l4_hdr_offset + TCP_TS_HDR_SIZE;
 +      else
 +              data_offset = l4_hdr_offset + TCP_HDR_SIZE;
 +
 +      skb_put(skb, lro_length + data_offset);
 +
 +      skb->truesize = (skb->len + sizeof(struct sk_buff) +
 +                      ((unsigned long)skb->data - (unsigned long)skb->head));
 +
 +      skb_pull(skb, l2_hdr_offset);
 +      skb->protocol = eth_type_trans(skb, netdev);
 +
 +      iph = (struct iphdr *)skb->data;
 +      th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
 +
 +      length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
 +      iph->tot_len = htons(length);
 +      iph->check = 0;
 +      iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 +      th->psh = push;
 +      th->seq = htonl(seq_number);
 +
 +      netif_receive_skb(skb);
 +
 +      return buffer;
 +}
 +
  #define netxen_merge_rx_buffers(list, head) \
        do { list_splice_tail_init(list, head); } while (0);
  
@@@ -1378,33 -1275,27 +1371,33 @@@ netxen_process_rcv_ring(struct nx_host_
        u32 consumer = sds_ring->consumer;
  
        int count = 0;
 -      u64 sts_data;
 -      int opcode, ring, index, length, cksum, pkt_offset, desc_cnt;
 +      u64 sts_data0, sts_data1;
 +      int opcode, ring = 0, desc_cnt;
  
        while (count < max) {
                desc = &sds_ring->desc_head[consumer];
 -              sts_data = le64_to_cpu(desc->status_desc_data[0]);
 +              sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
  
 -              if (!(sts_data & STATUS_OWNER_HOST))
 +              if (!(sts_data0 & STATUS_OWNER_HOST))
                        break;
  
 -              desc_cnt = netxen_get_sts_desc_cnt(sts_data);
 -              ring   = netxen_get_sts_type(sts_data);
 -
 -              if (ring > RCV_RING_JUMBO)
 -                      goto skip;
 +              desc_cnt = netxen_get_sts_desc_cnt(sts_data0);
  
 -              opcode = netxen_get_sts_opcode(sts_data);
 +              opcode = netxen_get_sts_opcode(sts_data0);
  
                switch (opcode) {
                case NETXEN_NIC_RXPKT_DESC:
                case NETXEN_OLD_RXPKT_DESC:
 +              case NETXEN_NIC_SYN_OFFLOAD:
 +                      ring = netxen_get_sts_type(sts_data0);
 +                      rxbuf = netxen_process_rcv(adapter, sds_ring,
 +                                      ring, sts_data0);
 +                      break;
 +              case NETXEN_NIC_LRO_DESC:
 +                      ring = netxen_get_lro_sts_type(sts_data0);
 +                      sts_data1 = le64_to_cpu(desc->status_desc_data[1]);
 +                      rxbuf = netxen_process_lro(adapter, sds_ring,
 +                                      ring, sts_data0, sts_data1);
                        break;
                case NETXEN_NIC_RESPONSE_DESC:
                        netxen_handle_fw_message(desc_cnt, consumer, sds_ring);
  
                WARN_ON(desc_cnt > 1);
  
 -              index  = netxen_get_sts_refhandle(sts_data);
 -              length = netxen_get_sts_totallength(sts_data);
 -              cksum  = netxen_get_sts_status(sts_data);
 -              pkt_offset = netxen_get_sts_pkt_offset(sts_data);
 -
 -              rxbuf = netxen_process_rcv(adapter, ring, index,
 -                              length, cksum, pkt_offset, sds_ring);
 -
                if (rxbuf)
                        list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
  
@@@ -1569,7 -1468,7 +1562,7 @@@ netxen_post_rx_buffers(struct netxen_ad
                NXWR32(adapter, rds_ring->crb_rcv_producer,
                                (producer-1) & (rds_ring->num_desc-1));
  
 -              if (adapter->fw_major < 4) {
 +              if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
                        /*
                         * Write a doorbell msg to tell phanmon of change in
                         * receive ring producer
@@@ -39,7 -39,6 +39,7 @@@
  #include <linux/if_vlan.h>
  #include <net/ip.h>
  #include <linux/ipv6.h>
 +#include <linux/inetdevice.h>
  
  MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
  MODULE_LICENSE("GPL");
@@@ -66,7 -65,7 +66,7 @@@ static int netxen_nic_open(struct net_d
  static int netxen_nic_close(struct net_device *netdev);
  static int netxen_nic_xmit_frame(struct sk_buff *, struct net_device *);
  static void netxen_tx_timeout(struct net_device *netdev);
 -static void netxen_tx_timeout_task(struct work_struct *work);
 +static void netxen_reset_task(struct work_struct *work);
  static void netxen_watchdog(unsigned long);
  static int netxen_nic_poll(struct napi_struct *napi, int budget);
  #ifdef CONFIG_NET_POLL_CONTROLLER
@@@ -95,10 -94,6 +95,6 @@@ static struct pci_device_id netxen_pci_
  
  MODULE_DEVICE_TABLE(pci, netxen_pci_tbl);
  
- static struct workqueue_struct *netxen_workq;
- #define SCHEDULE_WORK(tp)     queue_work(netxen_workq, tp)
- #define FLUSH_SCHEDULED_WORK()        flush_workqueue(netxen_workq)
  static void netxen_watchdog(unsigned long);
  
  static uint32_t crb_cmd_producer[4] = {
@@@ -172,6 -167,8 +168,8 @@@ netxen_free_sds_rings(struct netxen_rec
  {
        if (recv_ctx->sds_rings != NULL)
                kfree(recv_ctx->sds_rings);
+       recv_ctx->sds_rings = NULL;
  }
  
  static int
@@@ -182,7 -179,7 +180,7 @@@ netxen_napi_add(struct netxen_adapter *
        struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
  
        if (netxen_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
 -              return 1;
 +              return -ENOMEM;
  
        for (ring = 0; ring < adapter->max_sds_rings; ring++) {
                sds_ring = &recv_ctx->sds_rings[ring];
        return 0;
  }
  
+ static void
+ netxen_napi_del(struct netxen_adapter *adapter)
+ {
+       int ring;
+       struct nx_host_sds_ring *sds_ring;
+       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               netif_napi_del(&sds_ring->napi);
+       }
+       netxen_free_sds_rings(&adapter->recv_ctx);
+ }
  static void
  netxen_napi_enable(struct netxen_adapter *adapter)
  {
@@@ -296,16 -308,12 +309,16 @@@ err_out
        return err;
  }
  
 -static void netxen_check_options(struct netxen_adapter *adapter)
 +static void
 +netxen_check_options(struct netxen_adapter *adapter)
  {
 -      if (adapter->ahw.port_type == NETXEN_NIC_XGBE)
 -              adapter->num_rxd = MAX_RCV_DESCRIPTORS_10G;
 -      else if (adapter->ahw.port_type == NETXEN_NIC_GBE)
 -              adapter->num_rxd = MAX_RCV_DESCRIPTORS_1G;
 +      if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
 +              adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_10G;
 +              adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_10G;
 +      } else if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
 +              adapter->num_rxd = DEFAULT_RCV_DESCRIPTORS_1G;
 +              adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS_1G;
 +      }
  
        adapter->msix_supported = 0;
        if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
                }
        }
  
 -      adapter->num_txd = MAX_CMD_DESCRIPTORS_HOST;
 -      adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS;
 -      adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS;
 +      adapter->num_txd = MAX_CMD_DESCRIPTORS;
  
 -      return;
 +      if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
 +              adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS;
 +              adapter->max_rds_rings = 3;
 +      } else {
 +              adapter->num_lro_rxd = 0;
 +              adapter->max_rds_rings = 2;
 +      }
  }
  
  static int
@@@ -766,7 -770,7 +779,7 @@@ netxen_start_firmware(struct netxen_ada
  
        }
  
 -      err = netxen_initialize_adapter_offload(adapter);
 +      err = netxen_init_dummy_dma(adapter);
        if (err)
                return err;
  
@@@ -782,14 -786,10 +795,14 @@@ wait_init
        /* Handshake with the card before we register the devices. */
        err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
        if (err) {
 -              netxen_free_adapter_offload(adapter);
 +              netxen_free_dummy_dma(adapter);
                return err;
        }
  
 +      nx_update_dma_mask(adapter);
 +
 +      netxen_nic_get_firmware_info(adapter);
 +
        return 0;
  }
  
@@@ -840,20 -840,6 +853,20 @@@ netxen_nic_free_irq(struct netxen_adapt
        }
  }
  
 +static void
 +netxen_nic_init_coalesce_defaults(struct netxen_adapter *adapter)
 +{
 +      adapter->coal.flags = NETXEN_NIC_INTR_DEFAULT;
 +      adapter->coal.normal.data.rx_time_us =
 +              NETXEN_DEFAULT_INTR_COALESCE_RX_TIME_US;
 +      adapter->coal.normal.data.rx_packets =
 +              NETXEN_DEFAULT_INTR_COALESCE_RX_PACKETS;
 +      adapter->coal.normal.data.tx_time_us =
 +              NETXEN_DEFAULT_INTR_COALESCE_TX_TIME_US;
 +      adapter->coal.normal.data.tx_packets =
 +              NETXEN_DEFAULT_INTR_COALESCE_TX_PACKETS;
 +}
 +
  static int
  netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
  {
        if (adapter->max_sds_rings > 1)
                netxen_config_rss(adapter, 1);
  
 +      if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
 +              netxen_config_intr_coalesce(adapter);
 +
        netxen_napi_enable(adapter);
  
        if (adapter->capabilities & NX_FW_CAPABILITY_LINK_NOTIFICATION)
@@@ -910,7 -893,6 +923,6 @@@ netxen_nic_down(struct netxen_adapter *
        spin_unlock(&adapter->tx_clean_lock);
  
        del_timer_sync(&adapter->watchdog_timer);
-       FLUSH_SCHEDULED_WORK();
  }
  
  
@@@ -923,15 -905,19 +935,17 @@@ netxen_nic_attach(struct netxen_adapte
        struct nx_host_rds_ring *rds_ring;
        struct nx_host_tx_ring *tx_ring;
  
 +      if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
 +              return 0;
 +
        err = netxen_init_firmware(adapter);
-       if (err != 0) {
-               printk(KERN_ERR "Failed to init firmware\n");
-               return -EIO;
-       }
+       if (err)
+               return err;
+       err = netxen_napi_add(adapter, netdev);
+       if (err)
+               return err;
  
 -      if (adapter->fw_major < 4)
 -              adapter->max_rds_rings = 3;
 -      else
 -              adapter->max_rds_rings = 2;
 -
        err = netxen_alloc_sw_resources(adapter);
        if (err) {
                printk(KERN_ERR "%s: Error in setting sw resources\n",
                goto err_out_free_sw;
        }
  
 -      if (adapter->fw_major < 4) {
 +      if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
                tx_ring = adapter->tx_ring;
                tx_ring->crb_cmd_producer = crb_cmd_producer[adapter->portnum];
                tx_ring->crb_cmd_consumer = crb_cmd_consumer[adapter->portnum];
                goto err_out_free_rxbuf;
        }
  
 +      if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
 +              netxen_nic_init_coalesce_defaults(adapter);
 +
        adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
        return 0;
  
@@@ -989,106 -972,15 +1003,107 @@@ err_out_free_sw
  static void
  netxen_nic_detach(struct netxen_adapter *adapter)
  {
 +      if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
 +              return;
 +
        netxen_free_hw_resources(adapter);
        netxen_release_rx_buffers(adapter);
        netxen_nic_free_irq(adapter);
+       netxen_napi_del(adapter);
        netxen_free_sw_resources(adapter);
  
        adapter->is_up = 0;
  }
  
 +int
 +netxen_nic_reset_context(struct netxen_adapter *adapter)
 +{
 +      int err = 0;
 +      struct net_device *netdev = adapter->netdev;
 +
 +      if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
 +
 +              if (netif_running(netdev))
 +                      netxen_nic_down(adapter, netdev);
 +
 +              netxen_nic_detach(adapter);
 +
 +              err = netxen_nic_attach(adapter);
 +              if (err)
 +                      goto done;
 +
 +              if (netif_running(netdev))
 +                      err = netxen_nic_up(adapter, netdev);
 +      }
 +done:
 +      return err;
 +}
 +
 +static int
 +netxen_setup_netdev(struct netxen_adapter *adapter,
 +              struct net_device *netdev)
 +{
 +      int err = 0;
 +      struct pci_dev *pdev = adapter->pdev;
 +
 +      adapter->rx_csum = 1;
 +      adapter->mc_enabled = 0;
 +      if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
 +              adapter->max_mc_count = 38;
 +      else
 +              adapter->max_mc_count = 16;
 +
 +      netdev->netdev_ops         = &netxen_netdev_ops;
 +      netdev->watchdog_timeo     = 2*HZ;
 +
 +      netxen_nic_change_mtu(netdev, netdev->mtu);
 +
 +      SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
 +
 +      netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
 +      netdev->features |= (NETIF_F_GRO);
 +      netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
 +
 +      if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
 +              netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
 +              netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
 +      }
 +
 +      if (adapter->pci_using_dac) {
 +              netdev->features |= NETIF_F_HIGHDMA;
 +              netdev->vlan_features |= NETIF_F_HIGHDMA;
 +      }
 +
 +      if (adapter->capabilities & NX_FW_CAPABILITY_FVLANTX)
 +              netdev->features |= (NETIF_F_HW_VLAN_TX);
 +
 +      netdev->irq = adapter->msix_entries[0].vector;
 +
 +      err = netxen_napi_add(adapter, netdev);
 +      if (err)
 +              return err;
 +
 +      init_timer(&adapter->watchdog_timer);
 +      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_reset_task);
 +
 +      if (netxen_read_mac_addr(adapter))
 +              dev_warn(&pdev->dev, "failed to read mac addr\n");
 +
 +      netif_carrier_off(netdev);
 +      netif_stop_queue(netdev);
 +
 +      err = register_netdev(netdev);
 +      if (err) {
 +              dev_err(&pdev->dev, "failed to register net device\n");
 +              return err;
 +      }
 +
 +      return 0;
 +}
 +
  static int __devinit
  netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
  {
  
        netdev = alloc_etherdev(sizeof(struct netxen_adapter));
        if(!netdev) {
 -              printk(KERN_ERR"%s: Failed to allocate memory for the "
 -                              "device block.Check system memory resource"
 -                              " usage.\n", netxen_nic_driver_name);
 +              dev_err(&pdev->dev, "failed to allocate net_device\n");
 +              err = -ENOMEM;
                goto err_out_free_res;
        }
  
  
        /* This will be reset for mezz cards  */
        adapter->portnum = pci_func_id;
 -      adapter->rx_csum = 1;
 -      adapter->mc_enabled = 0;
 -      if (NX_IS_REVISION_P3(revision_id))
 -              adapter->max_mc_count = 38;
 -      else
 -              adapter->max_mc_count = 16;
 -
 -      netdev->netdev_ops         = &netxen_netdev_ops;
 -      netdev->watchdog_timeo     = 2*HZ;
  
 -      netxen_nic_change_mtu(netdev, netdev->mtu);
 -
 -      SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops);
 -
 -      netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
 -      netdev->features |= (NETIF_F_GRO);
 -      netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO);
 -
 -      if (NX_IS_REVISION_P3(revision_id)) {
 -              netdev->features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
 -              netdev->vlan_features |= (NETIF_F_IPV6_CSUM | NETIF_F_TSO6);
 -      }
 -
 -      if (adapter->pci_using_dac) {
 -              netdev->features |= NETIF_F_HIGHDMA;
 -              netdev->vlan_features |= NETIF_F_HIGHDMA;
 -      }
 -
 -      if (netxen_nic_get_board_info(adapter) != 0) {
 -              printk("%s: Error getting board config info.\n",
 -                              netxen_nic_driver_name);
 -              err = -EIO;
 +      err = netxen_nic_get_board_info(adapter);
 +      if (err) {
 +              dev_err(&pdev->dev, "Error getting board config info.\n");
                goto err_out_iounmap;
        }
  
        if (err)
                goto err_out_iounmap;
  
 -      nx_update_dma_mask(adapter);
 -
 -      netxen_nic_get_firmware_info(adapter);
 -
        /*
         * See if the firmware gave us a virtual-physical port mapping.
         */
        adapter->physical_port = adapter->portnum;
 -      if (adapter->fw_major < 4) {
 +      if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
                i = NXRD32(adapter, CRB_V2P(adapter->portnum));
                if (i != 0x55555555)
                        adapter->physical_port = i;
  
        netxen_setup_intr(adapter);
  
 -      netdev->irq = adapter->msix_entries[0].vector;
 -
 -      init_timer(&adapter->watchdog_timer);
 -      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);
 -
 -      err = netxen_read_mac_addr(adapter);
 +      err = netxen_setup_netdev(adapter, netdev);
        if (err)
 -              dev_warn(&pdev->dev, "failed to read mac addr\n");
 -
 -      netif_carrier_off(netdev);
 -      netif_stop_queue(netdev);
 -
 -      if ((err = register_netdev(netdev))) {
 -              printk(KERN_ERR "%s: register_netdev failed port #%d"
 -                             " aborting\n", netxen_nic_driver_name,
 -                             adapter->portnum);
 -              err = -EIO;
                goto err_out_disable_msi;
 -      }
  
        pci_set_drvdata(pdev, adapter);
  
  err_out_disable_msi:
        netxen_teardown_intr(adapter);
  
 -      netxen_free_adapter_offload(adapter);
 +      netxen_free_dummy_dma(adapter);
  
  err_out_iounmap:
        netxen_cleanup_pci_map(adapter);
@@@ -1245,13 -1189,17 +1260,15 @@@ static void __devexit netxen_nic_remove
  
        unregister_netdev(netdev);
  
 -      if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
 -              netxen_nic_detach(adapter);
 -      }
+       cancel_work_sync(&adapter->watchdog_task);
+       cancel_work_sync(&adapter->tx_timeout_task);
 +      netxen_nic_detach(adapter);
  
        if (adapter->portnum == 0)
 -              netxen_free_adapter_offload(adapter);
 +              netxen_free_dummy_dma(adapter);
  
        netxen_teardown_intr(adapter);
-       netxen_free_sds_rings(&adapter->recv_ctx);
  
        netxen_cleanup_pci_map(adapter);
  
@@@ -1277,7 -1225,11 +1294,10 @@@ netxen_nic_suspend(struct pci_dev *pdev
        if (netif_running(netdev))
                netxen_nic_down(adapter, netdev);
  
 -      if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
 -              netxen_nic_detach(adapter);
+       cancel_work_sync(&adapter->watchdog_task);
+       cancel_work_sync(&adapter->tx_timeout_task);
 +      netxen_nic_detach(adapter);
  
        pci_save_state(pdev);
  
@@@ -1338,9 -1290,11 +1358,9 @@@ static int netxen_nic_open(struct net_d
        if (adapter->driver_mismatch)
                return -EIO;
  
 -      if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) {
 -              err = netxen_nic_attach(adapter);
 -              if (err)
 -                      return err;
 -      }
 +      err = netxen_nic_attach(adapter);
 +      if (err)
 +              return err;
  
        err = netxen_nic_up(adapter, netdev);
        if (err)
@@@ -1366,52 -1320,30 +1386,52 @@@ static int netxen_nic_close(struct net_
        return 0;
  }
  
 -static bool netxen_tso_check(struct net_device *netdev,
 -                    struct cmd_desc_type0 *desc, struct sk_buff *skb)
 +static void
 +netxen_tso_check(struct net_device *netdev,
 +              struct nx_host_tx_ring *tx_ring,
 +              struct cmd_desc_type0 *first_desc,
 +              struct sk_buff *skb)
  {
 -      bool tso = false;
        u8 opcode = TX_ETHER_PKT;
        __be16 protocol = skb->protocol;
 -      u16 flags = 0;
 +      u16 flags = 0, vid = 0;
 +      u32 producer;
 +      int copied, offset, copy_len, hdr_len = 0, tso = 0, vlan_oob = 0;
 +      struct cmd_desc_type0 *hwdesc;
 +      struct vlan_ethhdr *vh;
  
        if (protocol == cpu_to_be16(ETH_P_8021Q)) {
 -              struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data;
 +
 +              vh = (struct vlan_ethhdr *)skb->data;
                protocol = vh->h_vlan_encapsulated_proto;
                flags = FLAGS_VLAN_TAGGED;
 +
 +      } else if (vlan_tx_tag_present(skb)) {
 +
 +              flags = FLAGS_VLAN_OOB;
 +              vid = vlan_tx_tag_get(skb);
 +              netxen_set_tx_vlan_tci(first_desc, vid);
 +              vlan_oob = 1;
        }
  
        if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
                        skb_shinfo(skb)->gso_size > 0) {
  
 -              desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
 -              desc->total_hdr_length =
 -                      skb_transport_offset(skb) + tcp_hdrlen(skb);
 +              hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
 +
 +              first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
 +              first_desc->total_hdr_length = hdr_len;
 +              if (vlan_oob) {
 +                      first_desc->total_hdr_length += VLAN_HLEN;
 +                      first_desc->tcp_hdr_offset = VLAN_HLEN;
 +                      first_desc->ip_hdr_offset = VLAN_HLEN;
 +                      /* Only in case of TSO on vlan device */
 +                      flags |= FLAGS_VLAN_TAGGED;
 +              }
  
                opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ?
                                TX_TCP_LSO6 : TX_TCP_LSO;
 -              tso = true;
 +              tso = 1;
  
        } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
                u8 l4proto;
                                opcode = TX_UDPV6_PKT;
                }
        }
 -      desc->tcp_hdr_offset = skb_transport_offset(skb);
 -      desc->ip_hdr_offset = skb_network_offset(skb);
 -      netxen_set_tx_flags_opcode(desc, flags, opcode);
 -      return tso;
 +
 +      first_desc->tcp_hdr_offset += skb_transport_offset(skb);
 +      first_desc->ip_hdr_offset += skb_network_offset(skb);
 +      netxen_set_tx_flags_opcode(first_desc, flags, opcode);
 +
 +      if (!tso)
 +              return;
 +
 +      /* For LSO, we need to copy the MAC/IP/TCP headers into
 +       * the descriptor ring
 +       */
 +      producer = tx_ring->producer;
 +      copied = 0;
 +      offset = 2;
 +
 +      if (vlan_oob) {
 +              /* Create a TSO vlan header template for firmware */
 +
 +              hwdesc = &tx_ring->desc_head[producer];
 +              tx_ring->cmd_buf_arr[producer].skb = NULL;
 +
 +              copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
 +                              hdr_len + VLAN_HLEN);
 +
 +              vh = (struct vlan_ethhdr *)((char *)hwdesc + 2);
 +              skb_copy_from_linear_data(skb, vh, 12);
 +              vh->h_vlan_proto = htons(ETH_P_8021Q);
 +              vh->h_vlan_TCI = htons(vid);
 +              skb_copy_from_linear_data_offset(skb, 12,
 +                              (char *)vh + 16, copy_len - 16);
 +
 +              copied = copy_len - VLAN_HLEN;
 +              offset = 0;
 +
 +              producer = get_next_index(producer, tx_ring->num_desc);
 +      }
 +
 +      while (copied < hdr_len) {
 +
 +              copy_len = min((int)sizeof(struct cmd_desc_type0) - offset,
 +                              (hdr_len - copied));
 +
 +              hwdesc = &tx_ring->desc_head[producer];
 +              tx_ring->cmd_buf_arr[producer].skb = NULL;
 +
 +              skb_copy_from_linear_data_offset(skb, copied,
 +                               (char *)hwdesc + offset, copy_len);
 +
 +              copied += copy_len;
 +              offset = 0;
 +
 +              producer = get_next_index(producer, tx_ring->num_desc);
 +      }
 +
 +      tx_ring->producer = producer;
 +      barrier();
  }
  
  static void
@@@ -1511,8 -1391,9 +1531,8 @@@ netxen_clean_tx_dma_mapping(struct pci_
  static inline void
  netxen_clear_cmddesc(u64 *desc)
  {
 -      int i;
 -      for (i = 0; i < 8; i++)
 -              desc[i] = 0ULL;
 +      desc[0] = 0ULL;
 +      desc[2] = 0ULL;
  }
  
  static int
@@@ -1520,18 -1401,18 +1540,18 @@@ netxen_nic_xmit_frame(struct sk_buff *s
  {
        struct netxen_adapter *adapter = netdev_priv(netdev);
        struct nx_host_tx_ring *tx_ring = adapter->tx_ring;
 -      unsigned int first_seg_len = skb->len - skb->data_len;
 +      struct skb_frag_struct *frag;
        struct netxen_cmd_buffer *pbuf;
        struct netxen_skb_frag *buffrag;
 -      struct cmd_desc_type0 *hwdesc;
 -      struct pci_dev *pdev = adapter->pdev;
 +      struct cmd_desc_type0 *hwdesc, *first_desc;
 +      struct pci_dev *pdev;
        dma_addr_t temp_dma;
        int i, k;
 +      unsigned long offset;
  
        u32 producer;
 -      int frag_count, no_of_desc;
 +      int len, frag_count, no_of_desc;
        u32 num_txd = tx_ring->num_desc;
 -      bool is_tso = false;
  
        frag_count = skb_shinfo(skb)->nr_frags + 1;
  
  
        producer = tx_ring->producer;
  
 -      hwdesc = &tx_ring->desc_head[producer];
 -      netxen_clear_cmddesc((u64 *)hwdesc);
 -      pbuf = &tx_ring->cmd_buf_arr[producer];
 +      pdev = adapter->pdev;
 +      len = skb->len - skb->data_len;
  
 -      is_tso = netxen_tso_check(netdev, hwdesc, skb);
 +      temp_dma = pci_map_single(pdev, skb->data, len, PCI_DMA_TODEVICE);
 +      if (pci_dma_mapping_error(pdev, temp_dma))
 +              goto drop_packet;
  
 +      pbuf = &tx_ring->cmd_buf_arr[producer];
        pbuf->skb = skb;
        pbuf->frag_count = frag_count;
 -      buffrag = &pbuf->frag_array[0];
 -      temp_dma = pci_map_single(pdev, skb->data, first_seg_len,
 -                                    PCI_DMA_TODEVICE);
 -      if (pci_dma_mapping_error(pdev, temp_dma))
 -              goto drop_packet;
  
 +      buffrag = &pbuf->frag_array[0];
        buffrag->dma = temp_dma;
 -      buffrag->length = first_seg_len;
 +      buffrag->length = len;
 +
 +      first_desc = hwdesc = &tx_ring->desc_head[producer];
 +      netxen_clear_cmddesc((u64 *)hwdesc);
        netxen_set_tx_frags_len(hwdesc, frag_count, skb->len);
        netxen_set_tx_port(hwdesc, adapter->portnum);
  
 -      hwdesc->buffer_length[0] = cpu_to_le16(first_seg_len);
 -      hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
 +      hwdesc->buffer_length[0] = cpu_to_le16(len);
 +      hwdesc->addr_buffer1 = cpu_to_le64(temp_dma);
  
        for (i = 1, k = 1; i < frag_count; i++, k++) {
 -              struct skb_frag_struct *frag;
 -              int len, temp_len;
 -              unsigned long offset;
  
                /* move to next desc. if there is a need */
                if ((i & 0x3) == 0) {
                        pbuf = &tx_ring->cmd_buf_arr[producer];
                        pbuf->skb = NULL;
                }
 +              buffrag = &pbuf->frag_array[i];
                frag = &skb_shinfo(skb)->frags[i - 1];
                len = frag->size;
                offset = frag->page_offset;
  
 -              temp_len = len;
                temp_dma = pci_map_page(pdev, frag->page, offset,
                                        len, PCI_DMA_TODEVICE);
                if (pci_dma_mapping_error(pdev, temp_dma)) {
                        goto drop_packet;
                }
  
 -              buffrag++;
                buffrag->dma = temp_dma;
 -              buffrag->length = temp_len;
 +              buffrag->length = len;
  
 -              hwdesc->buffer_length[k] = cpu_to_le16(temp_len);
 +              hwdesc->buffer_length[k] = cpu_to_le16(len);
                switch (k) {
                case 0:
                        hwdesc->addr_buffer1 = cpu_to_le64(temp_dma);
                        hwdesc->addr_buffer4 = cpu_to_le64(temp_dma);
                        break;
                }
 -              frag++;
        }
 -      producer = get_next_index(producer, num_txd);
 -
 -      /* For LSO, we need to copy the MAC/IP/TCP headers into
 -       * the descriptor ring
 -       */
 -      if (is_tso) {
 -              int hdr_len, first_hdr_len, more_hdr;
 -              hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
 -              if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) {
 -                      first_hdr_len = sizeof(struct cmd_desc_type0) - 2;
 -                      more_hdr = 1;
 -              } else {
 -                      first_hdr_len = hdr_len;
 -                      more_hdr = 0;
 -              }
 -              /* copy the MAC/IP/TCP headers to the cmd descriptor list */
 -              hwdesc = &tx_ring->desc_head[producer];
 -              pbuf = &tx_ring->cmd_buf_arr[producer];
 -              pbuf->skb = NULL;
 +      tx_ring->producer = get_next_index(producer, num_txd);
  
 -              /* copy the first 64 bytes */
 -              memcpy(((void *)hwdesc) + 2,
 -                     (void *)(skb->data), first_hdr_len);
 -              producer = get_next_index(producer, num_txd);
 -
 -              if (more_hdr) {
 -                      hwdesc = &tx_ring->desc_head[producer];
 -                      pbuf = &tx_ring->cmd_buf_arr[producer];
 -                      pbuf->skb = NULL;
 -                      /* copy the next 64 bytes - should be enough except
 -                       * for pathological case
 -                       */
 -                      skb_copy_from_linear_data_offset(skb, first_hdr_len,
 -                                                       hwdesc,
 -                                                       (hdr_len -
 -                                                        first_hdr_len));
 -                      producer = get_next_index(producer, num_txd);
 -              }
 -      }
 -
 -      tx_ring->producer = producer;
 -      adapter->stats.txbytes += skb->len;
 +      netxen_tso_check(netdev, tx_ring, first_desc, skb);
  
        netxen_nic_update_cmd_producer(adapter, tx_ring);
  
 +      adapter->stats.txbytes += skb->len;
        adapter->stats.xmitcalled++;
  
        return NETDEV_TX_OK;
@@@ -1643,11 -1566,6 +1663,6 @@@ static int netxen_nic_check_temp(struc
                       "%s: Device temperature %d degrees C exceeds"
                       " maximum allowed. Hardware has been shut down.\n",
                       netdev->name, temp_val);
-               netif_device_detach(netdev);
-               netxen_nic_down(adapter, netdev);
-               netxen_nic_detach(adapter);
                rv = 1;
        } else if (temp_state == NX_TEMP_WARN) {
                if (adapter->temp == NX_TEMP_NORMAL) {
@@@ -1681,10 -1599,7 +1696,7 @@@ void netxen_advert_link_change(struct n
                        netif_carrier_off(netdev);
                        netif_stop_queue(netdev);
                }
-               if (!adapter->has_link_events)
-                       netxen_nic_set_link_parameters(adapter);
+               adapter->link_changed = !adapter->has_link_events;
        } else if (!adapter->ahw.linkup && linkup) {
                printk(KERN_INFO "%s: %s NIC Link is up\n",
                       netxen_nic_driver_name, netdev->name);
                        netif_carrier_on(netdev);
                        netif_wake_queue(netdev);
                }
-               if (!adapter->has_link_events)
-                       netxen_nic_set_link_parameters(adapter);
+               adapter->link_changed = !adapter->has_link_events;
        }
  }
  
@@@ -1722,11 -1635,36 +1732,36 @@@ static void netxen_nic_handle_phy_intr(
        netxen_advert_link_change(adapter, linkup);
  }
  
+ static void netxen_nic_thermal_shutdown(struct netxen_adapter *adapter)
+ {
+       struct net_device *netdev = adapter->netdev;
+       netif_device_detach(netdev);
+       netxen_nic_down(adapter, netdev);
+       netxen_nic_detach(adapter);
+ }
  static void netxen_watchdog(unsigned long v)
  {
        struct netxen_adapter *adapter = (struct netxen_adapter *)v;
  
-       SCHEDULE_WORK(&adapter->watchdog_task);
+       if (netxen_nic_check_temp(adapter))
+               goto do_sched;
+       if (!adapter->has_link_events) {
+               netxen_nic_handle_phy_intr(adapter);
+               if (adapter->link_changed)
+                       goto do_sched;
+       }
+       if (netif_running(adapter->netdev))
+               mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+       return;
+ do_sched:
+       schedule_work(&adapter->watchdog_task);
  }
  
  void netxen_watchdog_task(struct work_struct *work)
        struct netxen_adapter *adapter =
                container_of(work, struct netxen_adapter, watchdog_task);
  
-       if (netxen_nic_check_temp(adapter))
+       if (adapter->temp == NX_TEMP_PANIC) {
+               netxen_nic_thermal_shutdown(adapter);
                return;
+       }
  
-       if (!adapter->has_link_events)
-               netxen_nic_handle_phy_intr(adapter);
+       if (adapter->link_changed)
+               netxen_nic_set_link_parameters(adapter);
  
        if (netif_running(adapter->netdev))
                mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
  
  static void netxen_tx_timeout(struct net_device *netdev)
  {
-       struct netxen_adapter *adapter = (struct netxen_adapter *)
-                                               netdev_priv(netdev);
+       struct netxen_adapter *adapter = netdev_priv(netdev);
 +
 +      dev_err(&netdev->dev, "transmit timeout, resetting.\n");
-       SCHEDULE_WORK(&adapter->tx_timeout_task);
+       schedule_work(&adapter->tx_timeout_task);
  }
  
 -static void netxen_tx_timeout_task(struct work_struct *work)
 +static void netxen_reset_task(struct work_struct *work)
  {
        struct netxen_adapter *adapter =
                container_of(work, struct netxen_adapter, tx_timeout_task);
        if (!netif_running(adapter->netdev))
                return;
  
 -      printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
 -             netxen_nic_driver_name, adapter->netdev->name);
 -
        netxen_napi_disable(adapter);
  
        adapter->netdev->trans_start = jiffies;
@@@ -1819,7 -1758,7 +1854,7 @@@ static irqreturn_t netxen_intr(int irq
        }
  
        /* clear interrupt */
 -      if (adapter->fw_major < 4)
 +      if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
                netxen_nic_disable_int(sds_ring);
  
        adapter->pci_write_immediate(adapter,
@@@ -1888,128 -1827,6 +1923,128 @@@ static void netxen_nic_poll_controller(
  }
  #endif
  
 +#ifdef CONFIG_INET
 +
 +#define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops)
 +
 +static int
 +netxen_destip_supported(struct netxen_adapter *adapter)
 +{
 +      if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
 +              return 0;
 +
 +      if (adapter->ahw.cut_through)
 +              return 0;
 +
 +      return 1;
 +}
 +
 +static int netxen_netdev_event(struct notifier_block *this,
 +                               unsigned long event, void *ptr)
 +{
 +      struct netxen_adapter *adapter;
 +      struct net_device *dev = (struct net_device *)ptr;
 +      struct in_device *indev;
 +
 +recheck:
 +      if (dev == NULL)
 +              goto done;
 +
 +      if (dev->priv_flags & IFF_802_1Q_VLAN) {
 +              dev = vlan_dev_real_dev(dev);
 +              goto recheck;
 +      }
 +
 +      if (!is_netxen_netdev(dev))
 +              goto done;
 +
 +      adapter = netdev_priv(dev);
 +
 +      if (!adapter || !netxen_destip_supported(adapter))
 +              goto done;
 +
 +      if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
 +              goto done;
 +
 +      indev = in_dev_get(dev);
 +      if (!indev)
 +              goto done;
 +
 +      for_ifa(indev) {
 +              switch (event) {
 +              case NETDEV_UP:
 +                      netxen_config_ipaddr(adapter,
 +                                      ifa->ifa_address, NX_IP_UP);
 +                      break;
 +              case NETDEV_DOWN:
 +                      netxen_config_ipaddr(adapter,
 +                                      ifa->ifa_address, NX_IP_DOWN);
 +                      break;
 +              default:
 +                      break;
 +              }
 +      } endfor_ifa(indev);
 +
 +      in_dev_put(indev);
 +done:
 +      return NOTIFY_DONE;
 +}
 +
 +static int
 +netxen_inetaddr_event(struct notifier_block *this,
 +              unsigned long event, void *ptr)
 +{
 +      struct netxen_adapter *adapter;
 +      struct net_device *dev;
 +
 +      struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
 +
 +      dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;
 +
 +recheck:
 +      if (dev == NULL || !netif_running(dev))
 +              goto done;
 +
 +      if (dev->priv_flags & IFF_802_1Q_VLAN) {
 +              dev = vlan_dev_real_dev(dev);
 +              goto recheck;
 +      }
 +
 +      if (!is_netxen_netdev(dev))
 +              goto done;
 +
 +      adapter = netdev_priv(dev);
 +
 +      if (!adapter || !netxen_destip_supported(adapter))
 +              goto done;
 +
 +      if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
 +              goto done;
 +
 +      switch (event) {
 +      case NETDEV_UP:
 +              netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP);
 +              break;
 +      case NETDEV_DOWN:
 +              netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_DOWN);
 +              break;
 +      default:
 +              break;
 +      }
 +
 +done:
 +      return NOTIFY_DONE;
 +}
 +
 +static struct notifier_block  netxen_netdev_cb = {
 +      .notifier_call = netxen_netdev_event,
 +};
 +
 +static struct notifier_block netxen_inetaddr_cb = {
 +      .notifier_call = netxen_inetaddr_event,
 +};
 +#endif
 +
  static struct pci_driver netxen_driver = {
        .name = netxen_nic_driver_name,
        .id_table = netxen_pci_tbl,
  #endif
  };
  
 -/* Driver Registration on NetXen card    */
 -
  static int __init netxen_init_module(void)
  {
        printk(KERN_INFO "%s\n", netxen_nic_driver_string);
  
-       if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL)
-               return -ENOMEM;
 +#ifdef CONFIG_INET
 +      register_netdevice_notifier(&netxen_netdev_cb);
 +      register_inetaddr_notifier(&netxen_inetaddr_cb);
 +#endif
 +
        return pci_register_driver(&netxen_driver);
  }
  
@@@ -2041,12 -1852,6 +2073,11 @@@ module_init(netxen_init_module)
  static void __exit netxen_exit_module(void)
  {
        pci_unregister_driver(&netxen_driver);
-       destroy_workqueue(netxen_workq);
 +
 +#ifdef CONFIG_INET
 +      unregister_inetaddr_notifier(&netxen_inetaddr_cb);
 +      unregister_netdevice_notifier(&netxen_netdev_cb);
 +#endif
  }
  
  module_exit(netxen_exit_module);