]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/cxgb3/cxgb3_main.c
[netdrvr] atlx: code movement: move atl1 parameter parsing
[linux-2.6-omap-h63xx.git] / drivers / net / cxgb3 / cxgb3_main.c
index dc5d26988bb3e912030ae2a35bb91020a45ca5f4..05e5f59e87fa56f2e71f359f0a312ba446bdae5b 100644 (file)
@@ -76,20 +76,20 @@ enum {
 
 #define EEPROM_MAGIC 0x38E2F10C
 
-#define CH_DEVICE(devid, ssid, idx) \
-       { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx }
+#define CH_DEVICE(devid, idx) \
+       { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, PCI_ANY_ID, 0, 0, idx }
 
 static const struct pci_device_id cxgb3_pci_tbl[] = {
-       CH_DEVICE(0x20, 1, 0),  /* PE9000 */
-       CH_DEVICE(0x21, 1, 1),  /* T302E */
-       CH_DEVICE(0x22, 1, 2),  /* T310E */
-       CH_DEVICE(0x23, 1, 3),  /* T320X */
-       CH_DEVICE(0x24, 1, 1),  /* T302X */
-       CH_DEVICE(0x25, 1, 3),  /* T320E */
-       CH_DEVICE(0x26, 1, 2),  /* T310X */
-       CH_DEVICE(0x30, 1, 2),  /* T3B10 */
-       CH_DEVICE(0x31, 1, 3),  /* T3B20 */
-       CH_DEVICE(0x32, 1, 1),  /* T3B02 */
+       CH_DEVICE(0x20, 0),     /* PE9000 */
+       CH_DEVICE(0x21, 1),     /* T302E */
+       CH_DEVICE(0x22, 2),     /* T310E */
+       CH_DEVICE(0x23, 3),     /* T320X */
+       CH_DEVICE(0x24, 1),     /* T302X */
+       CH_DEVICE(0x25, 3),     /* T320E */
+       CH_DEVICE(0x26, 2),     /* T310X */
+       CH_DEVICE(0x30, 2),     /* T3B10 */
+       CH_DEVICE(0x31, 3),     /* T3B20 */
+       CH_DEVICE(0x32, 1),     /* T3B02 */
        {0,}
 };
 
@@ -306,6 +306,77 @@ static int request_msix_data_irqs(struct adapter *adap)
        return 0;
 }
 
