myri10ge: use pci_map_page to prepare the dmatest buffer
[deliverable/linux.git] / drivers / net / myri10ge / myri10ge.c
index 030924fb1ab3544545ea5770c9d265010bd9f315..eab9b5acd0cf9790140898d3b1a70f9188a541c4 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
@@ -195,6 +195,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 +451,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 +461,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 +566,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 +717,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 +728,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 +771,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 +781,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 +792,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 +803,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 +821,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;
 }
 
@@ -1437,6 +1466,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);
@@ -1444,6 +1475,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)
@@ -2239,7 +2272,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 */
This page took 0.030382 seconds and 5 git commands to generate.