]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/tg3.c
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6-omap-h63xx.git] / drivers / net / tg3.c
index a2ca6ab2df00c03d374c98c86b5c560c5fdab03c..f7efcecc4108f44e8fcdb26a83bb653a17660a36 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
  * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
  * Copyright (C) 2004 Sun Microsystems Inc.
- * Copyright (C) 2005-2007 Broadcom Corporation.
+ * Copyright (C) 2005-2009 Broadcom Corporation.
  *
  * Firmware is:
  *     Derived from proprietary unpublished source code,
@@ -68,8 +68,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.97"
-#define DRV_MODULE_RELDATE     "December 10, 2008"
+#define DRV_MODULE_VERSION     "3.98"
+#define DRV_MODULE_RELDATE     "February 25, 2009"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -2283,22 +2283,13 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
        return ret;
 }
 
-static int tg3_nvram_read_swab(struct tg3 *tp, u32 offset, u32 *val)
-{
-       int err;
-       u32 tmp;
-
-       err = tg3_nvram_read(tp, offset, &tmp);
-       *val = swab32(tmp);
-       return err;
-}
-
-static int tg3_nvram_read_le(struct tg3 *tp, u32 offset, __le32 *val)
+/* Ensures NVRAM data is in bytestream format. */
+static int tg3_nvram_read_be32(struct tg3 *tp, u32 offset, __be32 *val)
 {
        u32 v;
-       int res = tg3_nvram_read_swab(tp, offset, &v);
+       int res = tg3_nvram_read(tp, offset, &v);
        if (!res)
-               *val = cpu_to_le32(v);
+               *val = cpu_to_be32(v);
        return res;
 }
 
@@ -8539,7 +8530,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        int ret;
        u8  *pd;
        u32 i, offset, len, b_offset, b_count;
-       __le32 val;
+       __be32 val;
 
        if (tp->link_config.phy_is_low_power)
                return -EAGAIN;
@@ -8558,7 +8549,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                        /* i.e. offset=1 len=2 */
                        b_count = len;
                }
-               ret = tg3_nvram_read_le(tp, offset-b_offset, &val);
+               ret = tg3_nvram_read_be32(tp, offset-b_offset, &val);
                if (ret)
                        return ret;
                memcpy(data, ((char*)&val) + b_offset, b_count);
