📄 myri10ge.c
字号:
/************************************************************************* * myri10ge.c: Myricom Myri-10G Ethernet driver. * * Copyright (C) 2005 - 2007 Myricom, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Myricom, Inc. nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * 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 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 * newer firmware image at: * http://www.myri.com/scs/download-Myri10GE.html * * Contact Information: * <help@myri.com> * Myricom, Inc., 325N Santa Anita Avenue, Arcadia, CA 91006 *************************************************************************/#include <linux/tcp.h>#include <linux/netdevice.h>#include <linux/skbuff.h>#include <linux/string.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <linux/etherdevice.h>#include <linux/if_ether.h>#include <linux/if_vlan.h>#include <linux/inet_lro.h>#include <linux/ip.h>#include <linux/inet.h>#include <linux/in.h>#include <linux/ethtool.h>#include <linux/firmware.h>#include <linux/delay.h>#include <linux/version.h>#include <linux/timer.h>#include <linux/vmalloc.h>#include <linux/crc32.h>#include <linux/moduleparam.h>#include <linux/io.h>#include <linux/log2.h>#include <net/checksum.h>#include <net/ip.h>#include <net/tcp.h>#include <asm/byteorder.h>#include <asm/io.h>#include <asm/processor.h>#ifdef CONFIG_MTRR#include <asm/mtrr.h>#endif#include "myri10ge_mcp.h"#include "myri10ge_mcp_gen_header.h"#define MYRI10GE_VERSION_STR "1.3.2-1.287"MODULE_DESCRIPTION("Myricom 10G driver (10GbE)");MODULE_AUTHOR("Maintainer: help@myri.com");MODULE_VERSION(MYRI10GE_VERSION_STR);MODULE_LICENSE("Dual BSD/GPL");#define MYRI10GE_MAX_ETHER_MTU 9014#define MYRI10GE_ETH_STOPPED 0#define MYRI10GE_ETH_STOPPING 1#define MYRI10GE_ETH_STARTING 2#define MYRI10GE_ETH_RUNNING 3#define MYRI10GE_ETH_OPEN_FAILED 4#define MYRI10GE_EEPROM_STRINGS_SIZE 256#define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2)#define MYRI10GE_MAX_LRO_DESCRIPTORS 8#define MYRI10GE_LRO_MAX_PKTS 64#define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff)#define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff#define MYRI10GE_ALLOC_ORDER 0#define MYRI10GE_ALLOC_SIZE ((1 << MYRI10GE_ALLOC_ORDER) * PAGE_SIZE)#define MYRI10GE_MAX_FRAGS_PER_FRAME (MYRI10GE_MAX_ETHER_MTU/MYRI10GE_ALLOC_SIZE + 1)struct myri10ge_rx_buffer_state { struct page *page; int page_offset; DECLARE_PCI_UNMAP_ADDR(bus) DECLARE_PCI_UNMAP_LEN(len)};struct myri10ge_tx_buffer_state { struct sk_buff *skb; int last; DECLARE_PCI_UNMAP_ADDR(bus) DECLARE_PCI_UNMAP_LEN(len)};struct myri10ge_cmd { u32 data0; u32 data1; u32 data2;};struct myri10ge_rx_buf { struct mcp_kreq_ether_recv __iomem *lanai; /* lanai ptr for recv ring */ u8 __iomem *wc_fifo; /* w/c rx dma addr fifo address */ struct mcp_kreq_ether_recv *shadow; /* host shadow of recv ring */ struct myri10ge_rx_buffer_state *info; struct page *page; dma_addr_t bus; int page_offset; int cnt; int fill_cnt; int alloc_fail; int mask; /* number of rx slots -1 */ int watchdog_needed;};struct myri10ge_tx_buf { struct mcp_kreq_ether_send __iomem *lanai; /* lanai ptr for sendq */ u8 __iomem *wc_fifo; /* w/c send fifo address */ struct mcp_kreq_ether_send *req_list; /* host shadow of sendq */ char *req_bytes; struct myri10ge_tx_buffer_state *info; int mask; /* number of transmit slots -1 */ int boundary; /* boundary transmits cannot cross */ int req ____cacheline_aligned; /* transmit slots submitted */ int pkt_start; /* packets started */ int done ____cacheline_aligned; /* transmit slots completed */ int pkt_done; /* packets completed */};struct myri10ge_rx_done { struct mcp_slot *entry; dma_addr_t bus; int cnt; int idx; struct net_lro_mgr lro_mgr; struct net_lro_desc lro_desc[MYRI10GE_MAX_LRO_DESCRIPTORS];};struct myri10ge_priv { int running; /* running? */ int csum_flag; /* rx_csums? */ struct myri10ge_tx_buf tx; /* transmit ring */ struct myri10ge_rx_buf rx_small; struct myri10ge_rx_buf rx_big; struct myri10ge_rx_done rx_done; int small_bytes; int big_bytes; struct net_device *dev; struct napi_struct napi; struct net_device_stats stats; u8 __iomem *sram; int sram_size; unsigned long board_span; unsigned long iomem_base; __be32 __iomem *irq_claim; __be32 __iomem *irq_deassert; char *mac_addr_string; struct mcp_cmd_response *cmd; dma_addr_t cmd_bus; struct mcp_irq_data *fw_stats; dma_addr_t fw_stats_bus; struct pci_dev *pdev; int msi_enabled; __be32 link_state; unsigned int rdma_tags_available; int intr_coal_delay; __be32 __iomem *intr_coal_delay_ptr; int mtrr; int wc_enabled; int wake_queue; int stop_queue; int down_cnt; wait_queue_head_t down_wq; struct work_struct watchdog_work; struct timer_list watchdog_timer; int watchdog_tx_done; int watchdog_tx_req; int watchdog_pause; int watchdog_resets; int tx_linearized; int pause; 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; int fw_multicast_support; unsigned long features; u32 max_tso6; u32 read_dma; u32 write_dma; u32 read_write_dma; u32 link_changes; u32 msg_enable;};static char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat";static char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat";static char *myri10ge_fw_name = NULL;module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name\n");static int myri10ge_ecrc_enable = 1;module_param(myri10ge_ecrc_enable, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_ecrc_enable, "Enable Extended CRC on PCI-E\n");static int myri10ge_max_intr_slots = 1024;module_param(myri10ge_max_intr_slots, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_max_intr_slots, "Interrupt queue slots\n");static int myri10ge_small_bytes = -1; /* -1 == auto */module_param(myri10ge_small_bytes, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(myri10ge_small_bytes, "Threshold of small packets\n");static int myri10ge_msi = 1; /* enable msi by default */module_param(myri10ge_msi, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(myri10ge_msi, "Enable Message Signalled Interrupts\n");static int myri10ge_intr_coal_delay = 75;module_param(myri10ge_intr_coal_delay, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_intr_coal_delay, "Interrupt coalescing delay\n");static int myri10ge_flow_control = 1;module_param(myri10ge_flow_control, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_flow_control, "Pause parameter\n");static int myri10ge_deassert_wait = 1;module_param(myri10ge_deassert_wait, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(myri10ge_deassert_wait, "Wait when deasserting legacy interrupts\n");static int myri10ge_force_firmware = 0;module_param(myri10ge_force_firmware, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_force_firmware, "Force firmware to assume aligned completions\n");static int myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN;module_param(myri10ge_initial_mtu, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_initial_mtu, "Initial MTU\n");static int myri10ge_napi_weight = 64;module_param(myri10ge_napi_weight, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_napi_weight, "Set NAPI weight\n");static int myri10ge_watchdog_timeout = 1;module_param(myri10ge_watchdog_timeout, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_watchdog_timeout, "Set watchdog timeout\n");static int myri10ge_max_irq_loops = 1048576;module_param(myri10ge_max_irq_loops, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_max_irq_loops, "Set stuck legacy IRQ detection threshold\n");#define MYRI10GE_MSG_DEFAULT NETIF_MSG_LINKstatic int myri10ge_debug = -1; /* defaults above */module_param(myri10ge_debug, int, 0);MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");static int myri10ge_lro = 1;module_param(myri10ge_lro, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload\n");static int myri10ge_lro_max_pkts = MYRI10GE_LRO_MAX_PKTS;module_param(myri10ge_lro_max_pkts, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_lro, "Number of LRO packets to be aggregated\n");static int myri10ge_fill_thresh = 256;module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n");static int myri10ge_reset_recover = 1;static int myri10ge_wcfifo = 0;module_param(myri10ge_wcfifo, int, S_IRUGO);MODULE_PARM_DESC(myri10ge_wcfifo, "Enable WC Fifo when WC is enabled\n");#define MYRI10GE_FW_OFFSET 1024*1024#define MYRI10GE_HIGHPART_TO_U32(X) \(sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0)#define MYRI10GE_LOWPART_TO_U32(X) ((u32)(X))#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8)static void myri10ge_set_multicast_list(struct net_device *dev);static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev);static inline void put_be32(__be32 val, __be32 __iomem * p){ __raw_writel((__force __u32) val, (__force void __iomem *)p);}static intmyri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, struct myri10ge_cmd *data, int atomic){ struct mcp_cmd *buf; char buf_bytes[sizeof(*buf) + 8]; struct mcp_cmd_response *response = mgp->cmd; char __iomem *cmd_addr = mgp->sram + MXGEFW_ETH_CMD; u32 dma_low, dma_high, result, value; int sleep_total = 0; /* ensure buf is aligned to 8 bytes */ buf = (struct mcp_cmd *)ALIGN((unsigned long)buf_bytes, 8); buf->data0 = htonl(data->data0); buf->data1 = htonl(data->data1); buf->data2 = htonl(data->data2); buf->cmd = htonl(cmd); dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus); dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus); buf->response_addr.low = htonl(dma_low); buf->response_addr.high = htonl(dma_high); response->result = htonl(MYRI10GE_NO_RESPONSE_RESULT); mb(); myri10ge_pio_copy(cmd_addr, buf, sizeof(*buf)); /* wait up to 15ms. Longest command is the DMA benchmark, * which is capped at 5ms, but runs from a timeout handler * that runs every 7.8ms. So a 15ms timeout leaves us with * a 2.2ms margin */ if (atomic) { /* if atomic is set, do not sleep, * and try to get the completion quickly * (1ms will be enough for those commands) */ for (sleep_total = 0; sleep_total < 1000 && response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT); sleep_total += 10) udelay(10); } else { /* use msleep for most command */ for (sleep_total = 0; sleep_total < 15 && response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT); sleep_total++) msleep(1); } result = ntohl(response->result); value = ntohl(response->data); if (result != MYRI10GE_NO_RESPONSE_RESULT) { if (result == 0) { data->data0 = value; 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", cmd, result); return -ENXIO; } } dev_err(&mgp->pdev->dev, "command %d timed out, result = %d\n", cmd, result); return -EAGAIN;}/* * The eeprom strings on the lanaiX have the format * SN=x\0 * MAC=x:x:x:x:x:x\0 * PT:ddd mmm xx xx:xx:xx xx\0 * PV:ddd mmm xx xx:xx:xx xx\0 */static int myri10ge_read_mac_addr(struct myri10ge_priv *mgp){ char *ptr, *limit; int i; ptr = mgp->eeprom_strings; limit = mgp->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE; while (*ptr != '\0' && ptr < limit) { if (memcmp(ptr, "MAC=", 4) == 0) { ptr += 4; mgp->mac_addr_string = ptr; for (i = 0; i < 6; i++) { if ((ptr + 2) > limit) goto abort; mgp->mac_addr[i] = simple_strtoul(ptr, &ptr, 16); ptr += 1; } } if (memcmp((const void *)ptr, "SN=", 3) == 0) { ptr += 3; mgp->serial_number = simple_strtoul(ptr, &ptr, 10); } while (ptr < limit && *ptr++) ; } return 0;abort: dev_err(&mgp->pdev->dev, "failed to parse eeprom_strings\n"); return -ENXIO;}/* * Enable or disable periodic RDMAs from the host to make certain * chipsets resend dropped PCIe messages */static void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable){ char __iomem *submit; __be32 buf[16]; u32 dma_low, dma_high; int i; /* clear confirmation addr */ mgp->cmd->data = 0; mb(); /* send a rdma command to the PCIe engine, and wait for the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -