]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/myri10ge/myri10ge.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[linux-2.6-omap-h63xx.git] / drivers / net / myri10ge / myri10ge.c
index 61cbd4a604460448bd699664500f1803fb0794e7..ac02b3b60f926e40f175aed8c1f2ac27adc090f4 100644 (file)
@@ -1,7 +1,7 @@
 /*************************************************************************
  * myri10ge.c: Myricom Myri-10G Ethernet driver.
  *
- * Copyright (C) 2005, 2006 Myricom, Inc.
+ * Copyright (C) 2005 - 2007 Myricom, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  *    may be used to endorse or promote products derived from this software
  *    without specific prior written permission.
  *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
  *
  *
  * If the eeprom on your board is not recent enough, you will need to get a
@@ -181,6 +181,7 @@ struct myri10ge_priv {
        int intr_coal_delay;
        __be32 __iomem *intr_coal_delay_ptr;
        int mtrr;
+       int wc_enabled;
        int wake_queue;
        int stop_queue;
        int down_cnt;
@@ -195,6 +196,10 @@ struct myri10ge_priv {
        char *fw_name;
        char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE];
        char fw_version[128];
+       int fw_ver_major;
+       int fw_ver_minor;
+       int fw_ver_tiny;
+       int adopted_rx_filter_bug;
        u8 mac_addr[6];         /* eeprom mac address */
        unsigned long serial_number;
        int vendor_specific_offset;
@@ -447,7 +452,6 @@ myri10ge_validate_firmware(struct myri10ge_priv *mgp,
                           struct mcp_gen_header *hdr)
 {
        struct device *dev = &mgp->pdev->dev;
-       int major, minor;
 
        /* check firmware type */
        if (ntohl(hdr->mcp_type) != MCP_TYPE_ETH) {
@@ -458,9 +462,11 @@ myri10ge_validate_firmware(struct myri10ge_priv *mgp,
        /* save firmware version for ethtool */
        strncpy(mgp->fw_version, hdr->version, sizeof(mgp->fw_version));
 
-       sscanf(mgp->fw_version, "%d.%d", &major, &minor);
+       sscanf(mgp->fw_version, "%d.%d.%d", &mgp->fw_ver_major,
+              &mgp->fw_ver_minor, &mgp->fw_ver_tiny);
 
-       if (!(major == MXGEFW_VERSION_MAJOR && minor == MXGEFW_VERSION_MINOR)) {
+       if (!(mgp->fw_ver_major == MXGEFW_VERSION_MAJOR
+             && mgp->fw_ver_minor == MXGEFW_VERSION_MINOR)) {
                dev_err(dev, "Found firmware version %s\n", mgp->fw_version);
                dev_err(dev, "Driver needs %d.%d\n", MXGEFW_VERSION_MAJOR,
                        MXGEFW_VERSION_MINOR);
@@ -561,6 +567,18 @@ static int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp)
        memcpy_fromio(hdr, mgp->sram + hdr_offset, bytes);
        status = myri10ge_validate_firmware(mgp, hdr);
        kfree(hdr);
+
+       /* check to see if adopted firmware has bug where adopting
+        * it will cause broadcasts to be filtered unless the NIC
+        * is kept in ALLMULTI mode */
+       if (mgp->fw_ver_major == 1 && mgp->fw_ver_minor == 4 &&
+           mgp->fw_ver_tiny >= 4 && mgp->fw_ver_tiny <= 11) {
+               mgp->adopted_rx_filter_bug = 1;
+               dev_warn(dev, "Adopting fw %d.%d.%d: "
+                        "working around rx filter bug\n",
+                        mgp->fw_ver_major, mgp->fw_ver_minor,
+                        mgp->fw_ver_tiny);
+       }
        return status;
 }
 
@@ -700,6 +718,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
        int status;
        size_t bytes;
        u32 len;
+       struct page *dmatest_page;
+       dma_addr_t dmatest_bus;
 
        /* try to send a reset command to the card to see if it
         * is alive */
@@ -709,6 +729,11 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
                dev_err(&mgp->pdev->dev, "failed reset\n");
                return -ENXIO;
        }
+       dmatest_page = alloc_page(GFP_KERNEL);
+       if (!dmatest_page)
+               return -ENOMEM;
+       dmatest_bus = pci_map_page(mgp->pdev, dmatest_page, 0, PAGE_SIZE,
+                                  DMA_BIDIRECTIONAL);
 
        /* Now exchange information about interrupts  */
 
@@ -747,8 +772,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
 
        len = mgp->tx.boundary;
 
-       cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
-       cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+       cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+       cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
        cmd.data2 = len * 0x10000;
        status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
        if (status == 0)
@@ -757,8 +782,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
        else
                dev_warn(&mgp->pdev->dev, "DMA read benchmark failed: %d\n",
                         status);
-       cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
-       cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+       cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+       cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
        cmd.data2 = len * 0x1;
        status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
        if (status == 0)
@@ -768,8 +793,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
                dev_warn(&mgp->pdev->dev, "DMA write benchmark failed: %d\n",
                         status);
 
-       cmd.data0 = MYRI10GE_LOWPART_TO_U32(mgp->rx_done.bus);
-       cmd.data1 = MYRI10GE_HIGHPART_TO_U32(mgp->rx_done.bus);
+       cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus);
+       cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus);
        cmd.data2 = len * 0x10001;
        status = myri10ge_send_cmd(mgp, MXGEFW_DMA_TEST, &cmd, 0);
        if (status == 0)
