myri10ge: replace the chipset whitelist with firmware autodetection
authorBrice Goglin <brice@myri.com>
Mon, 7 May 2007 21:52:22 +0000 (23:52 +0200)
committerJeff Garzik <jeff@garzik.org>
Tue, 8 May 2007 05:15:15 +0000 (01:15 -0400)
Remove the aligned-completion whitelist, and replace it by using the 1.4.16
firmware's auto-detection features to choose which firmware to load.
The driver now loads the aligned firmware, performs a MXGEFW_CMD_UNALIGNED_TEST,
and falls back to using the unaligned firmware if:
- The firmware is too old (ie, MXGEFW_CMD_UNALIGNED_TEST is an unknown command).
- The MXGEFW_CMD_UNALIGNED_TEST returns MXGEFW_CMD_ERROR_UNALIGNED, meaning
  that it has seen an unaligned completion during the DMA test.

Signed-off-by: Brice Goglin <brice@myri.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/net/myri10ge/myri10ge.c

index f53b0da..5d14be7 100644 (file)
@@ -355,6 +355,8 @@ myri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd,
                        return 0;
                } else if (result == MXGEFW_CMD_UNKNOWN) {
                        return -ENOSYS;
+               } else if (result == MXGEFW_CMD_ERROR_UNALIGNED) {
+                       return -E2BIG;
                } else {
                        dev_err(&mgp->pdev->dev,
                                "command %d failed, result = %d\n",
@@ -2483,8 +2485,6 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
        err_cap |= PCI_ERR_CAP_ECRC_GENE;
        pci_write_config_dword(bridge, cap + PCI_ERR_CAP, err_cap);
        dev_info(dev, "Enabled ECRC on upstream bridge %s\n", pci_name(bridge));
-       mgp->tx.boundary = 4096;
-       mgp->fw_name = myri10ge_fw_aligned;
 }
 
 /*
@@ -2506,22 +2506,70 @@ static void myri10ge_enable_ecrc(struct myri10ge_priv *mgp)
  * firmware image, and set tx.boundary to 4KB.
  */
 
-#define PCI_DEVICE_ID_INTEL_E5000_PCIE23 0x25f7
-#define PCI_DEVICE_ID_INTEL_E5000_PCIE47 0x25fa
-#define PCI_DEVICE_ID_INTEL_6300ESB_PCIEE1 0x3510
-#define PCI_DEVICE_ID_INTEL_6300ESB_PCIEE4 0x351b
-#define PCI_DEVICE_ID_INTEL_E3000_PCIE 0x2779
-#define PCI_DEVICE_ID_INTEL_E3010_PCIE 0x277a
-#define PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_FIRST 0x140
-#define PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_LAST 0x142
-
-static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
+static void myri10ge_firmware_probe(struct myri10ge_priv *mgp)
 {
-       struct pci_dev *bridge = mgp->pdev->bus->self;
+       struct pci_dev *pdev = mgp->pdev;
+       struct device *dev = &pdev->dev;
+       int cap, status;
+       u16 val;
 
+       mgp->tx.boundary = 4096;
+       /*
+        * Verify the max read request size was set to 4KB
+        * before trying the test with 4KB.
+        */
+       cap = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+       if (cap < 64) {
+               dev_err(dev, "Bad PCI_CAP_ID_EXP location %d\n", cap);
+               goto abort;
+       }
+       status = pci_read_config_word(pdev, cap + PCI_EXP_DEVCTL, &val);
+       if (status != 0) {
+               dev_err(dev, "Couldn't read max read req size: %d\n", status);
+               goto abort;
+       }
+       if ((val & (5 << 12)) != (5 << 12)) {
+               dev_warn(dev, "Max Read Request size != 4096 (0x%x)\n", val);
+               mgp->tx.boundary = 2048;
+       }
+       /*
+        * load the optimized firmware (which assumes aligned PCIe
+        * completions) in order to see if it works on this host.
+        */
+       mgp->fw_name = myri10ge_fw_aligned;
+       status = myri10ge_load_firmware(mgp);
+       if (status != 0) {
+               goto abort;
+       }
+
+       /*
+        * Enable ECRC if possible
+        */
+       myri10ge_enable_ecrc(mgp);
+
+       /*
+        * Run a DMA test which watches for unaligned completions and
+        * aborts on the first one seen.
+        */
+
+       status = myri10ge_dma_test(mgp, MXGEFW_CMD_UNALIGNED_TEST);
+       if (status == 0)
+               return;         /* keep the aligned firmware */
+
+       if (status != -E2BIG)
+               dev_warn(dev, "DMA test failed: %d\n", status);
+       if (status == -ENOSYS)
+               dev_warn(dev, "Falling back to ethp! "
+                        "Please install up to date fw\n");
+abort:
+       /* fall back to using the unaligned firmware */
        mgp->tx.boundary = 2048;
        mgp->fw_name = myri10ge_fw_unaligned;
 
+}
+
+static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
+{
        if (myri10ge_force_firmware == 0) {
                int link_width, exp_cap;
                u16 lnk;
@@ -2530,8 +2578,6 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
                pci_read_config_word(mgp->pdev, exp_cap + PCI_EXP_LNKSTA, &lnk);
                link_width = (lnk >> 4) & 0x3f;
 
-               myri10ge_enable_ecrc(mgp);
-
                /* Check to see if Link is less than 8 or if the
                 * upstream bridge is known to provide aligned
                 * completions */
@@ -2540,46 +2586,8 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
                                 link_width);
                        mgp->tx.boundary = 4096;
                        mgp->fw_name = myri10ge_fw_aligned;
-               } else if (bridge &&
-                          /* ServerWorks HT2000/HT1000 */
-                          ((bridge->vendor == PCI_VENDOR_ID_SERVERWORKS
-                            && bridge->device ==
-                            PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE)
-                           /* ServerWorks HT2100 */
-                           || (bridge->vendor == PCI_VENDOR_ID_SERVERWORKS
-                               && bridge->device >=
-                               PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_FIRST
-                               && bridge->device <=
-                               PCI_DEVICE_ID_SERVERWORKS_HT2100_PCIE_LAST)
-                           /* All Intel E3000/E3010 PCIE ports */
-                           || (bridge->vendor == PCI_VENDOR_ID_INTEL
-                               && (bridge->device ==
-                                   PCI_DEVICE_ID_INTEL_E3000_PCIE
-                                   || bridge->device ==
-                                   PCI_DEVICE_ID_INTEL_E3010_PCIE))
-                           /* All Intel 6310/6311/6321ESB PCIE ports */
-                           || (bridge->vendor == PCI_VENDOR_ID_INTEL
-                               && bridge->device >=
-                               PCI_DEVICE_ID_INTEL_6300ESB_PCIEE1
-                               && bridge->device <=
-                               PCI_DEVICE_ID_INTEL_6300ESB_PCIEE4)
-                           /* All Intel E5000 PCIE ports */
-                           || (bridge->vendor == PCI_VENDOR_ID_INTEL
-                               && bridge->device >=
-                               PCI_DEVICE_ID_INTEL_E5000_PCIE23
-                               && bridge->device <=
-                               PCI_DEVICE_ID_INTEL_E5000_PCIE47))) {
-                       dev_info(&mgp->pdev->dev,
-                                "Assuming aligned completions (0x%x:0x%x)\n",
-                                bridge->vendor, bridge->device);
-                       mgp->tx.boundary = 4096;
-                       mgp->fw_name = myri10ge_fw_aligned;
-               } else if (bridge &&
-                          bridge->vendor == PCI_VENDOR_ID_SGI &&
-                          bridge->device == 0x4002 /* TIOCE pcie-port */ ) {
-                       /* this pcie bridge does not support 4K rdma request */
-                       mgp->tx.boundary = 2048;
-                       mgp->fw_name = myri10ge_fw_aligned;
+               } else {
+                       myri10ge_firmware_probe(mgp);
                }
        } else {
                if (myri10ge_force_firmware == 1) {
@@ -2847,7 +2855,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                status = -ENODEV;
                goto abort_with_netdev;
        }
-       myri10ge_select_firmware(mgp);
 
        /* Find the vendor-specific cap so we can check
         * the reboot register later on */
@@ -2941,6 +2948,8 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                goto abort_with_ioremap;
        memset(mgp->rx_done.entry, 0, bytes);
 
+       myri10ge_select_firmware(mgp);
+
        status = myri10ge_load_firmware(mgp);
        if (status != 0) {
                dev_err(&pdev->dev, "failed to load firmware\n");