@@ -8570,7 +8561,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        /* read bytes upto the last 4 byte boundary */
        pd = &data[eeprom->len];
        for (i = 0; i < (len - (len & 3)); i += 4) {
-               ret = tg3_nvram_read_le(tp, offset + i, &val);
+               ret = tg3_nvram_read_be32(tp, offset + i, &val);
                if (ret) {
                        eeprom->len += i;
                        return ret;
@@ -8584,7 +8575,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                pd = &data[eeprom->len];
                b_count = len & 3;
                b_offset = offset + len - b_count;
-               ret = tg3_nvram_read_le(tp, b_offset, &val);
+               ret = tg3_nvram_read_be32(tp, b_offset, &val);
                if (ret)
                        return ret;
                memcpy(pd, &val, b_count);
@@ -8601,7 +8592,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        int ret;
        u32 offset, len, b_offset, odd_len;
        u8 *buf;
-       __le32 start, end;
+       __be32 start, end;
 
        if (tp->link_config.phy_is_low_power)
                return -EAGAIN;
@@ -8614,7 +8605,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 
        if ((b_offset = (offset & 3))) {
                /* adjustments to start on required 4 byte boundary */
-               ret = tg3_nvram_read_le(tp, offset-b_offset, &start);
+               ret = tg3_nvram_read_be32(tp, offset-b_offset, &start);
                if (ret)
                        return ret;
                len += b_offset;
@@ -8628,7 +8619,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                /* adjustments to end on required 4 byte boundary */
                odd_len = 1;
                len = (len + 3) & ~3;
-               ret = tg3_nvram_read_le(tp, offset+len-4, &end);
+               ret = tg3_nvram_read_be32(tp, offset+len-4, &end);
                if (ret)
                        return ret;
        }
@@ -9200,7 +9191,7 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
 static int tg3_test_nvram(struct tg3 *tp)
 {
        u32 csum, magic;
-       __le32 *buf;
+       __be32 *buf;
        int i, j, k, err = 0, size;
 
        if (tg3_nvram_read(tp, 0, &magic) != 0)
@@ -9237,14 +9228,15 @@ static int tg3_test_nvram(struct tg3 *tp)
 
        err = -EIO;
        for (i = 0, j = 0; i < size; i += 4, j++) {
-               if ((err = tg3_nvram_read_le(tp, i, &buf[j])) != 0)
+               err = tg3_nvram_read_be32(tp, i, &buf[j]);
+               if (err)
                        break;
        }
        if (i < size)
                goto out;
 
        /* Selfboot format */
-       magic = swab32(le32_to_cpu(buf[0]));
+       magic = be32_to_cpu(buf[0]);
        if ((magic & TG3_EEPROM_MAGIC_FW_MSK) ==
            TG3_EEPROM_MAGIC_FW) {
                u8 *buf8 = (u8 *) buf, csum8 = 0;
@@ -9273,7 +9265,7 @@ static int tg3_test_nvram(struct tg3 *tp)
        if ((magic & TG3_EEPROM_MAGIC_HW_MSK) ==
            TG3_EEPROM_MAGIC_HW) {
                u8 data[NVRAM_SELFBOOT_DATA_SIZE];
-               u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
+               u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
                u8 *buf8 = (u8 *) buf;
 
                /* Separate the parity bits and the data bytes.  */
@@ -9316,13 +9308,13 @@ static int tg3_test_nvram(struct tg3 *tp)
 
        /* Bootstrap checksum at offset 0x10 */
        csum = calc_crc((unsigned char *) buf, 0x10);
-       if(csum != le32_to_cpu(buf[0x10/4]))
+       if (csum != be32_to_cpu(buf[0x10/4]))
                goto out;
 
        /* Manufacturing block starts at offset 0x74, checksum at 0xfc */
        csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88);
-       if (csum != le32_to_cpu(buf[0xfc/4]))
-                goto out;
+       if (csum != be32_to_cpu(buf[0xfc/4]))
+               goto out;
 
        err = 0;
 
@@ -10193,9 +10185,20 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp)
                return;
        }
 
-       if (tg3_nvram_read_swab(tp, 0xf0, &val) == 0) {
+       if (tg3_nvram_read(tp, 0xf0, &val) == 0) {
                if (val != 0) {
-                       tp->nvram_size = (val >> 16) * 1024;
+                       /* This is confusing.  We want to operate on the
+                        * 16-bit value at offset 0xf2.  The tg3_nvram_read()
+                        * call will read from NVRAM and byteswap the data
+                        * according to the byteswapping settings for all
+                        * other register accesses.  This ensures the data we
+                        * want will always reside in the lower 16-bits.
+                        * However, the data in NVRAM is in LE format, which
+                        * means the data from the NVRAM read will always be
+                        * opposite the endianness of the CPU.  The 16-bit
+                        * byteswap then brings the data to CPU endianness.
+                        */
+                       tp->nvram_size = swab16((u16)(val & 0x0000ffff)) * 1024;
                        return;
                }
        }
@@ -10654,13 +10657,13 @@ static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
 
        for (i = 0; i < len; i += 4) {
                u32 addr;
-               __le32 data;
+               __be32 data;
 
                addr = offset + i;
 
                memcpy(&data, buf + i, 4);
 
-               tw32(GRC_EEPROM_DATA, le32_to_cpu(data));
+               tw32(GRC_EEPROM_DATA, be32_to_cpu(data));
 
                val = tr32(GRC_EEPROM_ADDR);
                tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE);
@@ -10710,8 +10713,9 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
                phy_addr = offset & ~pagemask;
 
                for (j = 0; j < pagesize; j += 4) {
-                       if ((ret = tg3_nvram_read_le(tp, phy_addr + j,
-                                               (__le32 *) (tmp + j))))
+                       ret = tg3_nvram_read_be32(tp, phy_addr + j,
+                                                 (__be32 *) (tmp + j));
+                       if (ret)
                                break;
                }
                if (ret)
@@ -10758,7 +10762,7 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
                        __be32 data;
 
                        data = *((__be32 *) (tmp + j));
-                       /* swab32(le32_to_cpu(data)), actually */
+
                        tw32(NVRAM_WRDATA, be32_to_cpu(data));
 
                        tw32(NVRAM_ADDR, phy_addr + j);
@@ -11344,7 +11348,7 @@ skip_phy_reset:
 
 static void __devinit tg3_read_partno(struct tg3 *tp)
 {
-       unsigned char vpd_data[256];
+       unsigned char vpd_data[256];   /* in little-endian format */
        unsigned int i;
        u32 magic;
 
@@ -11355,13 +11359,14 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
                for (i = 0; i < 256; i += 4) {
                        u32 tmp;
 
-                       if (tg3_nvram_read_swab(tp, 0x100 + i, &tmp))
+                       /* The data is in little-endian format in NVRAM.
+                        * Use the big-endian read routines to preserve
+                        * the byte order as it exists in NVRAM.
+                        */
+                       if (tg3_nvram_read_be32(tp, 0x100 + i, &tmp))
                                goto out_not_found;
 
-                       vpd_data[i + 0] = ((tmp >>  0) & 0xff);
-                       vpd_data[i + 1] = ((tmp >>  8) & 0xff);
-                       vpd_data[i + 2] = ((tmp >> 16) & 0xff);
-                       vpd_data[i + 3] = ((tmp >> 24) & 0xff);
+                       memcpy(&vpd_data[i], &tmp, sizeof(tmp));
                }
        } else {
                int vpd_cap;
@@ -11387,7 +11392,7 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
                        pci_read_config_dword(tp->pdev, vpd_cap + PCI_VPD_DATA,
                                              &tmp);
                        v = cpu_to_le32(tmp);
-                       memcpy(&vpd_data[i], &v, 4);
+                       memcpy(&vpd_data[i], &v, sizeof(v));
                }
        }
 
@@ -11456,6 +11461,70 @@ static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset)
        return 1;
 }
 