@@ -779,6 +804,9 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
                dev_warn(&mgp->pdev->dev,
                         "DMA read/write benchmark failed: %d\n", status);
 
+       pci_unmap_page(mgp->pdev, dmatest_bus, PAGE_SIZE, DMA_BIDIRECTIONAL);
+       put_page(dmatest_page);
+
        memset(mgp->rx_done.entry, 0, bytes);
 
        /* reset mcp/driver shared state back to 0 */
@@ -794,6 +822,8 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
        status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr);
        myri10ge_change_promisc(mgp, 0, 0);
        myri10ge_change_pause(mgp, mgp->pause);
+       if (mgp->adopted_rx_filter_bug)
+               (void)myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1);
        return status;
 }
 
@@ -1356,7 +1386,7 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
                data[i] = ((unsigned long *)&mgp->stats)[i];
 
        data[i++] = (unsigned int)mgp->tx.boundary;
-       data[i++] = (unsigned int)(mgp->mtrr >= 0);
+       data[i++] = (unsigned int)mgp->wc_enabled;
        data[i++] = (unsigned int)mgp->pdev->irq;
        data[i++] = (unsigned int)mgp->msi_enabled;
        data[i++] = (unsigned int)mgp->read_dma;
@@ -1412,10 +1442,8 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
        .set_tx_csum = ethtool_op_set_tx_hw_csum,
        .get_sg = ethtool_op_get_sg,
        .set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
        .get_tso = ethtool_op_get_tso,
        .set_tso = ethtool_op_set_tso,
-#endif
        .get_strings = myri10ge_get_strings,
        .get_stats_count = myri10ge_get_stats_count,
        .get_ethtool_stats = myri10ge_get_ethtool_stats,
@@ -1439,6 +1467,8 @@ static int myri10ge_allocate_rings(struct net_device *dev)
        status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0);
        tx_ring_size = cmd.data0;
        status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0);
+       if (status != 0)
+               return status;
        rx_ring_size = cmd.data0;
 
        tx_ring_entries = tx_ring_size / sizeof(struct mcp_kreq_ether_send);
@@ -1446,6 +1476,8 @@ static int myri10ge_allocate_rings(struct net_device *dev)
        mgp->tx.mask = tx_ring_entries - 1;
        mgp->rx_small.mask = mgp->rx_big.mask = rx_ring_entries - 1;
 
+       status = -ENOMEM;
+
        /* allocate the host shadow rings */
 
        bytes = 8 + (MYRI10GE_MAX_SEND_DESC_TSO + 4)
@@ -1718,7 +1750,7 @@ static int myri10ge_open(struct net_device *dev)
                goto abort_with_irq;
        }
 
