]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/net/cxgb3/cxgb3_main.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
[net-next-2.6.git] / drivers / net / cxgb3 / cxgb3_main.c
index c97ab82ec743b5edd1371dcdf3d3e64afc198dfd..34e776c5f06b4391e1a7bf42ff1cffb72c8b9ce7 100644 (file)
@@ -172,6 +172,23 @@ static void link_report(struct net_device *dev)
        }
 }
 
+static void enable_tx_fifo_drain(struct adapter *adapter,
+                                struct port_info *pi)
+{
+       t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset, 0,
+                        F_ENDROPPKT);
+       t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, 0);
+       t3_write_reg(adapter, A_XGM_TX_CTRL + pi->mac.offset, F_TXEN);
+       t3_write_reg(adapter, A_XGM_RX_CTRL + pi->mac.offset, F_RXEN);
+}
+
+static void disable_tx_fifo_drain(struct adapter *adapter,
+                                 struct port_info *pi)
+{
+       t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + pi->mac.offset,
+                        F_ENDROPPKT, 0);
+}
+
 void t3_os_link_fault(struct adapter *adap, int port_id, int state)
 {
        struct net_device *dev = adap->port[port_id];
@@ -185,6 +202,8 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state)
 
                netif_carrier_on(dev);
 
+               disable_tx_fifo_drain(adap, pi);
+
                /* Clear local faults */
                t3_xgm_intr_disable(adap, pi->port_id);
                t3_read_reg(adap, A_XGM_INT_STATUS +
@@ -200,9 +219,12 @@ void t3_os_link_fault(struct adapter *adap, int port_id, int state)
                t3_xgm_intr_enable(adap, pi->port_id);
 
                t3_mac_enable(mac, MAC_DIRECTION_TX);
-       } else
+       } else {
                netif_carrier_off(dev);
 
+               /* Flush TX FIFO */
+               enable_tx_fifo_drain(adap, pi);
+       }
        link_report(dev);
 }
 
@@ -232,6 +254,8 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
 
        if (link_stat != netif_carrier_ok(dev)) {
                if (link_stat) {
+                       disable_tx_fifo_drain(adapter, pi);
+
                        t3_mac_enable(mac, MAC_DIRECTION_RX);
 
                        /* Clear local faults */
@@ -263,6 +287,9 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
                        t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
                        t3_mac_disable(mac, MAC_DIRECTION_RX);
                        t3_link_start(&pi->phy, mac, &pi->link_config);
+
+                       /* Flush TX FIFO */
+                       enable_tx_fifo_drain(adapter, pi);
                }
 
                link_report(dev);
@@ -443,6 +470,7 @@ static int init_tp_parity(struct adapter *adap)
                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->mtu_idx = NMTUS - 1;
                req->iff = i;
                t3_mgmt_tx(adap, skb);
                if (skb == adap->nofail_skb) {
@@ -963,6 +991,75 @@ static int bind_qsets(struct adapter *adap)
 
 #define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin"
 #define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin"
+#define AEL2005_OPT_EDC_NAME "cxgb3/ael2005_opt_edc.bin"
+#define AEL2005_TWX_EDC_NAME "cxgb3/ael2005_twx_edc.bin"
+#define AEL2020_TWX_EDC_NAME "cxgb3/ael2020_twx_edc.bin"
+
+static inline const char *get_edc_fw_name(int edc_idx)
+{
+       const char *fw_name = NULL;
+
+       switch (edc_idx) {
+       case EDC_OPT_AEL2005:
+               fw_name = AEL2005_OPT_EDC_NAME;
+               break;
+       case EDC_TWX_AEL2005:
+               fw_name = AEL2005_TWX_EDC_NAME;
+               break;
+       case EDC_TWX_AEL2020:
+               fw_name = AEL2020_TWX_EDC_NAME;
+               break;
+       }
+       return fw_name;
+}
+
+int t3_get_edc_fw(struct cphy *phy, int edc_idx, int size)
+{
+       struct adapter *adapter = phy->adapter;
+       const struct firmware *fw;
+       char buf[64];
+       u32 csum;
+       const __be32 *p;
+       u16 *cache = phy->phy_cache;
+       int i, ret;
+
+       snprintf(buf, sizeof(buf), get_edc_fw_name(edc_idx));
+
+       ret = request_firmware(&fw, buf, &adapter->pdev->dev);
+       if (ret < 0) {
+               dev_err(&adapter->pdev->dev,
+                       "could not upgrade firmware: unable to load %s\n",
+                       buf);
+               return ret;
+       }
+
+       /* check size, take checksum in account */
+       if (fw->size > size + 4) {
+               CH_ERR(adapter, "firmware image too large %u, expected %d\n",
+                      (unsigned int)fw->size, size + 4);
+               ret = -EINVAL;
+       }
+
+       /* compute checksum */
+       p = (const __be32 *)fw->data;
+       for (csum = 0, i = 0; i < fw->size / sizeof(csum); i++)
+               csum += ntohl(p[i]);
+
+       if (csum != 0xffffffff) {
+               CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
+                      csum);
+               ret = -EINVAL;
+       }
+
+       for (i = 0; i < size / 4 ; i++) {
+               *cache++ = (be32_to_cpu(p[i]) & 0xffff0000) >> 16;
+               *cache++ = be32_to_cpu(p[i]) & 0xffff;
+       }
+
+       release_firmware(fw);
+
+       return ret;
+}
 
 static int upgrade_fw(struct adapter *adap)
 {