+static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
+                             unsigned long n)
+{
+       int attempts = 5;
+
+       while (adap->sge.qs[0].rspq.offload_pkts < init_cnt + n) {
+               if (!--attempts)
+                       return -ETIMEDOUT;
+               msleep(10);
+       }
+       return 0;
+}
+
+static int init_tp_parity(struct adapter *adap)
+{
+       int i;
+       struct sk_buff *skb;
+       struct cpl_set_tcb_field *greq;
+       unsigned long cnt = adap->sge.qs[0].rspq.offload_pkts;
+
+       t3_tp_set_offload_mode(adap, 1);
+
+       for (i = 0; i < 16; i++) {
+               struct cpl_smt_write_req *req;
+
+               skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+               req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
+               memset(req, 0, sizeof(*req));
+               req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+               OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, i));
+               req->iff = i;
+               t3_mgmt_tx(adap, skb);
+       }
+
+       for (i = 0; i < 2048; i++) {
+               struct cpl_l2t_write_req *req;
+
+               skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+               req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
+               memset(req, 0, sizeof(*req));
+               req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+               OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, i));
+               req->params = htonl(V_L2T_W_IDX(i));
+               t3_mgmt_tx(adap, skb);
+       }
+
+       for (i = 0; i < 2048; i++) {
+               struct cpl_rte_write_req *req;
+
+               skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+               req = (struct cpl_rte_write_req *)__skb_put(skb, sizeof(*req));
+               memset(req, 0, sizeof(*req));
+               req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+               OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RTE_WRITE_REQ, i));
+               req->l2t_idx = htonl(V_L2T_W_IDX(i));
+               t3_mgmt_tx(adap, skb);
+       }
+
+       skb = alloc_skb(sizeof(*greq), GFP_KERNEL | __GFP_NOFAIL);
+       greq = (struct cpl_set_tcb_field *)__skb_put(skb, sizeof(*greq));
+       memset(greq, 0, sizeof(*greq));
+       greq->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+       OPCODE_TID(greq) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, 0));
+       greq->mask = cpu_to_be64(1);
+       t3_mgmt_tx(adap, skb);
+
+       i = await_mgmt_replies(adap, cnt, 16 + 2048 + 2048 + 1);
+       t3_tp_set_offload_mode(adap, 0);
+       return i;
+}
+
 /**
  *     setup_rss - configure RSS
  *     @adap: the adapter
@@ -336,49 +407,20 @@ static void setup_rss(struct adapter *adap)
 
        t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
                      F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
-                     V_RRCPLCPUSIZE(6), cpus, rspq_map);
+                     V_RRCPLCPUSIZE(6) | F_HASHTOEPLITZ, cpus, rspq_map);
 }
 
-/*
- * If we have multiple receive queues per port serviced by NAPI we need one
- * netdevice per queue as NAPI operates on netdevices.  We already have one
- * netdevice, namely the one associated with the interface, so we use dummy
- * ones for any additional queues.  Note that these netdevices exist purely
- * so that NAPI has something to work with, they do not represent network
- * ports and are not registered.
- */
-static int init_dummy_netdevs(struct adapter *adap)
+static void init_napi(struct adapter *adap)
 {
-       int i, j, dummy_idx = 0;
-       struct net_device *nd;
-
-       for_each_port(adap, i) {
-               struct net_device *dev = adap->port[i];
-               const struct port_info *pi = netdev_priv(dev);
-
-               for (j = 0; j < pi->nqsets - 1; j++) {
-                       if (!adap->dummy_netdev[dummy_idx]) {
-                               nd = alloc_netdev(0, "", ether_setup);
-                               if (!nd)
-                                       goto free_all;
+       int i;
 
-                               nd->priv = adap;
-                               nd->weight = 64;
-                               set_bit(__LINK_STATE_START, &nd->state);
-                               adap->dummy_netdev[dummy_idx] = nd;
-                       }
-                       strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name);
-                       dummy_idx++;
-               }
-       }
-       return 0;
+       for (i = 0; i < SGE_QSETS; i++) {
+               struct sge_qset *qs = &adap->sge.qs[i];
 
-free_all:
-       while (--dummy_idx >= 0) {
-               free_netdev(adap->dummy_netdev[dummy_idx]);
-               adap->dummy_netdev[dummy_idx] = NULL;
+               if (qs->adap)
+                       netif_napi_add(qs->netdev, &qs->napi, qs->napi.poll,
+                                      64);
        }
-       return -ENOMEM;
 }
 
 /*
@@ -389,20 +431,18 @@ free_all:
 static void quiesce_rx(struct adapter *adap)
 {
        int i;
-       struct net_device *dev;
 
-       for_each_port(adap, i) {
-               dev = adap->port[i];
-               while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
-                       msleep(1);
-       }
+       for (i = 0; i < SGE_QSETS; i++)
+               if (adap->sge.qs[i].adap)
+                       napi_disable(&adap->sge.qs[i].napi);
+}
 
-       for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) {
-               dev = adap->dummy_netdev[i];
-               if (dev)
-                       while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
-                               msleep(1);
-       }
+static void enable_all_napi(struct adapter *adap)
+{
+       int i;
+       for (i = 0; i < SGE_QSETS; i++)
+               if (adap->sge.qs[i].adap)
+                       napi_enable(&adap->sge.qs[i].napi);
 }
 
 /**
@@ -415,7 +455,7 @@ static void quiesce_rx(struct adapter *adap)
  */
 static int setup_sge_qsets(struct adapter *adap)
 {
-       int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0;
+       int i, j, err, irq_idx = 0, qset_idx = 0;
        unsigned int ntxq = SGE_TXQ_PER_SET;
 
        if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
@@ -423,15 +463,14 @@ static int setup_sge_qsets(struct adapter *adap)
 
        for_each_port(adap, i) {
                struct net_device *dev = adap->port[i];
-               const struct port_info *pi = netdev_priv(dev);
+               struct port_info *pi = netdev_priv(dev);
 
+               pi->qs = &adap->sge.qs[pi->first_qset];
                for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
                        err = t3_sge_alloc_qset(adap, qset_idx, 1,
                                (adap->flags & USING_MSIX) ? qset_idx + 1 :
                                                             irq_idx,
-                               &adap->params.sge.qset[qset_idx], ntxq,
-                               j == 0 ? dev :
-                                        adap-> dummy_netdev[dummy_dev_idx++]);
+                               &adap->params.sge.qset[qset_idx], ntxq, dev);
                        if (err) {
                                t3_free_sge_resources(adap);
                                return err;
@@ -442,8 +481,7 @@ static int setup_sge_qsets(struct adapter *adap)
        return 0;
 }
 
-static ssize_t attr_show(struct device *d, struct device_attribute *attr,
-                        char *buf,
+static ssize_t attr_show(struct device *d, char *buf,
                         ssize_t(*format) (struct net_device *, char *))
 {
        ssize_t len;
@@ -455,7 +493,7 @@ static ssize_t attr_show(struct device *d, struct device_attribute *attr,
        return len;
 }
 
-static ssize_t attr_store(struct device *d, struct device_attribute *attr,
+static ssize_t attr_store(struct device *d,
                          const char *buf, size_t len,
                          ssize_t(*set) (struct net_device *, unsigned int),
                          unsigned int min_val, unsigned int max_val)
@@ -482,18 +520,20 @@ static ssize_t attr_store(struct device *d, struct device_attribute *attr,
 #define CXGB3_SHOW(name, val_expr) \
 static ssize_t format_##name(struct net_device *dev, char *buf) \
 { \
-       struct adapter *adap = dev->priv; \
+       struct port_info *pi = netdev_priv(dev); \
+       struct adapter *adap = pi->adapter; \
        return sprintf(buf, "%u\n", val_expr); \
 } \
 static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
                           char *buf) \
 { \
-       return attr_show(d, attr, buf, format_##name); \
+       return attr_show(d, buf, format_##name); \
 }
 
 static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
 {
-       struct adapter *adap = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adap = pi->adapter;
        int min_tids = is_offload(adap) ? MC5_MIN_TIDS : 0;
 
        if (adap->flags & FULL_INIT_DONE)
@@ -510,12 +550,13 @@ static ssize_t set_nfilters(struct net_device *dev, unsigned int val)
 static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
                              const char *buf, size_t len)
 {
-       return attr_store(d, attr, buf, len, set_nfilters, 0, ~0);
+       return attr_store(d, buf, len, set_nfilters, 0, ~0);
 }
 
 static ssize_t set_nservers(struct net_device *dev, unsigned int val)
 {
-       struct adapter *adap = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adap = pi->adapter;
 
        if (adap->flags & FULL_INIT_DONE)
                return -EBUSY;
@@ -529,7 +570,7 @@ static ssize_t set_nservers(struct net_device *dev, unsigned int val)
 static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
                              const char *buf, size_t len)
 {
-       return attr_store(d, attr, buf, len, set_nservers, 0, ~0);
+       return attr_store(d, buf, len, set_nservers, 0, ~0);
 }
 
 #define CXGB3_ATTR_R(name, val_expr) \
@@ -553,12 +594,13 @@ static struct attribute *cxgb3_attrs[] = {
 
 static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
 
-static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
+static ssize_t tm_attr_show(struct device *d,
                            char *buf, int sched)
 {
-       ssize_t len;
+       struct port_info *pi = netdev_priv(to_net_dev(d));
+       struct adapter *adap = pi->adapter;
        unsigned int v, addr, bpt, cpt;
-       struct adapter *adap = to_net_dev(d)->priv;
+       ssize_t len;
 
        addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
        rtnl_lock();
@@ -578,13 +620,14 @@ static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
        return len;
 }
 
-static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
+static ssize_t tm_attr_store(struct device *d,
                             const char *buf, size_t len, int sched)
 {
+       struct port_info *pi = netdev_priv(to_net_dev(d));
+       struct adapter *adap = pi->adapter;
+       unsigned int val;
        char *endp;
        ssize_t ret;
-       unsigned int val;
-       struct adapter *adap = to_net_dev(d)->priv;
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
@@ -605,12 +648,12 @@ static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
 static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
                           char *buf) \
 { \
-       return tm_attr_show(d, attr, buf, sched); \
+       return tm_attr_show(d, buf, sched); \
 } \
 static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
                            const char *buf, size_t len) \
 { \
-       return tm_attr_store(d, attr, buf, len, sched); \
+       return tm_attr_store(d, buf, len, sched); \
 } \
 static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
 
@@ -721,6 +764,7 @@ static void bind_qsets(struct adapter *adap)
 }
 
 #define FW_FNAME "t3fw-%d.%d.%d.bin"
+#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
 
 static int upgrade_fw(struct adapter *adap)
 {
@@ -739,6 +783,74 @@ static int upgrade_fw(struct adapter *adap)
        }
        ret = t3_load_fw(adap, fw->data, fw->size);
        release_firmware(fw);
+
+       if (ret == 0)
+               dev_info(dev, "successful upgrade to firmware %d.%d.%d\n",
+                        FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
+       else
+               dev_err(dev, "failed to upgrade to firmware %d.%d.%d\n",
+                       FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
+
+       return ret;
+}
+
+static inline char t3rev2char(struct adapter *adapter)
+{
+       char rev = 0;
+
+       switch(adapter->params.rev) {
+       case T3_REV_B:
+       case T3_REV_B2:
+               rev = 'b';
+               break;
+       case T3_REV_C:
+               rev = 'c';
+               break;
+       }
+       return rev;
+}
+
+static int update_tpsram(struct adapter *adap)
+{
+       const struct firmware *tpsram;
+       char buf[64];
+       struct device *dev = &adap->pdev->dev;
+       int ret;
+       char rev;
+
+       rev = t3rev2char(adap);
+       if (!rev)
+               return 0;
+
+       snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
+                TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+
+       ret = request_firmware(&tpsram, buf, dev);
+       if (ret < 0) {
+               dev_err(dev, "could not load TP SRAM: unable to load %s\n",
+                       buf);
+               return ret;
+       }
+
+       ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
+       if (ret)
+               goto release_tpsram;
+
+       ret = t3_set_proto_sram(adap, tpsram->data);
+       if (ret == 0)
+               dev_info(dev,
+                        "successful update of protocol engine "
+                        "to %d.%d.%d\n",
+                        TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+       else
+               dev_err(dev, "failed to update of protocol engine %d.%d.%d\n",
+                       TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
+       if (ret)
+               dev_err(dev, "loading protocol SRAM failed\n");
+
+release_tpsram:
+       release_firmware(tpsram);
+
        return ret;
 }
 
@@ -754,30 +866,37 @@ static int upgrade_fw(struct adapter *adap)
  */
 static int cxgb_up(struct adapter *adap)
 {
-       int err = 0;
+       int err;
+       int must_load;
 
        if (!(adap->flags & FULL_INIT_DONE)) {
-               err = t3_check_fw_version(adap);
-               if (err == -EINVAL)
+               err = t3_check_fw_version(adap, &must_load);
+               if (err == -EINVAL) {
                        err = upgrade_fw(adap);
-               if (err)
-                       goto out;
+                       if (err && must_load)
+                               goto out;
+               }
 
-               err = init_dummy_netdevs(adap);
-               if (err)
-                       goto out;
+               err = t3_check_tpsram_version(adap, &must_load);
+               if (err == -EINVAL) {
+                       err = update_tpsram(adap);
+                       if (err && must_load)
+                               goto out;
+               }
 
                err = t3_init_hw(adap, 0);
                if (err)
                        goto out;
 
+               t3_set_reg_field(adap, A_TP_PARA_REG5, 0, F_RXDDPOFFINIT);
                t3_write_reg(adap, A_ULPRX_TDDP_PSZ, V_HPZ0(PAGE_SHIFT - 12));
-               
+
                err = setup_sge_qsets(adap);
                if (err)
                        goto out;
 
                setup_rss(adap);
+               init_napi(adap);
                adap->flags |= FULL_INIT_DONE;
        }
 
@@ -791,7 +910,8 @@ static int cxgb_up(struct adapter *adap)
                if (err)
                        goto irq_err;
 
-               if (request_msix_data_irqs(adap)) {
+               err = request_msix_data_irqs(adap);
+               if (err) {
                        free_irq(adap->msix_info[0].vec, adap);
                        goto irq_err;
                }
@@ -804,9 +924,20 @@ static int cxgb_up(struct adapter *adap)
                                      adap->name, adap)))
                goto irq_err;
 
+       enable_all_napi(adap);
        t3_sge_start(adap);
        t3_intr_enable(adap);
 
+       if (adap->params.rev >= T3_REV_C && !(adap->flags & TP_PARITY_INIT) &&
+           is_offload(adap) && init_tp_parity(adap) == 0)
+               adap->flags |= TP_PARITY_INIT;
+
+       if (adap->flags & TP_PARITY_INIT) {
+               t3_write_reg(adap, A_TP_INT_CAUSE,
+                            F_CMCACHEPERR | F_ARPLUTPERR);
+               t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff);
+       }
+
        if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
                bind_qsets(adap);
        adap->flags |= QUEUES_BOUND;
@@ -858,10 +989,11 @@ static void schedule_chk_task(struct adapter *adap)
 
 static int offload_open(struct net_device *dev)
 {
-       struct adapter *adapter = dev->priv;
-       struct t3cdev *tdev = T3CDEV(dev);
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
+       struct t3cdev *tdev = dev2t3cdev(dev);
        int adap_up = adapter->open_device_map & PORT_MASK;
-       int err = 0;
+       int err;
 
        if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
                return 0;
@@ -882,8 +1014,8 @@ static int offload_open(struct net_device *dev)
                     adapter->port[0]->mtu : 0xffff);
        init_smt(adapter);
 
-       /* Never mind if the next step fails */
-       sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group);
+       if (sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group))
+               dev_dbg(&dev->dev, "cannot create sysfs group\n");
 
        /* Call back all registered clients */
        cxgb3_add_clients(tdev);
@@ -924,13 +1056,15 @@ static int offload_close(struct t3cdev *tdev)
 
 static int cxgb_open(struct net_device *dev)
 {
-       int err;
-       struct adapter *adapter = dev->priv;
        struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        int other_ports = adapter->open_device_map & PORT_MASK;
+       int err;
 
-       if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+       if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0) {
+               quiesce_rx(adapter);
                return err;
+       }
 
        set_bit(pi->port_id, &adapter->open_device_map);
        if (is_offload(adapter) && !ofld_disable) {
@@ -951,17 +1085,17 @@ static int cxgb_open(struct net_device *dev)
 
 static int cxgb_close(struct net_device *dev)
 {
-       struct adapter *adapter = dev->priv;
-       struct port_info *p = netdev_priv(dev);
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
 
-       t3_port_intr_disable(adapter, p->port_id);
+       t3_port_intr_disable(adapter, pi->port_id);
        netif_stop_queue(dev);
-       p->phy.ops->power_down(&p->phy, 1);
+       pi->phy.ops->power_down(&pi->phy, 1);
        netif_carrier_off(dev);
-       t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
+       t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
 
        spin_lock(&adapter->work_lock); /* sync with update task */
-       clear_bit(p->port_id, &adapter->open_device_map);
+       clear_bit(pi->port_id, &adapter->open_device_map);
        spin_unlock(&adapter->work_lock);
 
        if (!(adapter->open_device_map & PORT_MASK))
@@ -976,13 +1110,13 @@ static int cxgb_close(struct net_device *dev)
 
 static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
 {
-       struct adapter *adapter = dev->priv;
-       struct port_info *p = netdev_priv(dev);
-       struct net_device_stats *ns = &p->netstats;
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
+       struct net_device_stats *ns = &pi->netstats;
        const struct mac_stats *pstats;
 
        spin_lock(&adapter->stats_lock);
-       pstats = t3_mac_update_stats(&p->mac);
+       pstats = t3_mac_update_stats(&pi->mac);
        spin_unlock(&adapter->stats_lock);
 
        ns->tx_bytes = pstats->tx_octets;
@@ -1015,14 +1149,16 @@ static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
 
 static u32 get_msglevel(struct net_device *dev)
 {
-       struct adapter *adapter = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
 
        return adapter->msg_enable;
 }
 
 static void set_msglevel(struct net_device *dev, u32 val)
 {
-       struct adapter *adapter = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
 
        adapter->msg_enable = val;
 }
@@ -1077,9 +1213,14 @@ static char stats_strings[][ETH_GSTRING_LEN] = {
 
 };
 
-static int get_stats_count(struct net_device *dev)
+static int get_sset_count(struct net_device *dev, int sset)
 {
-       return ARRAY_SIZE(stats_strings);
+       switch (sset) {
+       case ETH_SS_STATS:
+               return ARRAY_SIZE(stats_strings);
+       default:
+               return -EOPNOTSUPP;
+       }
 }
 
 #define T3_REGMAP_SIZE (3 * 1024)
@@ -1096,10 +1237,13 @@ static int get_eeprom_len(struct net_device *dev)
 
 static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        u32 fw_vers = 0;
-       struct adapter *adapter = dev->priv;
+       u32 tp_vers = 0;
 
        t3_get_fw_version(adapter, &fw_vers);
+       t3_get_tp_version(adapter, &tp_vers);
 
        strcpy(info->driver, DRV_NAME);
        strcpy(info->version, DRV_VERSION);
@@ -1108,11 +1252,14 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
                strcpy(info->fw_version, "N/A");
        else {
                snprintf(info->fw_version, sizeof(info->fw_version),
-                        "%s %u.%u.%u",
+                        "%s %u.%u.%u TP %u.%u.%u",
                         G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
                         G_FW_VERSION_MAJOR(fw_vers),
                         G_FW_VERSION_MINOR(fw_vers),
-                        G_FW_VERSION_MICRO(fw_vers));
+                        G_FW_VERSION_MICRO(fw_vers),
+                        G_TP_VERSION_MAJOR(tp_vers),
+                        G_TP_VERSION_MINOR(tp_vers),
+                        G_TP_VERSION_MICRO(tp_vers));
        }
 }
 
@@ -1136,8 +1283,8 @@ static unsigned long collect_sge_port_stats(struct adapter *adapter,
 static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
                      u64 *data)
 {
-       struct adapter *adapter = dev->priv;
        struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        const struct mac_stats *s;
 
        spin_lock(&adapter->stats_lock);
@@ -1205,7 +1352,8 @@ static inline void reg_block_dump(struct adapter *ap, void *buf,
 static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
                     void *buf)
 {
-       struct adapter *ap = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *ap = pi->adapter;
 
        /*
         * Version scheme:
@@ -1246,8 +1394,9 @@ static int restart_autoneg(struct net_device *dev)
 
 static int cxgb3_phys_id(struct net_device *dev, u32 data)
 {
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        int i;
-       struct adapter *adapter = dev->priv;
 
        if (data == 0)
                data = 2;
@@ -1408,8 +1557,8 @@ static int set_rx_csum(struct net_device *dev, u32 data)
 
 static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
 {
-       const struct adapter *adapter = dev->priv;
-       const struct port_info *pi = netdev_priv(dev);
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        const struct qset_params *q = &adapter->params.sge.qset[pi->first_qset];
 
        e->rx_max_pending = MAX_RX_BUFFERS;
@@ -1425,10 +1574,10 @@ static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
 
 static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
 {
-       int i;
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        struct qset_params *q;
-       struct adapter *adapter = dev->priv;
-       const struct port_info *pi = netdev_priv(dev);
+       int i;
 
        if (e->rx_pending > MAX_RX_BUFFERS ||
            e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
@@ -1457,7 +1606,8 @@ static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
 
 static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 {
-       struct adapter *adapter = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        struct qset_params *qsp = &adapter->params.sge.qset[0];
        struct sge_qset *qs = &adapter->sge.qs[0];
 
@@ -1471,7 +1621,8 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 
 static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 {
-       struct adapter *adapter = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        struct qset_params *q = adapter->params.sge.qset;
 
        c->rx_coalesce_usecs = q->coalesce_usecs;
@@ -1481,8 +1632,9 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
                      u8 * data)
 {
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        int i, err = 0;
-       struct adapter *adapter = dev->priv;
 
        u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
        if (!buf)
@@ -1490,7 +1642,7 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
 
        e->magic = EEPROM_MAGIC;
        for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
-               err = t3_seeprom_read(adapter, i, (u32 *) & buf[i]);
+               err = t3_seeprom_read(adapter, i, (__le32 *) & buf[i]);
 
        if (!err)
                memcpy(data, buf + e->offset, e->len);
@@ -1501,10 +1653,12 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
 static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                      u8 * data)
 {
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
+       u32 aligned_offset, aligned_len;
+       __le32 *p;
        u8 *buf;
-       int err = 0;
-       u32 aligned_offset, aligned_len, *p;
-       struct adapter *adapter = dev->priv;
+       int err;
 
        if (eeprom->magic != EEPROM_MAGIC)
                return -EINVAL;
@@ -1516,11 +1670,11 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                buf = kmalloc(aligned_len, GFP_KERNEL);
                if (!buf)
                        return -ENOMEM;
-               err = t3_seeprom_read(adapter, aligned_offset, (u32 *) buf);
+               err = t3_seeprom_read(adapter, aligned_offset, (__le32 *) buf);
                if (!err && aligned_len > 4)
                        err = t3_seeprom_read(adapter,
                                              aligned_offset + aligned_len - 4,
-                                             (u32 *) & buf[aligned_len - 4]);
+                                             (__le32 *) & buf[aligned_len - 4]);
                if (err)
                        goto out;
                memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
@@ -1531,7 +1685,7 @@ static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        if (err)
                goto out;
 
-       for (p = (u32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
+       for (p = (__le32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
                err = t3_seeprom_write(adapter, aligned_offset, *p);
                aligned_offset += 4;
        }
@@ -1568,20 +1722,17 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
        .set_pauseparam = set_pauseparam,
        .get_rx_csum = get_rx_csum,
        .set_rx_csum = set_rx_csum,
-       .get_tx_csum = ethtool_op_get_tx_csum,
        .set_tx_csum = ethtool_op_set_tx_csum,
-       .get_sg = ethtool_op_get_sg,
        .set_sg = ethtool_op_set_sg,
        .get_link = ethtool_op_get_link,
        .get_strings = get_strings,
        .phys_id = cxgb3_phys_id,
        .nway_reset = restart_autoneg,
-       .get_stats_count = get_stats_count,
+       .get_sset_count = get_sset_count,
        .get_ethtool_stats = get_stats,
        .get_regs_len = get_regs_len,
        .get_regs = get_regs,
        .get_wol = get_wol,
-       .get_tso = ethtool_op_get_tso,
        .set_tso = ethtool_op_set_tso,
 };
 
@@ -1592,9 +1743,10 @@ static int in_range(int val, int lo, int hi)
 
 static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
 {
-       int ret;
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        u32 cmd;
-       struct adapter *adapter = dev->priv;
+       int ret;
 
        if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
                return -EFAULT;
@@ -1700,7 +1852,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
        }
        case CHELSIO_SET_QSET_NUM:{
                struct ch_reg edata;
-               struct port_info *pi = netdev_priv(dev);
                unsigned int i, first_qset = 0, other_qsets = 0;
 
                if (!capable(CAP_NET_ADMIN))
@@ -1732,7 +1883,6 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
        }
        case CHELSIO_GET_QSET_NUM:{
                struct ch_reg edata;
-               struct port_info *pi = netdev_priv(dev);
 
                edata.cmd = CHELSIO_GET_QSET_NUM;
                edata.val = pi->nqsets;
@@ -1923,10 +2073,10 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
 
 static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
 {
-       int ret, mmd;
-       struct adapter *adapter = dev->priv;
-       struct port_info *pi = netdev_priv(dev);
        struct mii_ioctl_data *data = if_mii(req);
+       struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
+       int ret, mmd;
 
        switch (cmd) {
        case SIOCGMIIPHY:
@@ -1994,9 +2144,9 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
 
 static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
 {
-       int ret;
-       struct adapter *adapter = dev->priv;
        struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
+       int ret;
 
        if (new_mtu < 81)       /* accommodate SACK */
                return -EINVAL;
@@ -2013,8 +2163,8 @@ static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
 
 static int cxgb_set_mac_addr(struct net_device *dev, void *p)
 {
-       struct adapter *adapter = dev->priv;
        struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        struct sockaddr *addr = p;
 
        if (!is_valid_ether_addr(addr->sa_data))
@@ -2050,8 +2200,8 @@ static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
 
 static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 {
-       struct adapter *adapter = dev->priv;
        struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
 
        pi->vlan_grp = grp;
        if (adapter->params.rev > 0)
@@ -2070,14 +2220,14 @@ static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void cxgb_netpoll(struct net_device *dev)
 {
-       struct adapter *adapter = dev->priv;
        struct port_info *pi = netdev_priv(dev);
+       struct adapter *adapter = pi->adapter;
        int qidx;
 
        for (qidx = pi->first_qset; qidx < pi->first_qset + pi->nqsets; qidx++) {
                struct sge_qset *qs = &adapter->sge.qs[qidx];
                void *source;
-               
+
                if (adapter->flags & USING_MSIX)
                        source = qs;
                else
@@ -2088,42 +2238,6 @@ static void cxgb_netpoll(struct net_device *dev)
 }
 #endif
 
-#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin"
-int update_tpsram(struct adapter *adap)
-{
-       const struct firmware *tpsram;
-       char buf[64];
-       struct device *dev = &adap->pdev->dev;
-       int ret;
-       char rev;
-       
-       rev = adap->params.rev == T3_REV_B2 ? 'b' : 'a';
-
-       snprintf(buf, sizeof(buf), TPSRAM_NAME, rev,
-                TP_VERSION_MAJOR, TP_VERSION_MINOR, TP_VERSION_MICRO);
-
-       ret = request_firmware(&tpsram, buf, dev);
-       if (ret < 0) {
-               dev_err(dev, "could not load TP SRAM: unable to load %s\n",
-                       buf);
-               return ret;
-       }
-       
-       ret = t3_check_tpsram(adap, tpsram->data, tpsram->size);
-       if (ret)
-               goto release_tpsram;    
-
-       ret = t3_set_proto_sram(adap, tpsram->data);
-       if (ret)
-               dev_err(dev, "loading protocol SRAM failed\n");
-
-release_tpsram:
-       release_firmware(tpsram);
-       
-       return ret;
-}
-
-
 /*
  * Periodic accumulation of MAC statistics.
  */
@@ -2270,6 +2384,10 @@ void t3_fatal_err(struct adapter *adapter)
 
        if (adapter->flags & FULL_INIT_DONE) {
                t3_sge_stop(adapter);
+               t3_write_reg(adapter, A_XGM_TX_CTRL, 0);
+               t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
+               t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
+               t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
                t3_intr_disable(adapter);
        }
        CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
@@ -2280,6 +2398,106 @@ void t3_fatal_err(struct adapter *adapter)
 
 }
 
+/**
+ * t3_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
+                                            pci_channel_state_t state)
+{
+       struct adapter *adapter = pci_get_drvdata(pdev);
+       int i;
+
+       /* Stop all ports */
+       for_each_port(adapter, i) {
+               struct net_device *netdev = adapter->port[i];
+
+               if (netif_running(netdev))
+                       cxgb_close(netdev);
+       }
+
+       if (is_offload(adapter) &&
+           test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+               offload_close(&adapter->tdev);
+
+       /* Free sge resources */
+       t3_free_sge_resources(adapter);
+
+       adapter->flags &= ~FULL_INIT_DONE;
+
+       pci_disable_device(pdev);
+
+       /* Request a slot slot reset. */
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/**
+ * t3_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot.
+ */
+static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev)
+{
+       struct adapter *adapter = pci_get_drvdata(pdev);
+
+       if (pci_enable_device(pdev)) {
+               dev_err(&pdev->dev,
+                       "Cannot re-enable PCI device after reset.\n");
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+       pci_set_master(pdev);
+
+       t3_prep_adapter(adapter, adapter->params.info, 1);
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * t3_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation.
+ */
+static void t3_io_resume(struct pci_dev *pdev)
+{
+       struct adapter *adapter = pci_get_drvdata(pdev);
+       int i;
+
+       /* Restart the ports */
+       for_each_port(adapter, i) {
+               struct net_device *netdev = adapter->port[i];
+
+               if (netif_running(netdev)) {
+                       if (cxgb_open(netdev)) {
+                               dev_err(&pdev->dev,
+                                       "can't bring device back up"
+                                       " after reset\n");
+                               continue;
+                       }
+                       netif_device_attach(netdev);
+               }
+       }
+
+       if (is_offload(adapter)) {
+               __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
+               if (offload_open(adapter->port[0]))
+                       printk(KERN_WARNING
+                              "Could not bring back offload capabilities\n");
+       }
+}
+
+static struct pci_error_handlers t3_err_handler = {
+       .error_detected = t3_io_error_detected,
+       .slot_reset = t3_io_slot_reset,
+       .resume = t3_io_resume,
+};
+
 static int __devinit cxgb_enable_msix(struct adapter *adap)
 {
        struct msix_entry entries[SGE_QSETS + 1];
@@ -2329,10 +2547,12 @@ static void __devinit print_port_info(struct adapter *adap,
                       (adap->flags & USING_MSIX) ? " MSI-X" :
                       (adap->flags & USING_MSI) ? " MSI" : "");
                if (adap->name == dev->name && adap->params.vpd.mclk)
-                       printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n",
+                       printk(KERN_INFO
+                              "%s: %uMB CM, %uMB PMTX, %uMB PMRX, S/N: %s\n",
                               adap->name, t3_mc7_size(&adap->cm) >> 20,
                               t3_mc7_size(&adap->pmtx) >> 20,
-                              t3_mc7_size(&adap->pmrx) >> 20);
+                              t3_mc7_size(&adap->pmrx) >> 20,
+                              adap->params.vpd.sn);
        }
 }
 
@@ -2428,11 +2648,11 @@ static int __devinit init_one(struct pci_dev *pdev,
                        goto out_free_dev;
                }
 
-               SET_MODULE_OWNER(netdev);
                SET_NETDEV_DEV(netdev, &pdev->dev);
 
                adapter->port[i] = netdev;
                pi = netdev_priv(netdev);
+               pi->adapter = adapter;
                pi->rx_csum_offload = 1;
                pi->nqsets = 1;
                pi->first_qset = i;
@@ -2442,7 +2662,6 @@ static int __devinit init_one(struct pci_dev *pdev,
                netdev->irq = pdev->irq;
                netdev->mem_start = mmio_start;
                netdev->mem_end = mmio_start + mmio_len - 1;
-               netdev->priv = adapter;
                netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
                netdev->features |= NETIF_F_LLTX;
                if (pci_using_dac)
@@ -2462,24 +2681,16 @@ static int __devinit init_one(struct pci_dev *pdev,
 #ifdef CONFIG_NET_POLL_CONTROLLER
                netdev->poll_controller = cxgb_netpoll;
 #endif
-               netdev->weight = 64;
 
                SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
        }
 
-       pci_set_drvdata(pdev, adapter->port[0]);
+       pci_set_drvdata(pdev, adapter);
        if (t3_prep_adapter(adapter, ai, 1) < 0) {
                err = -ENODEV;
                goto out_free_dev;
        }
 
-       err = t3_check_tpsram_version(adapter);
-       if (err == -EINVAL)
-               err = update_tpsram(adapter);
-
-       if (err)
-               goto out_free_dev;
-               
        /*
         * The card is now ready to go.  If any errors occur during device
         * registration we do not fail the whole card but rather proceed only
@@ -2547,20 +2758,15 @@ out_release_regions:
 
 static void __devexit remove_one(struct pci_dev *pdev)
 {
-       struct net_device *dev = pci_get_drvdata(pdev);
+       struct adapter *adapter = pci_get_drvdata(pdev);
 
-       if (dev) {
+       if (adapter) {
                int i;
-               struct adapter *adapter = dev->priv;
 
                t3_sge_stop(adapter);
                sysfs_remove_group(&adapter->port[0]->dev.kobj,
                                   &cxgb3_attr_group);
 
-               for_each_port(adapter, i)
-                   if (test_bit(i, &adapter->registered_device_map))
-                       unregister_netdev(adapter->port[i]);
-
                if (is_offload(adapter)) {
                        cxgb3_adapter_unofld(adapter);
                        if (test_bit(OFFLOAD_DEVMAP_BIT,
@@ -2568,15 +2774,13 @@ static void __devexit remove_one(struct pci_dev *pdev)
                                offload_close(&adapter->tdev);
                }
 
+               for_each_port(adapter, i)
+                   if (test_bit(i, &adapter->registered_device_map))
+                       unregister_netdev(adapter->port[i]);
+
                t3_free_sge_resources(adapter);
                cxgb_disable_msi(adapter);
 
-               for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++)
-                       if (adapter->dummy_netdev[i]) {
-                               free_netdev(adapter->dummy_netdev[i]);
-                               adapter->dummy_netdev[i] = NULL;
-                       }
-
                for_each_port(adapter, i)
                        if (adapter->port[i])
                                free_netdev(adapter->port[i]);
@@ -2594,6 +2798,7 @@ static struct pci_driver driver = {
        .id_table = cxgb3_pci_tbl,
        .probe = init_one,
        .remove = __devexit_p(remove_one),
+       .err_handler = &t3_err_handler,
 };
 
 static int __init cxgb3_init_module(void)