-       if (myri10ge_wcfifo && mgp->mtrr >= 0) {
+       if (myri10ge_wcfifo && mgp->wc_enabled) {
                mgp->tx.wc_fifo = (u8 __iomem *) mgp->sram + MXGEFW_ETH_SEND_4;
                mgp->rx_small.wc_fifo =
                    (u8 __iomem *) mgp->sram + MXGEFW_ETH_RECV_SMALL;
@@ -1975,13 +2007,11 @@ again:
        mss = 0;
        max_segments = MXGEFW_MAX_SEND_DESC;
 
-#ifdef NETIF_F_TSO
        if (skb->len > (dev->mtu + ETH_HLEN)) {
                mss = skb_shinfo(skb)->gso_size;
                if (mss != 0)
                        max_segments = MYRI10GE_MAX_SEND_DESC_TSO;
        }
-#endif                         /*NETIF_F_TSO */
 
        if ((unlikely(avail < max_segments))) {
                /* we are out of transmit resources */
@@ -2013,7 +2043,6 @@ again:
 
        cum_len = 0;
 
-#ifdef NETIF_F_TSO
        if (mss) {              /* TSO */
                /* this removes any CKSUM flag from before */
                flags = (MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST);
@@ -2029,7 +2058,6 @@ again:
                 * the checksum by parsing the header. */
                pseudo_hdr_offset = mss;
        } else
-#endif                         /*NETIF_F_TSO */
                /* Mark small packets, and pad out tiny packets */
        if (skb->len <= MXGEFW_SEND_SMALL_SIZE) {
                flags |= MXGEFW_FLAGS_SMALL;
@@ -2097,7 +2125,6 @@ again:
                                seglen = len;
                        flags_next = flags & ~MXGEFW_FLAGS_FIRST;
                        cum_len_next = cum_len + seglen;
-#ifdef NETIF_F_TSO
                        if (mss) {      /* TSO */
                                (req - rdma_count)->rdma_count = rdma_count + 1;
 
@@ -2124,7 +2151,6 @@ again:
                                            (small * MXGEFW_FLAGS_SMALL);
                                }
                        }
-#endif                         /* NETIF_F_TSO */
                        req->addr_high = high_swapped;
                        req->addr_low = htonl(low);
                        req->pseudo_hdr_offset = htons(pseudo_hdr_offset);
@@ -2161,14 +2187,12 @@ again:
        }
 
        (req - rdma_count)->rdma_count = rdma_count;
-#ifdef NETIF_F_TSO
        if (mss)
                do {
                        req--;
                        req->flags |= MXGEFW_FLAGS_TSO_LAST;
                } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP |
                                         MXGEFW_FLAGS_FIRST)));
-#endif
        idx = ((count - 1) + tx->req) & tx->mask;
        tx->info[idx].last = 1;
        if (tx->wc_fifo == NULL)
@@ -2249,7 +2273,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev)
        myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1);
 
        /* This firmware is known to not support multicast */
-       if (!mgp->fw_multicast_support)
+       if (!mgp->fw_multicast_support || mgp->adopted_rx_filter_bug)
                return;
 
        /* Disable multicast filtering */
@@ -2501,6 +2525,12 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
                                 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 {
                if (myri10ge_force_firmware == 1) {
@@ -2821,9 +2851,12 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        mgp->board_span = pci_resource_len(pdev, 0);
        mgp->iomem_base = pci_resource_start(pdev, 0);
        mgp->mtrr = -1;
+       mgp->wc_enabled = 0;
 #ifdef CONFIG_MTRR
        mgp->mtrr = mtrr_add(mgp->iomem_base, mgp->board_span,
                             MTRR_TYPE_WRCOMB, 1);
+       if (mgp->mtrr >= 0)
+               mgp->wc_enabled = 1;
 #endif
        /* Hack.  need to get rid of these magic numbers */
        mgp->sram_size =
@@ -2918,7 +2951,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, WC %s\n",
                 (mgp->msi_enabled ? "MSI" : "xPIC"),
                 netdev->irq, mgp->tx.boundary, mgp->fw_name,
-                (mgp->mtrr >= 0 ? "Enabled" : "Disabled"));
+                (mgp->wc_enabled ? "Enabled" : "Disabled"));
 
        return 0;