+static void __devinit tg3_read_bc_ver(struct tg3 *tp)
+{
+       u32 val, offset, start, ver_offset;
+       int i;
+       bool newver = false;
+
+       if (tg3_nvram_read(tp, 0xc, &offset) ||
+           tg3_nvram_read(tp, 0x4, &start))
+               return;
+
+       offset = tg3_nvram_logical_addr(tp, offset);
+
+       if (tg3_nvram_read(tp, offset, &val))
+               return;
+
+       if ((val & 0xfc000000) == 0x0c000000) {
+               if (tg3_nvram_read(tp, offset + 4, &val))
+                       return;
+
+               if (val == 0)
+                       newver = true;
+       }
+
+       if (newver) {
+               if (tg3_nvram_read(tp, offset + 8, &ver_offset))
+                       return;
+
+               offset = offset + ver_offset - start;
+               for (i = 0; i < 16; i += 4) {
+                       __be32 v;
+                       if (tg3_nvram_read_be32(tp, offset + i, &v))
+                               return;
+
+                       memcpy(tp->fw_ver + i, &v, sizeof(v));
+               }
+       } else {
+               u32 major, minor;
+
+               if (tg3_nvram_read(tp, TG3_NVM_PTREV_BCVER, &ver_offset))
+                       return;
+
+               major = (ver_offset & TG3_NVM_BCVER_MAJMSK) >>
+                       TG3_NVM_BCVER_MAJSFT;
+               minor = ver_offset & TG3_NVM_BCVER_MINMSK;
+               snprintf(&tp->fw_ver[0], 32, "v%d.%02d", major, minor);
+       }
+}
+
+static void __devinit tg3_read_hwsb_ver(struct tg3 *tp)
+{
+       u32 val, major, minor;
+
+       /* Use native endian representation */
+       if (tg3_nvram_read(tp, TG3_NVM_HWSB_CFG1, &val))
+               return;
+
+       major = (val & TG3_NVM_HWSB_CFG1_MAJMSK) >>
+               TG3_NVM_HWSB_CFG1_MAJSFT;
+       minor = (val & TG3_NVM_HWSB_CFG1_MINMSK) >>
+               TG3_NVM_HWSB_CFG1_MINSFT;
+
+       snprintf(&tp->fw_ver[0], 32, "sb v%d.%02d", major, minor);
+}
+
 static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val)
 {
        u32 offset, major, minor, build;
@@ -11501,44 +11570,10 @@ static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val)
        }
 }
 
-static void __devinit tg3_read_fw_ver(struct tg3 *tp)
+static void __devinit tg3_read_mgmtfw_ver(struct tg3 *tp)
 {
        u32 val, offset, start;
-       u32 ver_offset;
-       int i, bcnt;
-
-       if (tg3_nvram_read(tp, 0, &val))
-               return;
-
-       if (val != TG3_EEPROM_MAGIC) {
-               if ((val & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW)
-                       tg3_read_sb_ver(tp, val);
-
-               return;
-       }
-
-       if (tg3_nvram_read(tp, 0xc, &offset) ||
-           tg3_nvram_read(tp, 0x4, &start))
-               return;
-
-       offset = tg3_nvram_logical_addr(tp, offset);
-
-       if (!tg3_fw_img_is_valid(tp, offset) ||
-           tg3_nvram_read(tp, offset + 8, &ver_offset))
-               return;
-
-       offset = offset + ver_offset - start;
-       for (i = 0; i < 16; i += 4) {
-               __le32 v;
-               if (tg3_nvram_read_le(tp, offset + i, &v))
-                       return;
-
-               memcpy(tp->fw_ver + i, &v, 4);
-       }
-
-       if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
-            (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
-               return;
+       int i, vlen;
 
        for (offset = TG3_NVM_DIR_START;
             offset < TG3_NVM_DIR_END;
@@ -11565,26 +11600,77 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
 
        offset += val - start;
 
-       bcnt = strlen(tp->fw_ver);
+       vlen = strlen(tp->fw_ver);
 
-       tp->fw_ver[bcnt++] = ',';
-       tp->fw_ver[bcnt++] = ' ';
+       tp->fw_ver[vlen++] = ',';
+       tp->fw_ver[vlen++] = ' ';
 
        for (i = 0; i < 4; i++) {
-               __le32 v;
-               if (tg3_nvram_read_le(tp, offset, &v))
+               __be32 v;
+               if (tg3_nvram_read_be32(tp, offset, &v))
                        return;
 
                offset += sizeof(v);
 
-               if (bcnt > TG3_VER_SIZE - sizeof(v)) {
-                       memcpy(&tp->fw_ver[bcnt], &v, TG3_VER_SIZE - bcnt);
+               if (vlen > TG3_VER_SIZE - sizeof(v)) {
+                       memcpy(&tp->fw_ver[vlen], &v, TG3_VER_SIZE - vlen);
                        break;
                }
 
-               memcpy(&tp->fw_ver[bcnt], &v, sizeof(v));
-               bcnt += sizeof(v);
+               memcpy(&tp->fw_ver[vlen], &v, sizeof(v));
+               vlen += sizeof(v);
        }
+}
+
+static void __devinit tg3_read_dash_ver(struct tg3 *tp)
+{
+       int vlen;
+       u32 apedata;
+
+       if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) ||
+           !(tp->tg3_flags  & TG3_FLAG_ENABLE_ASF))
+               return;
+
+       apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
+       if (apedata != APE_SEG_SIG_MAGIC)
+               return;
+
+       apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
+       if (!(apedata & APE_FW_STATUS_READY))
+               return;
+
+       apedata = tg3_ape_read32(tp, TG3_APE_FW_VERSION);
+
+       vlen = strlen(tp->fw_ver);
+
+       snprintf(&tp->fw_ver[vlen], TG3_VER_SIZE - vlen, " DASH v%d.%d.%d.%d",
+                (apedata & APE_FW_VERSION_MAJMSK) >> APE_FW_VERSION_MAJSFT,
+                (apedata & APE_FW_VERSION_MINMSK) >> APE_FW_VERSION_MINSFT,
+                (apedata & APE_FW_VERSION_REVMSK) >> APE_FW_VERSION_REVSFT,
+                (apedata & APE_FW_VERSION_BLDMSK));
+}
+
+static void __devinit tg3_read_fw_ver(struct tg3 *tp)
+{
+       u32 val;
+
+       if (tg3_nvram_read(tp, 0, &val))
+               return;
+
+       if (val == TG3_EEPROM_MAGIC)
+               tg3_read_bc_ver(tp);
+       else if ((val & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW)
+               tg3_read_sb_ver(tp, val);
+       else if ((val & TG3_EEPROM_MAGIC_HW_MSK) == TG3_EEPROM_MAGIC_HW)
+               tg3_read_hwsb_ver(tp);
+       else
+               return;
+
+       if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+            (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+               return;
+
+       tg3_read_mgmtfw_ver(tp);
 
        tp->fw_ver[TG3_VER_SIZE - 1] = 0;
 }
@@ -12355,14 +12441,10 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
        }
        if (!addr_ok) {
                /* Next, try NVRAM. */
-               if (!tg3_nvram_read_swab(tp, mac_offset + 0, &hi) &&
-                   !tg3_nvram_read_swab(tp, mac_offset + 4, &lo)) {
-                       dev->dev_addr[0] = ((hi >> 16) & 0xff);
-                       dev->dev_addr[1] = ((hi >> 24) & 0xff);
-                       dev->dev_addr[2] = ((lo >>  0) & 0xff);
-                       dev->dev_addr[3] = ((lo >>  8) & 0xff);
-                       dev->dev_addr[4] = ((lo >> 16) & 0xff);
-                       dev->dev_addr[5] = ((lo >> 24) & 0xff);
+               if (!tg3_nvram_read_be32(tp, mac_offset + 0, &hi) &&
+                   !tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) {
+                       memcpy(&dev->dev_addr[0], ((char *)&hi) + 2, 2);
+                       memcpy(&dev->dev_addr[2], (char *)&lo, sizeof(lo));
                }
                /* Finally just fetch it out of the MAC control regs. */
                else {
@@ -13243,6 +13325,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                }
 
                tg3_ape_lock_init(tp);
+
+               if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
+                       tg3_read_dash_ver(tp);
        }
 
        /*