162306a36Sopenharmony_ci/************************************************************************* 262306a36Sopenharmony_ci * myri10ge.c: Myricom Myri-10G Ethernet driver. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2005 - 2011 Myricom, Inc. 562306a36Sopenharmony_ci * All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 862306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 962306a36Sopenharmony_ci * are met: 1062306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 1162306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1262306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 1362306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in the 1462306a36Sopenharmony_ci * documentation and/or other materials provided with the distribution. 1562306a36Sopenharmony_ci * 3. Neither the name of Myricom, Inc. nor the names of its contributors 1662306a36Sopenharmony_ci * may be used to endorse or promote products derived from this software 1762306a36Sopenharmony_ci * without specific prior written permission. 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 2062306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2162306a36Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2262306a36Sopenharmony_ci * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 2362306a36Sopenharmony_ci * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2462306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2562306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2662306a36Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2762306a36Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2862306a36Sopenharmony_ci * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2962306a36Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGE. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * If the eeprom on your board is not recent enough, you will need to get a 3362306a36Sopenharmony_ci * newer firmware image at: 3462306a36Sopenharmony_ci * http://www.myri.com/scs/download-Myri10GE.html 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * Contact Information: 3762306a36Sopenharmony_ci * <help@myri.com> 3862306a36Sopenharmony_ci * Myricom, Inc., 325N Santa Anita Avenue, Arcadia, CA 91006 3962306a36Sopenharmony_ci *************************************************************************/ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <linux/tcp.h> 4462306a36Sopenharmony_ci#include <linux/netdevice.h> 4562306a36Sopenharmony_ci#include <linux/skbuff.h> 4662306a36Sopenharmony_ci#include <linux/string.h> 4762306a36Sopenharmony_ci#include <linux/module.h> 4862306a36Sopenharmony_ci#include <linux/pci.h> 4962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 5062306a36Sopenharmony_ci#include <linux/etherdevice.h> 5162306a36Sopenharmony_ci#include <linux/if_ether.h> 5262306a36Sopenharmony_ci#include <linux/if_vlan.h> 5362306a36Sopenharmony_ci#include <linux/dca.h> 5462306a36Sopenharmony_ci#include <linux/ip.h> 5562306a36Sopenharmony_ci#include <linux/inet.h> 5662306a36Sopenharmony_ci#include <linux/in.h> 5762306a36Sopenharmony_ci#include <linux/ethtool.h> 5862306a36Sopenharmony_ci#include <linux/firmware.h> 5962306a36Sopenharmony_ci#include <linux/delay.h> 6062306a36Sopenharmony_ci#include <linux/timer.h> 6162306a36Sopenharmony_ci#include <linux/vmalloc.h> 6262306a36Sopenharmony_ci#include <linux/crc32.h> 6362306a36Sopenharmony_ci#include <linux/moduleparam.h> 6462306a36Sopenharmony_ci#include <linux/io.h> 6562306a36Sopenharmony_ci#include <linux/log2.h> 6662306a36Sopenharmony_ci#include <linux/slab.h> 6762306a36Sopenharmony_ci#include <linux/prefetch.h> 6862306a36Sopenharmony_ci#include <net/checksum.h> 6962306a36Sopenharmony_ci#include <net/gso.h> 7062306a36Sopenharmony_ci#include <net/ip.h> 7162306a36Sopenharmony_ci#include <net/tcp.h> 7262306a36Sopenharmony_ci#include <asm/byteorder.h> 7362306a36Sopenharmony_ci#include <asm/processor.h> 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#include "myri10ge_mcp.h" 7662306a36Sopenharmony_ci#include "myri10ge_mcp_gen_header.h" 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define MYRI10GE_VERSION_STR "1.5.3-1.534" 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ciMODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); 8162306a36Sopenharmony_ciMODULE_AUTHOR("Maintainer: help@myri.com"); 8262306a36Sopenharmony_ciMODULE_VERSION(MYRI10GE_VERSION_STR); 8362306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#define MYRI10GE_MAX_ETHER_MTU 9014 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define MYRI10GE_ETH_STOPPED 0 8862306a36Sopenharmony_ci#define MYRI10GE_ETH_STOPPING 1 8962306a36Sopenharmony_ci#define MYRI10GE_ETH_STARTING 2 9062306a36Sopenharmony_ci#define MYRI10GE_ETH_RUNNING 3 9162306a36Sopenharmony_ci#define MYRI10GE_ETH_OPEN_FAILED 4 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define MYRI10GE_EEPROM_STRINGS_SIZE 256 9462306a36Sopenharmony_ci#define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2) 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff) 9762306a36Sopenharmony_ci#define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#define MYRI10GE_ALLOC_ORDER 0 10062306a36Sopenharmony_ci#define MYRI10GE_ALLOC_SIZE ((1 << MYRI10GE_ALLOC_ORDER) * PAGE_SIZE) 10162306a36Sopenharmony_ci#define MYRI10GE_MAX_FRAGS_PER_FRAME (MYRI10GE_MAX_ETHER_MTU/MYRI10GE_ALLOC_SIZE + 1) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci#define MYRI10GE_MAX_SLICES 32 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistruct myri10ge_rx_buffer_state { 10662306a36Sopenharmony_ci struct page *page; 10762306a36Sopenharmony_ci int page_offset; 10862306a36Sopenharmony_ci DEFINE_DMA_UNMAP_ADDR(bus); 10962306a36Sopenharmony_ci DEFINE_DMA_UNMAP_LEN(len); 11062306a36Sopenharmony_ci}; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistruct myri10ge_tx_buffer_state { 11362306a36Sopenharmony_ci struct sk_buff *skb; 11462306a36Sopenharmony_ci int last; 11562306a36Sopenharmony_ci DEFINE_DMA_UNMAP_ADDR(bus); 11662306a36Sopenharmony_ci DEFINE_DMA_UNMAP_LEN(len); 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistruct myri10ge_cmd { 12062306a36Sopenharmony_ci u32 data0; 12162306a36Sopenharmony_ci u32 data1; 12262306a36Sopenharmony_ci u32 data2; 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistruct myri10ge_rx_buf { 12662306a36Sopenharmony_ci struct mcp_kreq_ether_recv __iomem *lanai; /* lanai ptr for recv ring */ 12762306a36Sopenharmony_ci struct mcp_kreq_ether_recv *shadow; /* host shadow of recv ring */ 12862306a36Sopenharmony_ci struct myri10ge_rx_buffer_state *info; 12962306a36Sopenharmony_ci struct page *page; 13062306a36Sopenharmony_ci dma_addr_t bus; 13162306a36Sopenharmony_ci int page_offset; 13262306a36Sopenharmony_ci int cnt; 13362306a36Sopenharmony_ci int fill_cnt; 13462306a36Sopenharmony_ci int alloc_fail; 13562306a36Sopenharmony_ci int mask; /* number of rx slots -1 */ 13662306a36Sopenharmony_ci int watchdog_needed; 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistruct myri10ge_tx_buf { 14062306a36Sopenharmony_ci struct mcp_kreq_ether_send __iomem *lanai; /* lanai ptr for sendq */ 14162306a36Sopenharmony_ci __be32 __iomem *send_go; /* "go" doorbell ptr */ 14262306a36Sopenharmony_ci __be32 __iomem *send_stop; /* "stop" doorbell ptr */ 14362306a36Sopenharmony_ci struct mcp_kreq_ether_send *req_list; /* host shadow of sendq */ 14462306a36Sopenharmony_ci char *req_bytes; 14562306a36Sopenharmony_ci struct myri10ge_tx_buffer_state *info; 14662306a36Sopenharmony_ci int mask; /* number of transmit slots -1 */ 14762306a36Sopenharmony_ci int req ____cacheline_aligned; /* transmit slots submitted */ 14862306a36Sopenharmony_ci int pkt_start; /* packets started */ 14962306a36Sopenharmony_ci int stop_queue; 15062306a36Sopenharmony_ci int linearized; 15162306a36Sopenharmony_ci int done ____cacheline_aligned; /* transmit slots completed */ 15262306a36Sopenharmony_ci int pkt_done; /* packets completed */ 15362306a36Sopenharmony_ci int wake_queue; 15462306a36Sopenharmony_ci int queue_active; 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistruct myri10ge_rx_done { 15862306a36Sopenharmony_ci struct mcp_slot *entry; 15962306a36Sopenharmony_ci dma_addr_t bus; 16062306a36Sopenharmony_ci int cnt; 16162306a36Sopenharmony_ci int idx; 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistruct myri10ge_slice_netstats { 16562306a36Sopenharmony_ci unsigned long rx_packets; 16662306a36Sopenharmony_ci unsigned long tx_packets; 16762306a36Sopenharmony_ci unsigned long rx_bytes; 16862306a36Sopenharmony_ci unsigned long tx_bytes; 16962306a36Sopenharmony_ci unsigned long rx_dropped; 17062306a36Sopenharmony_ci unsigned long tx_dropped; 17162306a36Sopenharmony_ci}; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistruct myri10ge_slice_state { 17462306a36Sopenharmony_ci struct myri10ge_tx_buf tx; /* transmit ring */ 17562306a36Sopenharmony_ci struct myri10ge_rx_buf rx_small; 17662306a36Sopenharmony_ci struct myri10ge_rx_buf rx_big; 17762306a36Sopenharmony_ci struct myri10ge_rx_done rx_done; 17862306a36Sopenharmony_ci struct net_device *dev; 17962306a36Sopenharmony_ci struct napi_struct napi; 18062306a36Sopenharmony_ci struct myri10ge_priv *mgp; 18162306a36Sopenharmony_ci struct myri10ge_slice_netstats stats; 18262306a36Sopenharmony_ci __be32 __iomem *irq_claim; 18362306a36Sopenharmony_ci struct mcp_irq_data *fw_stats; 18462306a36Sopenharmony_ci dma_addr_t fw_stats_bus; 18562306a36Sopenharmony_ci int watchdog_tx_done; 18662306a36Sopenharmony_ci int watchdog_tx_req; 18762306a36Sopenharmony_ci int watchdog_rx_done; 18862306a36Sopenharmony_ci int stuck; 18962306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 19062306a36Sopenharmony_ci int cached_dca_tag; 19162306a36Sopenharmony_ci int cpu; 19262306a36Sopenharmony_ci __be32 __iomem *dca_tag; 19362306a36Sopenharmony_ci#endif 19462306a36Sopenharmony_ci char irq_desc[32]; 19562306a36Sopenharmony_ci}; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cistruct myri10ge_priv { 19862306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 19962306a36Sopenharmony_ci int tx_boundary; /* boundary transmits cannot cross */ 20062306a36Sopenharmony_ci int num_slices; 20162306a36Sopenharmony_ci int running; /* running? */ 20262306a36Sopenharmony_ci int small_bytes; 20362306a36Sopenharmony_ci int big_bytes; 20462306a36Sopenharmony_ci int max_intr_slots; 20562306a36Sopenharmony_ci struct net_device *dev; 20662306a36Sopenharmony_ci u8 __iomem *sram; 20762306a36Sopenharmony_ci int sram_size; 20862306a36Sopenharmony_ci unsigned long board_span; 20962306a36Sopenharmony_ci unsigned long iomem_base; 21062306a36Sopenharmony_ci __be32 __iomem *irq_deassert; 21162306a36Sopenharmony_ci char *mac_addr_string; 21262306a36Sopenharmony_ci struct mcp_cmd_response *cmd; 21362306a36Sopenharmony_ci dma_addr_t cmd_bus; 21462306a36Sopenharmony_ci struct pci_dev *pdev; 21562306a36Sopenharmony_ci int msi_enabled; 21662306a36Sopenharmony_ci int msix_enabled; 21762306a36Sopenharmony_ci struct msix_entry *msix_vectors; 21862306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 21962306a36Sopenharmony_ci int dca_enabled; 22062306a36Sopenharmony_ci int relaxed_order; 22162306a36Sopenharmony_ci#endif 22262306a36Sopenharmony_ci u32 link_state; 22362306a36Sopenharmony_ci unsigned int rdma_tags_available; 22462306a36Sopenharmony_ci int intr_coal_delay; 22562306a36Sopenharmony_ci __be32 __iomem *intr_coal_delay_ptr; 22662306a36Sopenharmony_ci int wc_cookie; 22762306a36Sopenharmony_ci int down_cnt; 22862306a36Sopenharmony_ci wait_queue_head_t down_wq; 22962306a36Sopenharmony_ci struct work_struct watchdog_work; 23062306a36Sopenharmony_ci struct timer_list watchdog_timer; 23162306a36Sopenharmony_ci int watchdog_resets; 23262306a36Sopenharmony_ci int watchdog_pause; 23362306a36Sopenharmony_ci int pause; 23462306a36Sopenharmony_ci bool fw_name_allocated; 23562306a36Sopenharmony_ci char *fw_name; 23662306a36Sopenharmony_ci char eeprom_strings[MYRI10GE_EEPROM_STRINGS_SIZE]; 23762306a36Sopenharmony_ci char *product_code_string; 23862306a36Sopenharmony_ci char fw_version[128]; 23962306a36Sopenharmony_ci int fw_ver_major; 24062306a36Sopenharmony_ci int fw_ver_minor; 24162306a36Sopenharmony_ci int fw_ver_tiny; 24262306a36Sopenharmony_ci int adopted_rx_filter_bug; 24362306a36Sopenharmony_ci u8 mac_addr[ETH_ALEN]; /* eeprom mac address */ 24462306a36Sopenharmony_ci unsigned long serial_number; 24562306a36Sopenharmony_ci int vendor_specific_offset; 24662306a36Sopenharmony_ci int fw_multicast_support; 24762306a36Sopenharmony_ci u32 features; 24862306a36Sopenharmony_ci u32 max_tso6; 24962306a36Sopenharmony_ci u32 read_dma; 25062306a36Sopenharmony_ci u32 write_dma; 25162306a36Sopenharmony_ci u32 read_write_dma; 25262306a36Sopenharmony_ci u32 link_changes; 25362306a36Sopenharmony_ci u32 msg_enable; 25462306a36Sopenharmony_ci unsigned int board_number; 25562306a36Sopenharmony_ci int rebooted; 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic char *myri10ge_fw_unaligned = "myri10ge_ethp_z8e.dat"; 25962306a36Sopenharmony_cistatic char *myri10ge_fw_aligned = "myri10ge_eth_z8e.dat"; 26062306a36Sopenharmony_cistatic char *myri10ge_fw_rss_unaligned = "myri10ge_rss_ethp_z8e.dat"; 26162306a36Sopenharmony_cistatic char *myri10ge_fw_rss_aligned = "myri10ge_rss_eth_z8e.dat"; 26262306a36Sopenharmony_ciMODULE_FIRMWARE("myri10ge_ethp_z8e.dat"); 26362306a36Sopenharmony_ciMODULE_FIRMWARE("myri10ge_eth_z8e.dat"); 26462306a36Sopenharmony_ciMODULE_FIRMWARE("myri10ge_rss_ethp_z8e.dat"); 26562306a36Sopenharmony_ciMODULE_FIRMWARE("myri10ge_rss_eth_z8e.dat"); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci/* Careful: must be accessed under kernel_param_lock() */ 26862306a36Sopenharmony_cistatic char *myri10ge_fw_name = NULL; 26962306a36Sopenharmony_cimodule_param(myri10ge_fw_name, charp, 0644); 27062306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name"); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci#define MYRI10GE_MAX_BOARDS 8 27362306a36Sopenharmony_cistatic char *myri10ge_fw_names[MYRI10GE_MAX_BOARDS] = 27462306a36Sopenharmony_ci {[0 ... (MYRI10GE_MAX_BOARDS - 1)] = NULL }; 27562306a36Sopenharmony_cimodule_param_array_named(myri10ge_fw_names, myri10ge_fw_names, charp, NULL, 27662306a36Sopenharmony_ci 0444); 27762306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_fw_names, "Firmware image names per board"); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int myri10ge_ecrc_enable = 1; 28062306a36Sopenharmony_cimodule_param(myri10ge_ecrc_enable, int, 0444); 28162306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_ecrc_enable, "Enable Extended CRC on PCI-E"); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int myri10ge_small_bytes = -1; /* -1 == auto */ 28462306a36Sopenharmony_cimodule_param(myri10ge_small_bytes, int, 0644); 28562306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_small_bytes, "Threshold of small packets"); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic int myri10ge_msi = 1; /* enable msi by default */ 28862306a36Sopenharmony_cimodule_param(myri10ge_msi, int, 0644); 28962306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_msi, "Enable Message Signalled Interrupts"); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int myri10ge_intr_coal_delay = 75; 29262306a36Sopenharmony_cimodule_param(myri10ge_intr_coal_delay, int, 0444); 29362306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_intr_coal_delay, "Interrupt coalescing delay"); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic int myri10ge_flow_control = 1; 29662306a36Sopenharmony_cimodule_param(myri10ge_flow_control, int, 0444); 29762306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_flow_control, "Pause parameter"); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int myri10ge_deassert_wait = 1; 30062306a36Sopenharmony_cimodule_param(myri10ge_deassert_wait, int, 0644); 30162306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_deassert_wait, 30262306a36Sopenharmony_ci "Wait when deasserting legacy interrupts"); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic int myri10ge_force_firmware = 0; 30562306a36Sopenharmony_cimodule_param(myri10ge_force_firmware, int, 0444); 30662306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_force_firmware, 30762306a36Sopenharmony_ci "Force firmware to assume aligned completions"); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic int myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN; 31062306a36Sopenharmony_cimodule_param(myri10ge_initial_mtu, int, 0444); 31162306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_initial_mtu, "Initial MTU"); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int myri10ge_napi_weight = 64; 31462306a36Sopenharmony_cimodule_param(myri10ge_napi_weight, int, 0444); 31562306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_napi_weight, "Set NAPI weight"); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int myri10ge_watchdog_timeout = 1; 31862306a36Sopenharmony_cimodule_param(myri10ge_watchdog_timeout, int, 0444); 31962306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_watchdog_timeout, "Set watchdog timeout"); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic int myri10ge_max_irq_loops = 1048576; 32262306a36Sopenharmony_cimodule_param(myri10ge_max_irq_loops, int, 0444); 32362306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_max_irq_loops, 32462306a36Sopenharmony_ci "Set stuck legacy IRQ detection threshold"); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci#define MYRI10GE_MSG_DEFAULT NETIF_MSG_LINK 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic int myri10ge_debug = -1; /* defaults above */ 32962306a36Sopenharmony_cimodule_param(myri10ge_debug, int, 0); 33062306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)"); 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic int myri10ge_fill_thresh = 256; 33362306a36Sopenharmony_cimodule_param(myri10ge_fill_thresh, int, 0644); 33462306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed"); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int myri10ge_reset_recover = 1; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int myri10ge_max_slices = 1; 33962306a36Sopenharmony_cimodule_param(myri10ge_max_slices, int, 0444); 34062306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_max_slices, "Max tx/rx queues"); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_DST_PORT; 34362306a36Sopenharmony_cimodule_param(myri10ge_rss_hash, int, 0444); 34462306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_rss_hash, "Type of RSS hashing to do"); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic int myri10ge_dca = 1; 34762306a36Sopenharmony_cimodule_param(myri10ge_dca, int, 0444); 34862306a36Sopenharmony_ciMODULE_PARM_DESC(myri10ge_dca, "Enable DCA if possible"); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci#define MYRI10GE_FW_OFFSET 1024*1024 35162306a36Sopenharmony_ci#define MYRI10GE_HIGHPART_TO_U32(X) \ 35262306a36Sopenharmony_ci(sizeof (X) == 8) ? ((u32)((u64)(X) >> 32)) : (0) 35362306a36Sopenharmony_ci#define MYRI10GE_LOWPART_TO_U32(X) ((u32)(X)) 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci#define myri10ge_pio_copy(to,from,size) __iowrite64_copy(to,from,size/8) 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic void myri10ge_set_multicast_list(struct net_device *dev); 35862306a36Sopenharmony_cistatic netdev_tx_t myri10ge_sw_tso(struct sk_buff *skb, 35962306a36Sopenharmony_ci struct net_device *dev); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic inline void put_be32(__be32 val, __be32 __iomem * p) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci __raw_writel((__force __u32) val, (__force void __iomem *)p); 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic void myri10ge_get_stats(struct net_device *dev, 36762306a36Sopenharmony_ci struct rtnl_link_stats64 *stats); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic void set_fw_name(struct myri10ge_priv *mgp, char *name, bool allocated) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci if (mgp->fw_name_allocated) 37262306a36Sopenharmony_ci kfree(mgp->fw_name); 37362306a36Sopenharmony_ci mgp->fw_name = name; 37462306a36Sopenharmony_ci mgp->fw_name_allocated = allocated; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int 37862306a36Sopenharmony_cimyri10ge_send_cmd(struct myri10ge_priv *mgp, u32 cmd, 37962306a36Sopenharmony_ci struct myri10ge_cmd *data, int atomic) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct mcp_cmd *buf; 38262306a36Sopenharmony_ci char buf_bytes[sizeof(*buf) + 8]; 38362306a36Sopenharmony_ci struct mcp_cmd_response *response = mgp->cmd; 38462306a36Sopenharmony_ci char __iomem *cmd_addr = mgp->sram + MXGEFW_ETH_CMD; 38562306a36Sopenharmony_ci u32 dma_low, dma_high, result, value; 38662306a36Sopenharmony_ci int sleep_total = 0; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* ensure buf is aligned to 8 bytes */ 38962306a36Sopenharmony_ci buf = (struct mcp_cmd *)ALIGN((unsigned long)buf_bytes, 8); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci buf->data0 = htonl(data->data0); 39262306a36Sopenharmony_ci buf->data1 = htonl(data->data1); 39362306a36Sopenharmony_ci buf->data2 = htonl(data->data2); 39462306a36Sopenharmony_ci buf->cmd = htonl(cmd); 39562306a36Sopenharmony_ci dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus); 39662306a36Sopenharmony_ci dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci buf->response_addr.low = htonl(dma_low); 39962306a36Sopenharmony_ci buf->response_addr.high = htonl(dma_high); 40062306a36Sopenharmony_ci response->result = htonl(MYRI10GE_NO_RESPONSE_RESULT); 40162306a36Sopenharmony_ci mb(); 40262306a36Sopenharmony_ci myri10ge_pio_copy(cmd_addr, buf, sizeof(*buf)); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* wait up to 15ms. Longest command is the DMA benchmark, 40562306a36Sopenharmony_ci * which is capped at 5ms, but runs from a timeout handler 40662306a36Sopenharmony_ci * that runs every 7.8ms. So a 15ms timeout leaves us with 40762306a36Sopenharmony_ci * a 2.2ms margin 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_ci if (atomic) { 41062306a36Sopenharmony_ci /* if atomic is set, do not sleep, 41162306a36Sopenharmony_ci * and try to get the completion quickly 41262306a36Sopenharmony_ci * (1ms will be enough for those commands) */ 41362306a36Sopenharmony_ci for (sleep_total = 0; 41462306a36Sopenharmony_ci sleep_total < 1000 && 41562306a36Sopenharmony_ci response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT); 41662306a36Sopenharmony_ci sleep_total += 10) { 41762306a36Sopenharmony_ci udelay(10); 41862306a36Sopenharmony_ci mb(); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci } else { 42162306a36Sopenharmony_ci /* use msleep for most command */ 42262306a36Sopenharmony_ci for (sleep_total = 0; 42362306a36Sopenharmony_ci sleep_total < 15 && 42462306a36Sopenharmony_ci response->result == htonl(MYRI10GE_NO_RESPONSE_RESULT); 42562306a36Sopenharmony_ci sleep_total++) 42662306a36Sopenharmony_ci msleep(1); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci result = ntohl(response->result); 43062306a36Sopenharmony_ci value = ntohl(response->data); 43162306a36Sopenharmony_ci if (result != MYRI10GE_NO_RESPONSE_RESULT) { 43262306a36Sopenharmony_ci if (result == 0) { 43362306a36Sopenharmony_ci data->data0 = value; 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci } else if (result == MXGEFW_CMD_UNKNOWN) { 43662306a36Sopenharmony_ci return -ENOSYS; 43762306a36Sopenharmony_ci } else if (result == MXGEFW_CMD_ERROR_UNALIGNED) { 43862306a36Sopenharmony_ci return -E2BIG; 43962306a36Sopenharmony_ci } else if (result == MXGEFW_CMD_ERROR_RANGE && 44062306a36Sopenharmony_ci cmd == MXGEFW_CMD_ENABLE_RSS_QUEUES && 44162306a36Sopenharmony_ci (data-> 44262306a36Sopenharmony_ci data1 & MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES) != 44362306a36Sopenharmony_ci 0) { 44462306a36Sopenharmony_ci return -ERANGE; 44562306a36Sopenharmony_ci } else { 44662306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, 44762306a36Sopenharmony_ci "command %d failed, result = %d\n", 44862306a36Sopenharmony_ci cmd, result); 44962306a36Sopenharmony_ci return -ENXIO; 45062306a36Sopenharmony_ci } 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, "command %d timed out, result = %d\n", 45462306a36Sopenharmony_ci cmd, result); 45562306a36Sopenharmony_ci return -EAGAIN; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci/* 45962306a36Sopenharmony_ci * The eeprom strings on the lanaiX have the format 46062306a36Sopenharmony_ci * SN=x\0 46162306a36Sopenharmony_ci * MAC=x:x:x:x:x:x\0 46262306a36Sopenharmony_ci * PT:ddd mmm xx xx:xx:xx xx\0 46362306a36Sopenharmony_ci * PV:ddd mmm xx xx:xx:xx xx\0 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_cistatic int myri10ge_read_mac_addr(struct myri10ge_priv *mgp) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci char *ptr, *limit; 46862306a36Sopenharmony_ci int i; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci ptr = mgp->eeprom_strings; 47162306a36Sopenharmony_ci limit = mgp->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci while (*ptr != '\0' && ptr < limit) { 47462306a36Sopenharmony_ci if (memcmp(ptr, "MAC=", 4) == 0) { 47562306a36Sopenharmony_ci ptr += 4; 47662306a36Sopenharmony_ci mgp->mac_addr_string = ptr; 47762306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 47862306a36Sopenharmony_ci if ((ptr + 2) > limit) 47962306a36Sopenharmony_ci goto abort; 48062306a36Sopenharmony_ci mgp->mac_addr[i] = 48162306a36Sopenharmony_ci simple_strtoul(ptr, &ptr, 16); 48262306a36Sopenharmony_ci ptr += 1; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci if (memcmp(ptr, "PC=", 3) == 0) { 48662306a36Sopenharmony_ci ptr += 3; 48762306a36Sopenharmony_ci mgp->product_code_string = ptr; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci if (memcmp((const void *)ptr, "SN=", 3) == 0) { 49062306a36Sopenharmony_ci ptr += 3; 49162306a36Sopenharmony_ci mgp->serial_number = simple_strtoul(ptr, &ptr, 10); 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci while (ptr < limit && *ptr++) ; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci return 0; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ciabort: 49962306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, "failed to parse eeprom_strings\n"); 50062306a36Sopenharmony_ci return -ENXIO; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci/* 50462306a36Sopenharmony_ci * Enable or disable periodic RDMAs from the host to make certain 50562306a36Sopenharmony_ci * chipsets resend dropped PCIe messages 50662306a36Sopenharmony_ci */ 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic void myri10ge_dummy_rdma(struct myri10ge_priv *mgp, int enable) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci char __iomem *submit; 51162306a36Sopenharmony_ci __be32 buf[16] __attribute__ ((__aligned__(8))); 51262306a36Sopenharmony_ci u32 dma_low, dma_high; 51362306a36Sopenharmony_ci int i; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* clear confirmation addr */ 51662306a36Sopenharmony_ci mgp->cmd->data = 0; 51762306a36Sopenharmony_ci mb(); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* send a rdma command to the PCIe engine, and wait for the 52062306a36Sopenharmony_ci * response in the confirmation address. The firmware should 52162306a36Sopenharmony_ci * write a -1 there to indicate it is alive and well 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_ci dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus); 52462306a36Sopenharmony_ci dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci buf[0] = htonl(dma_high); /* confirm addr MSW */ 52762306a36Sopenharmony_ci buf[1] = htonl(dma_low); /* confirm addr LSW */ 52862306a36Sopenharmony_ci buf[2] = MYRI10GE_NO_CONFIRM_DATA; /* confirm data */ 52962306a36Sopenharmony_ci buf[3] = htonl(dma_high); /* dummy addr MSW */ 53062306a36Sopenharmony_ci buf[4] = htonl(dma_low); /* dummy addr LSW */ 53162306a36Sopenharmony_ci buf[5] = htonl(enable); /* enable? */ 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci submit = mgp->sram + MXGEFW_BOOT_DUMMY_RDMA; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci myri10ge_pio_copy(submit, &buf, sizeof(buf)); 53662306a36Sopenharmony_ci for (i = 0; mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 20; i++) 53762306a36Sopenharmony_ci msleep(1); 53862306a36Sopenharmony_ci if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA) 53962306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, "dummy rdma %s failed\n", 54062306a36Sopenharmony_ci (enable ? "enable" : "disable")); 54162306a36Sopenharmony_ci} 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_cistatic int 54462306a36Sopenharmony_cimyri10ge_validate_firmware(struct myri10ge_priv *mgp, 54562306a36Sopenharmony_ci struct mcp_gen_header *hdr) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci struct device *dev = &mgp->pdev->dev; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* check firmware type */ 55062306a36Sopenharmony_ci if (ntohl(hdr->mcp_type) != MCP_TYPE_ETH) { 55162306a36Sopenharmony_ci dev_err(dev, "Bad firmware type: 0x%x\n", ntohl(hdr->mcp_type)); 55262306a36Sopenharmony_ci return -EINVAL; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci /* save firmware version for ethtool */ 55662306a36Sopenharmony_ci strscpy(mgp->fw_version, hdr->version, sizeof(mgp->fw_version)); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci sscanf(mgp->fw_version, "%d.%d.%d", &mgp->fw_ver_major, 55962306a36Sopenharmony_ci &mgp->fw_ver_minor, &mgp->fw_ver_tiny); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (!(mgp->fw_ver_major == MXGEFW_VERSION_MAJOR && 56262306a36Sopenharmony_ci mgp->fw_ver_minor == MXGEFW_VERSION_MINOR)) { 56362306a36Sopenharmony_ci dev_err(dev, "Found firmware version %s\n", mgp->fw_version); 56462306a36Sopenharmony_ci dev_err(dev, "Driver needs %d.%d\n", MXGEFW_VERSION_MAJOR, 56562306a36Sopenharmony_ci MXGEFW_VERSION_MINOR); 56662306a36Sopenharmony_ci return -EINVAL; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci return 0; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic int myri10ge_load_hotplug_firmware(struct myri10ge_priv *mgp, u32 * size) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci unsigned crc, reread_crc; 57462306a36Sopenharmony_ci const struct firmware *fw; 57562306a36Sopenharmony_ci struct device *dev = &mgp->pdev->dev; 57662306a36Sopenharmony_ci unsigned char *fw_readback; 57762306a36Sopenharmony_ci struct mcp_gen_header *hdr; 57862306a36Sopenharmony_ci size_t hdr_offset; 57962306a36Sopenharmony_ci int status; 58062306a36Sopenharmony_ci unsigned i; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (request_firmware(&fw, mgp->fw_name, dev) < 0) { 58362306a36Sopenharmony_ci dev_err(dev, "Unable to load %s firmware image via hotplug\n", 58462306a36Sopenharmony_ci mgp->fw_name); 58562306a36Sopenharmony_ci status = -EINVAL; 58662306a36Sopenharmony_ci goto abort_with_nothing; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* check size */ 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (fw->size >= mgp->sram_size - MYRI10GE_FW_OFFSET || 59262306a36Sopenharmony_ci fw->size < MCP_HEADER_PTR_OFFSET + 4) { 59362306a36Sopenharmony_ci dev_err(dev, "Firmware size invalid:%d\n", (int)fw->size); 59462306a36Sopenharmony_ci status = -EINVAL; 59562306a36Sopenharmony_ci goto abort_with_fw; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci /* check id */ 59962306a36Sopenharmony_ci hdr_offset = ntohl(*(__be32 *) (fw->data + MCP_HEADER_PTR_OFFSET)); 60062306a36Sopenharmony_ci if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > fw->size) { 60162306a36Sopenharmony_ci dev_err(dev, "Bad firmware file\n"); 60262306a36Sopenharmony_ci status = -EINVAL; 60362306a36Sopenharmony_ci goto abort_with_fw; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci hdr = (void *)(fw->data + hdr_offset); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci status = myri10ge_validate_firmware(mgp, hdr); 60862306a36Sopenharmony_ci if (status != 0) 60962306a36Sopenharmony_ci goto abort_with_fw; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci crc = crc32(~0, fw->data, fw->size); 61262306a36Sopenharmony_ci for (i = 0; i < fw->size; i += 256) { 61362306a36Sopenharmony_ci myri10ge_pio_copy(mgp->sram + MYRI10GE_FW_OFFSET + i, 61462306a36Sopenharmony_ci fw->data + i, 61562306a36Sopenharmony_ci min(256U, (unsigned)(fw->size - i))); 61662306a36Sopenharmony_ci mb(); 61762306a36Sopenharmony_ci readb(mgp->sram); 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci fw_readback = vmalloc(fw->size); 62062306a36Sopenharmony_ci if (!fw_readback) { 62162306a36Sopenharmony_ci status = -ENOMEM; 62262306a36Sopenharmony_ci goto abort_with_fw; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci /* corruption checking is good for parity recovery and buggy chipset */ 62562306a36Sopenharmony_ci memcpy_fromio(fw_readback, mgp->sram + MYRI10GE_FW_OFFSET, fw->size); 62662306a36Sopenharmony_ci reread_crc = crc32(~0, fw_readback, fw->size); 62762306a36Sopenharmony_ci vfree(fw_readback); 62862306a36Sopenharmony_ci if (crc != reread_crc) { 62962306a36Sopenharmony_ci dev_err(dev, "CRC failed(fw-len=%u), got 0x%x (expect 0x%x)\n", 63062306a36Sopenharmony_ci (unsigned)fw->size, reread_crc, crc); 63162306a36Sopenharmony_ci status = -EIO; 63262306a36Sopenharmony_ci goto abort_with_fw; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci *size = (u32) fw->size; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ciabort_with_fw: 63762306a36Sopenharmony_ci release_firmware(fw); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ciabort_with_nothing: 64062306a36Sopenharmony_ci return status; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_cistatic int myri10ge_adopt_running_firmware(struct myri10ge_priv *mgp) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci struct mcp_gen_header *hdr; 64662306a36Sopenharmony_ci struct device *dev = &mgp->pdev->dev; 64762306a36Sopenharmony_ci const size_t bytes = sizeof(struct mcp_gen_header); 64862306a36Sopenharmony_ci size_t hdr_offset; 64962306a36Sopenharmony_ci int status; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* find running firmware header */ 65262306a36Sopenharmony_ci hdr_offset = swab32(readl(mgp->sram + MCP_HEADER_PTR_OFFSET)); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if ((hdr_offset & 3) || hdr_offset + sizeof(*hdr) > mgp->sram_size) { 65562306a36Sopenharmony_ci dev_err(dev, "Running firmware has bad header offset (%d)\n", 65662306a36Sopenharmony_ci (int)hdr_offset); 65762306a36Sopenharmony_ci return -EIO; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci /* copy header of running firmware from SRAM to host memory to 66162306a36Sopenharmony_ci * validate firmware */ 66262306a36Sopenharmony_ci hdr = kmalloc(bytes, GFP_KERNEL); 66362306a36Sopenharmony_ci if (hdr == NULL) 66462306a36Sopenharmony_ci return -ENOMEM; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci memcpy_fromio(hdr, mgp->sram + hdr_offset, bytes); 66762306a36Sopenharmony_ci status = myri10ge_validate_firmware(mgp, hdr); 66862306a36Sopenharmony_ci kfree(hdr); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* check to see if adopted firmware has bug where adopting 67162306a36Sopenharmony_ci * it will cause broadcasts to be filtered unless the NIC 67262306a36Sopenharmony_ci * is kept in ALLMULTI mode */ 67362306a36Sopenharmony_ci if (mgp->fw_ver_major == 1 && mgp->fw_ver_minor == 4 && 67462306a36Sopenharmony_ci mgp->fw_ver_tiny >= 4 && mgp->fw_ver_tiny <= 11) { 67562306a36Sopenharmony_ci mgp->adopted_rx_filter_bug = 1; 67662306a36Sopenharmony_ci dev_warn(dev, "Adopting fw %d.%d.%d: " 67762306a36Sopenharmony_ci "working around rx filter bug\n", 67862306a36Sopenharmony_ci mgp->fw_ver_major, mgp->fw_ver_minor, 67962306a36Sopenharmony_ci mgp->fw_ver_tiny); 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci return status; 68262306a36Sopenharmony_ci} 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_cistatic int myri10ge_get_firmware_capabilities(struct myri10ge_priv *mgp) 68562306a36Sopenharmony_ci{ 68662306a36Sopenharmony_ci struct myri10ge_cmd cmd; 68762306a36Sopenharmony_ci int status; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* probe for IPv6 TSO support */ 69062306a36Sopenharmony_ci mgp->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_TSO; 69162306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE, 69262306a36Sopenharmony_ci &cmd, 0); 69362306a36Sopenharmony_ci if (status == 0) { 69462306a36Sopenharmony_ci mgp->max_tso6 = cmd.data0; 69562306a36Sopenharmony_ci mgp->features |= NETIF_F_TSO6; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0); 69962306a36Sopenharmony_ci if (status != 0) { 70062306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, 70162306a36Sopenharmony_ci "failed MXGEFW_CMD_GET_RX_RING_SIZE\n"); 70262306a36Sopenharmony_ci return -ENXIO; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci mgp->max_intr_slots = 2 * (cmd.data0 / sizeof(struct mcp_dma_addr)); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci return 0; 70862306a36Sopenharmony_ci} 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_cistatic int myri10ge_load_firmware(struct myri10ge_priv *mgp, int adopt) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci char __iomem *submit; 71362306a36Sopenharmony_ci __be32 buf[16] __attribute__ ((__aligned__(8))); 71462306a36Sopenharmony_ci u32 dma_low, dma_high, size; 71562306a36Sopenharmony_ci int status, i; 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci size = 0; 71862306a36Sopenharmony_ci status = myri10ge_load_hotplug_firmware(mgp, &size); 71962306a36Sopenharmony_ci if (status) { 72062306a36Sopenharmony_ci if (!adopt) 72162306a36Sopenharmony_ci return status; 72262306a36Sopenharmony_ci dev_warn(&mgp->pdev->dev, "hotplug firmware loading failed\n"); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* Do not attempt to adopt firmware if there 72562306a36Sopenharmony_ci * was a bad crc */ 72662306a36Sopenharmony_ci if (status == -EIO) 72762306a36Sopenharmony_ci return status; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci status = myri10ge_adopt_running_firmware(mgp); 73062306a36Sopenharmony_ci if (status != 0) { 73162306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, 73262306a36Sopenharmony_ci "failed to adopt running firmware\n"); 73362306a36Sopenharmony_ci return status; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci dev_info(&mgp->pdev->dev, 73662306a36Sopenharmony_ci "Successfully adopted running firmware\n"); 73762306a36Sopenharmony_ci if (mgp->tx_boundary == 4096) { 73862306a36Sopenharmony_ci dev_warn(&mgp->pdev->dev, 73962306a36Sopenharmony_ci "Using firmware currently running on NIC" 74062306a36Sopenharmony_ci ". For optimal\n"); 74162306a36Sopenharmony_ci dev_warn(&mgp->pdev->dev, 74262306a36Sopenharmony_ci "performance consider loading optimized " 74362306a36Sopenharmony_ci "firmware\n"); 74462306a36Sopenharmony_ci dev_warn(&mgp->pdev->dev, "via hotplug\n"); 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci set_fw_name(mgp, "adopted", false); 74862306a36Sopenharmony_ci mgp->tx_boundary = 2048; 74962306a36Sopenharmony_ci myri10ge_dummy_rdma(mgp, 1); 75062306a36Sopenharmony_ci status = myri10ge_get_firmware_capabilities(mgp); 75162306a36Sopenharmony_ci return status; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* clear confirmation addr */ 75562306a36Sopenharmony_ci mgp->cmd->data = 0; 75662306a36Sopenharmony_ci mb(); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci /* send a reload command to the bootstrap MCP, and wait for the 75962306a36Sopenharmony_ci * response in the confirmation address. The firmware should 76062306a36Sopenharmony_ci * write a -1 there to indicate it is alive and well 76162306a36Sopenharmony_ci */ 76262306a36Sopenharmony_ci dma_low = MYRI10GE_LOWPART_TO_U32(mgp->cmd_bus); 76362306a36Sopenharmony_ci dma_high = MYRI10GE_HIGHPART_TO_U32(mgp->cmd_bus); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci buf[0] = htonl(dma_high); /* confirm addr MSW */ 76662306a36Sopenharmony_ci buf[1] = htonl(dma_low); /* confirm addr LSW */ 76762306a36Sopenharmony_ci buf[2] = MYRI10GE_NO_CONFIRM_DATA; /* confirm data */ 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* FIX: All newest firmware should un-protect the bottom of 77062306a36Sopenharmony_ci * the sram before handoff. However, the very first interfaces 77162306a36Sopenharmony_ci * do not. Therefore the handoff copy must skip the first 8 bytes 77262306a36Sopenharmony_ci */ 77362306a36Sopenharmony_ci buf[3] = htonl(MYRI10GE_FW_OFFSET + 8); /* where the code starts */ 77462306a36Sopenharmony_ci buf[4] = htonl(size - 8); /* length of code */ 77562306a36Sopenharmony_ci buf[5] = htonl(8); /* where to copy to */ 77662306a36Sopenharmony_ci buf[6] = htonl(0); /* where to jump to */ 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci submit = mgp->sram + MXGEFW_BOOT_HANDOFF; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci myri10ge_pio_copy(submit, &buf, sizeof(buf)); 78162306a36Sopenharmony_ci mb(); 78262306a36Sopenharmony_ci msleep(1); 78362306a36Sopenharmony_ci mb(); 78462306a36Sopenharmony_ci i = 0; 78562306a36Sopenharmony_ci while (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA && i < 9) { 78662306a36Sopenharmony_ci msleep(1 << i); 78762306a36Sopenharmony_ci i++; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci if (mgp->cmd->data != MYRI10GE_NO_CONFIRM_DATA) { 79062306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, "handoff failed\n"); 79162306a36Sopenharmony_ci return -ENXIO; 79262306a36Sopenharmony_ci } 79362306a36Sopenharmony_ci myri10ge_dummy_rdma(mgp, 1); 79462306a36Sopenharmony_ci status = myri10ge_get_firmware_capabilities(mgp); 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci return status; 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_cistatic int myri10ge_update_mac_address(struct myri10ge_priv *mgp, 80062306a36Sopenharmony_ci const u8 * addr) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci struct myri10ge_cmd cmd; 80362306a36Sopenharmony_ci int status; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci cmd.data0 = ((addr[0] << 24) | (addr[1] << 16) 80662306a36Sopenharmony_ci | (addr[2] << 8) | addr[3]); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci cmd.data1 = ((addr[4] << 8) | (addr[5])); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_SET_MAC_ADDRESS, &cmd, 0); 81162306a36Sopenharmony_ci return status; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int myri10ge_change_pause(struct myri10ge_priv *mgp, int pause) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct myri10ge_cmd cmd; 81762306a36Sopenharmony_ci int status, ctl; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci ctl = pause ? MXGEFW_ENABLE_FLOW_CONTROL : MXGEFW_DISABLE_FLOW_CONTROL; 82062306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, ctl, &cmd, 0); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci if (status) { 82362306a36Sopenharmony_ci netdev_err(mgp->dev, "Failed to set flow control mode\n"); 82462306a36Sopenharmony_ci return status; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci mgp->pause = pause; 82762306a36Sopenharmony_ci return 0; 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_cistatic void 83162306a36Sopenharmony_cimyri10ge_change_promisc(struct myri10ge_priv *mgp, int promisc, int atomic) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci struct myri10ge_cmd cmd; 83462306a36Sopenharmony_ci int status, ctl; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci ctl = promisc ? MXGEFW_ENABLE_PROMISC : MXGEFW_DISABLE_PROMISC; 83762306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, ctl, &cmd, atomic); 83862306a36Sopenharmony_ci if (status) 83962306a36Sopenharmony_ci netdev_err(mgp->dev, "Failed to set promisc mode\n"); 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_cistatic int myri10ge_dma_test(struct myri10ge_priv *mgp, int test_type) 84362306a36Sopenharmony_ci{ 84462306a36Sopenharmony_ci struct myri10ge_cmd cmd; 84562306a36Sopenharmony_ci int status; 84662306a36Sopenharmony_ci u32 len; 84762306a36Sopenharmony_ci struct page *dmatest_page; 84862306a36Sopenharmony_ci dma_addr_t dmatest_bus; 84962306a36Sopenharmony_ci char *test = " "; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci dmatest_page = alloc_page(GFP_KERNEL); 85262306a36Sopenharmony_ci if (!dmatest_page) 85362306a36Sopenharmony_ci return -ENOMEM; 85462306a36Sopenharmony_ci dmatest_bus = dma_map_page(&mgp->pdev->dev, dmatest_page, 0, 85562306a36Sopenharmony_ci PAGE_SIZE, DMA_BIDIRECTIONAL); 85662306a36Sopenharmony_ci if (unlikely(dma_mapping_error(&mgp->pdev->dev, dmatest_bus))) { 85762306a36Sopenharmony_ci __free_page(dmatest_page); 85862306a36Sopenharmony_ci return -ENOMEM; 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci /* Run a small DMA test. 86262306a36Sopenharmony_ci * The magic multipliers to the length tell the firmware 86362306a36Sopenharmony_ci * to do DMA read, write, or read+write tests. The 86462306a36Sopenharmony_ci * results are returned in cmd.data0. The upper 16 86562306a36Sopenharmony_ci * bits or the return is the number of transfers completed. 86662306a36Sopenharmony_ci * The lower 16 bits is the time in 0.5us ticks that the 86762306a36Sopenharmony_ci * transfers took to complete. 86862306a36Sopenharmony_ci */ 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci len = mgp->tx_boundary; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); 87362306a36Sopenharmony_ci cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); 87462306a36Sopenharmony_ci cmd.data2 = len * 0x10000; 87562306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, test_type, &cmd, 0); 87662306a36Sopenharmony_ci if (status != 0) { 87762306a36Sopenharmony_ci test = "read"; 87862306a36Sopenharmony_ci goto abort; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci mgp->read_dma = ((cmd.data0 >> 16) * len * 2) / (cmd.data0 & 0xffff); 88162306a36Sopenharmony_ci cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); 88262306a36Sopenharmony_ci cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); 88362306a36Sopenharmony_ci cmd.data2 = len * 0x1; 88462306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, test_type, &cmd, 0); 88562306a36Sopenharmony_ci if (status != 0) { 88662306a36Sopenharmony_ci test = "write"; 88762306a36Sopenharmony_ci goto abort; 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci mgp->write_dma = ((cmd.data0 >> 16) * len * 2) / (cmd.data0 & 0xffff); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci cmd.data0 = MYRI10GE_LOWPART_TO_U32(dmatest_bus); 89262306a36Sopenharmony_ci cmd.data1 = MYRI10GE_HIGHPART_TO_U32(dmatest_bus); 89362306a36Sopenharmony_ci cmd.data2 = len * 0x10001; 89462306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, test_type, &cmd, 0); 89562306a36Sopenharmony_ci if (status != 0) { 89662306a36Sopenharmony_ci test = "read/write"; 89762306a36Sopenharmony_ci goto abort; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci mgp->read_write_dma = ((cmd.data0 >> 16) * len * 2 * 2) / 90062306a36Sopenharmony_ci (cmd.data0 & 0xffff); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ciabort: 90362306a36Sopenharmony_ci dma_unmap_page(&mgp->pdev->dev, dmatest_bus, PAGE_SIZE, 90462306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 90562306a36Sopenharmony_ci put_page(dmatest_page); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci if (status != 0 && test_type != MXGEFW_CMD_UNALIGNED_TEST) 90862306a36Sopenharmony_ci dev_warn(&mgp->pdev->dev, "DMA %s benchmark failed: %d\n", 90962306a36Sopenharmony_ci test, status); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci return status; 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic int myri10ge_reset(struct myri10ge_priv *mgp) 91562306a36Sopenharmony_ci{ 91662306a36Sopenharmony_ci struct myri10ge_cmd cmd; 91762306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 91862306a36Sopenharmony_ci int i, status; 91962306a36Sopenharmony_ci size_t bytes; 92062306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 92162306a36Sopenharmony_ci unsigned long dca_tag_off; 92262306a36Sopenharmony_ci#endif 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* try to send a reset command to the card to see if it 92562306a36Sopenharmony_ci * is alive */ 92662306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 92762306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_RESET, &cmd, 0); 92862306a36Sopenharmony_ci if (status != 0) { 92962306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, "failed reset\n"); 93062306a36Sopenharmony_ci return -ENXIO; 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci (void)myri10ge_dma_test(mgp, MXGEFW_DMA_TEST); 93462306a36Sopenharmony_ci /* 93562306a36Sopenharmony_ci * Use non-ndis mcp_slot (eg, 4 bytes total, 93662306a36Sopenharmony_ci * no toeplitz hash value returned. Older firmware will 93762306a36Sopenharmony_ci * not understand this command, but will use the correct 93862306a36Sopenharmony_ci * sized mcp_slot, so we ignore error returns 93962306a36Sopenharmony_ci */ 94062306a36Sopenharmony_ci cmd.data0 = MXGEFW_RSS_MCP_SLOT_TYPE_MIN; 94162306a36Sopenharmony_ci (void)myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE, &cmd, 0); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci /* Now exchange information about interrupts */ 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci bytes = mgp->max_intr_slots * sizeof(*mgp->ss[0].rx_done.entry); 94662306a36Sopenharmony_ci cmd.data0 = (u32) bytes; 94762306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* 95062306a36Sopenharmony_ci * Even though we already know how many slices are supported 95162306a36Sopenharmony_ci * via myri10ge_probe_slices() MXGEFW_CMD_GET_MAX_RSS_QUEUES 95262306a36Sopenharmony_ci * has magic side effects, and must be called after a reset. 95362306a36Sopenharmony_ci * It must be called prior to calling any RSS related cmds, 95462306a36Sopenharmony_ci * including assigning an interrupt queue for anything but 95562306a36Sopenharmony_ci * slice 0. It must also be called *after* 95662306a36Sopenharmony_ci * MXGEFW_CMD_SET_INTRQ_SIZE, since the intrq size is used by 95762306a36Sopenharmony_ci * the firmware to compute offsets. 95862306a36Sopenharmony_ci */ 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (mgp->num_slices > 1) { 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci /* ask the maximum number of slices it supports */ 96362306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES, 96462306a36Sopenharmony_ci &cmd, 0); 96562306a36Sopenharmony_ci if (status != 0) { 96662306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, 96762306a36Sopenharmony_ci "failed to get number of slices\n"); 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* 97162306a36Sopenharmony_ci * MXGEFW_CMD_ENABLE_RSS_QUEUES must be called prior 97262306a36Sopenharmony_ci * to setting up the interrupt queue DMA 97362306a36Sopenharmony_ci */ 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci cmd.data0 = mgp->num_slices; 97662306a36Sopenharmony_ci cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; 97762306a36Sopenharmony_ci if (mgp->dev->real_num_tx_queues > 1) 97862306a36Sopenharmony_ci cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES; 97962306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES, 98062306a36Sopenharmony_ci &cmd, 0); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* Firmware older than 1.4.32 only supports multiple 98362306a36Sopenharmony_ci * RX queues, so if we get an error, first retry using a 98462306a36Sopenharmony_ci * single TX queue before giving up */ 98562306a36Sopenharmony_ci if (status != 0 && mgp->dev->real_num_tx_queues > 1) { 98662306a36Sopenharmony_ci netif_set_real_num_tx_queues(mgp->dev, 1); 98762306a36Sopenharmony_ci cmd.data0 = mgp->num_slices; 98862306a36Sopenharmony_ci cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; 98962306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, 99062306a36Sopenharmony_ci MXGEFW_CMD_ENABLE_RSS_QUEUES, 99162306a36Sopenharmony_ci &cmd, 0); 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci if (status != 0) { 99562306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, 99662306a36Sopenharmony_ci "failed to set number of slices\n"); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci return status; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 100262306a36Sopenharmony_ci ss = &mgp->ss[i]; 100362306a36Sopenharmony_ci cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->rx_done.bus); 100462306a36Sopenharmony_ci cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->rx_done.bus); 100562306a36Sopenharmony_ci cmd.data2 = i; 100662306a36Sopenharmony_ci status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA, 100762306a36Sopenharmony_ci &cmd, 0); 100862306a36Sopenharmony_ci } 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci status |= 101162306a36Sopenharmony_ci myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0); 101262306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 101362306a36Sopenharmony_ci ss = &mgp->ss[i]; 101462306a36Sopenharmony_ci ss->irq_claim = 101562306a36Sopenharmony_ci (__iomem __be32 *) (mgp->sram + cmd.data0 + 8 * i); 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, 101862306a36Sopenharmony_ci &cmd, 0); 101962306a36Sopenharmony_ci mgp->irq_deassert = (__iomem __be32 *) (mgp->sram + cmd.data0); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci status |= myri10ge_send_cmd 102262306a36Sopenharmony_ci (mgp, MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, &cmd, 0); 102362306a36Sopenharmony_ci mgp->intr_coal_delay_ptr = (__iomem __be32 *) (mgp->sram + cmd.data0); 102462306a36Sopenharmony_ci if (status != 0) { 102562306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, "failed set interrupt parameters\n"); 102662306a36Sopenharmony_ci return status; 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 103162306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_DCA_OFFSET, &cmd, 0); 103262306a36Sopenharmony_ci dca_tag_off = cmd.data0; 103362306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 103462306a36Sopenharmony_ci ss = &mgp->ss[i]; 103562306a36Sopenharmony_ci if (status == 0) { 103662306a36Sopenharmony_ci ss->dca_tag = (__iomem __be32 *) 103762306a36Sopenharmony_ci (mgp->sram + dca_tag_off + 4 * i); 103862306a36Sopenharmony_ci } else { 103962306a36Sopenharmony_ci ss->dca_tag = NULL; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci#endif /* CONFIG_MYRI10GE_DCA */ 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci /* reset mcp/driver shared state back to 0 */ 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci mgp->link_changes = 0; 104762306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 104862306a36Sopenharmony_ci ss = &mgp->ss[i]; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci memset(ss->rx_done.entry, 0, bytes); 105162306a36Sopenharmony_ci ss->tx.req = 0; 105262306a36Sopenharmony_ci ss->tx.done = 0; 105362306a36Sopenharmony_ci ss->tx.pkt_start = 0; 105462306a36Sopenharmony_ci ss->tx.pkt_done = 0; 105562306a36Sopenharmony_ci ss->rx_big.cnt = 0; 105662306a36Sopenharmony_ci ss->rx_small.cnt = 0; 105762306a36Sopenharmony_ci ss->rx_done.idx = 0; 105862306a36Sopenharmony_ci ss->rx_done.cnt = 0; 105962306a36Sopenharmony_ci ss->tx.wake_queue = 0; 106062306a36Sopenharmony_ci ss->tx.stop_queue = 0; 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci status = myri10ge_update_mac_address(mgp, mgp->dev->dev_addr); 106462306a36Sopenharmony_ci myri10ge_change_pause(mgp, mgp->pause); 106562306a36Sopenharmony_ci myri10ge_set_multicast_list(mgp->dev); 106662306a36Sopenharmony_ci return status; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 107062306a36Sopenharmony_cistatic int myri10ge_toggle_relaxed(struct pci_dev *pdev, int on) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci int ret; 107362306a36Sopenharmony_ci u16 ctl; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &ctl); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci ret = (ctl & PCI_EXP_DEVCTL_RELAX_EN) >> 4; 107862306a36Sopenharmony_ci if (ret != on) { 107962306a36Sopenharmony_ci ctl &= ~PCI_EXP_DEVCTL_RELAX_EN; 108062306a36Sopenharmony_ci ctl |= (on << 4); 108162306a36Sopenharmony_ci pcie_capability_write_word(pdev, PCI_EXP_DEVCTL, ctl); 108262306a36Sopenharmony_ci } 108362306a36Sopenharmony_ci return ret; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_cistatic void 108762306a36Sopenharmony_cimyri10ge_write_dca(struct myri10ge_slice_state *ss, int cpu, int tag) 108862306a36Sopenharmony_ci{ 108962306a36Sopenharmony_ci ss->cached_dca_tag = tag; 109062306a36Sopenharmony_ci put_be32(htonl(tag), ss->dca_tag); 109162306a36Sopenharmony_ci} 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_cistatic inline void myri10ge_update_dca(struct myri10ge_slice_state *ss) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci int cpu = get_cpu(); 109662306a36Sopenharmony_ci int tag; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (cpu != ss->cpu) { 109962306a36Sopenharmony_ci tag = dca3_get_tag(&ss->mgp->pdev->dev, cpu); 110062306a36Sopenharmony_ci if (ss->cached_dca_tag != tag) 110162306a36Sopenharmony_ci myri10ge_write_dca(ss, cpu, tag); 110262306a36Sopenharmony_ci ss->cpu = cpu; 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci put_cpu(); 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic void myri10ge_setup_dca(struct myri10ge_priv *mgp) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci int err, i; 111062306a36Sopenharmony_ci struct pci_dev *pdev = mgp->pdev; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci if (mgp->ss[0].dca_tag == NULL || mgp->dca_enabled) 111362306a36Sopenharmony_ci return; 111462306a36Sopenharmony_ci if (!myri10ge_dca) { 111562306a36Sopenharmony_ci dev_err(&pdev->dev, "dca disabled by administrator\n"); 111662306a36Sopenharmony_ci return; 111762306a36Sopenharmony_ci } 111862306a36Sopenharmony_ci err = dca_add_requester(&pdev->dev); 111962306a36Sopenharmony_ci if (err) { 112062306a36Sopenharmony_ci if (err != -ENODEV) 112162306a36Sopenharmony_ci dev_err(&pdev->dev, 112262306a36Sopenharmony_ci "dca_add_requester() failed, err=%d\n", err); 112362306a36Sopenharmony_ci return; 112462306a36Sopenharmony_ci } 112562306a36Sopenharmony_ci mgp->relaxed_order = myri10ge_toggle_relaxed(pdev, 0); 112662306a36Sopenharmony_ci mgp->dca_enabled = 1; 112762306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 112862306a36Sopenharmony_ci mgp->ss[i].cpu = -1; 112962306a36Sopenharmony_ci mgp->ss[i].cached_dca_tag = -1; 113062306a36Sopenharmony_ci myri10ge_update_dca(&mgp->ss[i]); 113162306a36Sopenharmony_ci } 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic void myri10ge_teardown_dca(struct myri10ge_priv *mgp) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci struct pci_dev *pdev = mgp->pdev; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if (!mgp->dca_enabled) 113962306a36Sopenharmony_ci return; 114062306a36Sopenharmony_ci mgp->dca_enabled = 0; 114162306a36Sopenharmony_ci if (mgp->relaxed_order) 114262306a36Sopenharmony_ci myri10ge_toggle_relaxed(pdev, 1); 114362306a36Sopenharmony_ci dca_remove_requester(&pdev->dev); 114462306a36Sopenharmony_ci} 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_cistatic int myri10ge_notify_dca_device(struct device *dev, void *data) 114762306a36Sopenharmony_ci{ 114862306a36Sopenharmony_ci struct myri10ge_priv *mgp; 114962306a36Sopenharmony_ci unsigned long event; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci mgp = dev_get_drvdata(dev); 115262306a36Sopenharmony_ci event = *(unsigned long *)data; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (event == DCA_PROVIDER_ADD) 115562306a36Sopenharmony_ci myri10ge_setup_dca(mgp); 115662306a36Sopenharmony_ci else if (event == DCA_PROVIDER_REMOVE) 115762306a36Sopenharmony_ci myri10ge_teardown_dca(mgp); 115862306a36Sopenharmony_ci return 0; 115962306a36Sopenharmony_ci} 116062306a36Sopenharmony_ci#endif /* CONFIG_MYRI10GE_DCA */ 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_cistatic inline void 116362306a36Sopenharmony_cimyri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst, 116462306a36Sopenharmony_ci struct mcp_kreq_ether_recv *src) 116562306a36Sopenharmony_ci{ 116662306a36Sopenharmony_ci __be32 low; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci low = src->addr_low; 116962306a36Sopenharmony_ci src->addr_low = htonl(DMA_BIT_MASK(32)); 117062306a36Sopenharmony_ci myri10ge_pio_copy(dst, src, 4 * sizeof(*src)); 117162306a36Sopenharmony_ci mb(); 117262306a36Sopenharmony_ci myri10ge_pio_copy(dst + 4, src + 4, 4 * sizeof(*src)); 117362306a36Sopenharmony_ci mb(); 117462306a36Sopenharmony_ci src->addr_low = low; 117562306a36Sopenharmony_ci put_be32(low, &dst->addr_low); 117662306a36Sopenharmony_ci mb(); 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic void 118062306a36Sopenharmony_cimyri10ge_alloc_rx_pages(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx, 118162306a36Sopenharmony_ci int bytes, int watchdog) 118262306a36Sopenharmony_ci{ 118362306a36Sopenharmony_ci struct page *page; 118462306a36Sopenharmony_ci dma_addr_t bus; 118562306a36Sopenharmony_ci int idx; 118662306a36Sopenharmony_ci#if MYRI10GE_ALLOC_SIZE > 4096 118762306a36Sopenharmony_ci int end_offset; 118862306a36Sopenharmony_ci#endif 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci if (unlikely(rx->watchdog_needed && !watchdog)) 119162306a36Sopenharmony_ci return; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci /* try to refill entire ring */ 119462306a36Sopenharmony_ci while (rx->fill_cnt != (rx->cnt + rx->mask + 1)) { 119562306a36Sopenharmony_ci idx = rx->fill_cnt & rx->mask; 119662306a36Sopenharmony_ci if (rx->page_offset + bytes <= MYRI10GE_ALLOC_SIZE) { 119762306a36Sopenharmony_ci /* we can use part of previous page */ 119862306a36Sopenharmony_ci get_page(rx->page); 119962306a36Sopenharmony_ci } else { 120062306a36Sopenharmony_ci /* we need a new page */ 120162306a36Sopenharmony_ci page = 120262306a36Sopenharmony_ci alloc_pages(GFP_ATOMIC | __GFP_COMP, 120362306a36Sopenharmony_ci MYRI10GE_ALLOC_ORDER); 120462306a36Sopenharmony_ci if (unlikely(page == NULL)) { 120562306a36Sopenharmony_ci if (rx->fill_cnt - rx->cnt < 16) 120662306a36Sopenharmony_ci rx->watchdog_needed = 1; 120762306a36Sopenharmony_ci return; 120862306a36Sopenharmony_ci } 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci bus = dma_map_page(&mgp->pdev->dev, page, 0, 121162306a36Sopenharmony_ci MYRI10GE_ALLOC_SIZE, 121262306a36Sopenharmony_ci DMA_FROM_DEVICE); 121362306a36Sopenharmony_ci if (unlikely(dma_mapping_error(&mgp->pdev->dev, bus))) { 121462306a36Sopenharmony_ci __free_pages(page, MYRI10GE_ALLOC_ORDER); 121562306a36Sopenharmony_ci if (rx->fill_cnt - rx->cnt < 16) 121662306a36Sopenharmony_ci rx->watchdog_needed = 1; 121762306a36Sopenharmony_ci return; 121862306a36Sopenharmony_ci } 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci rx->page = page; 122162306a36Sopenharmony_ci rx->page_offset = 0; 122262306a36Sopenharmony_ci rx->bus = bus; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci } 122562306a36Sopenharmony_ci rx->info[idx].page = rx->page; 122662306a36Sopenharmony_ci rx->info[idx].page_offset = rx->page_offset; 122762306a36Sopenharmony_ci /* note that this is the address of the start of the 122862306a36Sopenharmony_ci * page */ 122962306a36Sopenharmony_ci dma_unmap_addr_set(&rx->info[idx], bus, rx->bus); 123062306a36Sopenharmony_ci rx->shadow[idx].addr_low = 123162306a36Sopenharmony_ci htonl(MYRI10GE_LOWPART_TO_U32(rx->bus) + rx->page_offset); 123262306a36Sopenharmony_ci rx->shadow[idx].addr_high = 123362306a36Sopenharmony_ci htonl(MYRI10GE_HIGHPART_TO_U32(rx->bus)); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* start next packet on a cacheline boundary */ 123662306a36Sopenharmony_ci rx->page_offset += SKB_DATA_ALIGN(bytes); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci#if MYRI10GE_ALLOC_SIZE > 4096 123962306a36Sopenharmony_ci /* don't cross a 4KB boundary */ 124062306a36Sopenharmony_ci end_offset = rx->page_offset + bytes - 1; 124162306a36Sopenharmony_ci if ((unsigned)(rx->page_offset ^ end_offset) > 4095) 124262306a36Sopenharmony_ci rx->page_offset = end_offset & ~4095; 124362306a36Sopenharmony_ci#endif 124462306a36Sopenharmony_ci rx->fill_cnt++; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci /* copy 8 descriptors to the firmware at a time */ 124762306a36Sopenharmony_ci if ((idx & 7) == 7) { 124862306a36Sopenharmony_ci myri10ge_submit_8rx(&rx->lanai[idx - 7], 124962306a36Sopenharmony_ci &rx->shadow[idx - 7]); 125062306a36Sopenharmony_ci } 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci} 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_cistatic inline void 125562306a36Sopenharmony_cimyri10ge_unmap_rx_page(struct pci_dev *pdev, 125662306a36Sopenharmony_ci struct myri10ge_rx_buffer_state *info, int bytes) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci /* unmap the recvd page if we're the only or last user of it */ 125962306a36Sopenharmony_ci if (bytes >= MYRI10GE_ALLOC_SIZE / 2 || 126062306a36Sopenharmony_ci (info->page_offset + 2 * bytes) > MYRI10GE_ALLOC_SIZE) { 126162306a36Sopenharmony_ci dma_unmap_page(&pdev->dev, (dma_unmap_addr(info, bus) 126262306a36Sopenharmony_ci & ~(MYRI10GE_ALLOC_SIZE - 1)), 126362306a36Sopenharmony_ci MYRI10GE_ALLOC_SIZE, DMA_FROM_DEVICE); 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci} 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_ci/* 126862306a36Sopenharmony_ci * GRO does not support acceleration of tagged vlan frames, and 126962306a36Sopenharmony_ci * this NIC does not support vlan tag offload, so we must pop 127062306a36Sopenharmony_ci * the tag ourselves to be able to achieve GRO performance that 127162306a36Sopenharmony_ci * is comparable to LRO. 127262306a36Sopenharmony_ci */ 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_cistatic inline void 127562306a36Sopenharmony_cimyri10ge_vlan_rx(struct net_device *dev, void *addr, struct sk_buff *skb) 127662306a36Sopenharmony_ci{ 127762306a36Sopenharmony_ci u8 *va; 127862306a36Sopenharmony_ci struct vlan_ethhdr *veh; 127962306a36Sopenharmony_ci skb_frag_t *frag; 128062306a36Sopenharmony_ci __wsum vsum; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci va = addr; 128362306a36Sopenharmony_ci va += MXGEFW_PAD; 128462306a36Sopenharmony_ci veh = (struct vlan_ethhdr *)va; 128562306a36Sopenharmony_ci if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) == 128662306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX && 128762306a36Sopenharmony_ci veh->h_vlan_proto == htons(ETH_P_8021Q)) { 128862306a36Sopenharmony_ci /* fixup csum if needed */ 128962306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_COMPLETE) { 129062306a36Sopenharmony_ci vsum = csum_partial(va + ETH_HLEN, VLAN_HLEN, 0); 129162306a36Sopenharmony_ci skb->csum = csum_sub(skb->csum, vsum); 129262306a36Sopenharmony_ci } 129362306a36Sopenharmony_ci /* pop tag */ 129462306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(veh->h_vlan_TCI)); 129562306a36Sopenharmony_ci memmove(va + VLAN_HLEN, va, 2 * ETH_ALEN); 129662306a36Sopenharmony_ci skb->len -= VLAN_HLEN; 129762306a36Sopenharmony_ci skb->data_len -= VLAN_HLEN; 129862306a36Sopenharmony_ci frag = skb_shinfo(skb)->frags; 129962306a36Sopenharmony_ci skb_frag_off_add(frag, VLAN_HLEN); 130062306a36Sopenharmony_ci skb_frag_size_sub(frag, VLAN_HLEN); 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci} 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci#define MYRI10GE_HLEN 64 /* Bytes to copy from page to skb linear memory */ 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_cistatic inline int 130762306a36Sopenharmony_cimyri10ge_rx_done(struct myri10ge_slice_state *ss, int len, __wsum csum) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci struct myri10ge_priv *mgp = ss->mgp; 131062306a36Sopenharmony_ci struct sk_buff *skb; 131162306a36Sopenharmony_ci skb_frag_t *rx_frags; 131262306a36Sopenharmony_ci struct myri10ge_rx_buf *rx; 131362306a36Sopenharmony_ci int i, idx, remainder, bytes; 131462306a36Sopenharmony_ci struct pci_dev *pdev = mgp->pdev; 131562306a36Sopenharmony_ci struct net_device *dev = mgp->dev; 131662306a36Sopenharmony_ci u8 *va; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci if (len <= mgp->small_bytes) { 131962306a36Sopenharmony_ci rx = &ss->rx_small; 132062306a36Sopenharmony_ci bytes = mgp->small_bytes; 132162306a36Sopenharmony_ci } else { 132262306a36Sopenharmony_ci rx = &ss->rx_big; 132362306a36Sopenharmony_ci bytes = mgp->big_bytes; 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci len += MXGEFW_PAD; 132762306a36Sopenharmony_ci idx = rx->cnt & rx->mask; 132862306a36Sopenharmony_ci va = page_address(rx->info[idx].page) + rx->info[idx].page_offset; 132962306a36Sopenharmony_ci prefetch(va); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci skb = napi_get_frags(&ss->napi); 133262306a36Sopenharmony_ci if (unlikely(skb == NULL)) { 133362306a36Sopenharmony_ci ss->stats.rx_dropped++; 133462306a36Sopenharmony_ci for (i = 0, remainder = len; remainder > 0; i++) { 133562306a36Sopenharmony_ci myri10ge_unmap_rx_page(pdev, &rx->info[idx], bytes); 133662306a36Sopenharmony_ci put_page(rx->info[idx].page); 133762306a36Sopenharmony_ci rx->cnt++; 133862306a36Sopenharmony_ci idx = rx->cnt & rx->mask; 133962306a36Sopenharmony_ci remainder -= MYRI10GE_ALLOC_SIZE; 134062306a36Sopenharmony_ci } 134162306a36Sopenharmony_ci return 0; 134262306a36Sopenharmony_ci } 134362306a36Sopenharmony_ci rx_frags = skb_shinfo(skb)->frags; 134462306a36Sopenharmony_ci /* Fill skb_frag_t(s) with data from our receive */ 134562306a36Sopenharmony_ci for (i = 0, remainder = len; remainder > 0; i++) { 134662306a36Sopenharmony_ci myri10ge_unmap_rx_page(pdev, &rx->info[idx], bytes); 134762306a36Sopenharmony_ci skb_fill_page_desc(skb, i, rx->info[idx].page, 134862306a36Sopenharmony_ci rx->info[idx].page_offset, 134962306a36Sopenharmony_ci remainder < MYRI10GE_ALLOC_SIZE ? 135062306a36Sopenharmony_ci remainder : MYRI10GE_ALLOC_SIZE); 135162306a36Sopenharmony_ci rx->cnt++; 135262306a36Sopenharmony_ci idx = rx->cnt & rx->mask; 135362306a36Sopenharmony_ci remainder -= MYRI10GE_ALLOC_SIZE; 135462306a36Sopenharmony_ci } 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci /* remove padding */ 135762306a36Sopenharmony_ci skb_frag_off_add(&rx_frags[0], MXGEFW_PAD); 135862306a36Sopenharmony_ci skb_frag_size_sub(&rx_frags[0], MXGEFW_PAD); 135962306a36Sopenharmony_ci len -= MXGEFW_PAD; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci skb->len = len; 136262306a36Sopenharmony_ci skb->data_len = len; 136362306a36Sopenharmony_ci skb->truesize += len; 136462306a36Sopenharmony_ci if (dev->features & NETIF_F_RXCSUM) { 136562306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_COMPLETE; 136662306a36Sopenharmony_ci skb->csum = csum; 136762306a36Sopenharmony_ci } 136862306a36Sopenharmony_ci myri10ge_vlan_rx(mgp->dev, va, skb); 136962306a36Sopenharmony_ci skb_record_rx_queue(skb, ss - &mgp->ss[0]); 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci napi_gro_frags(&ss->napi); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci return 1; 137462306a36Sopenharmony_ci} 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_cistatic inline void 137762306a36Sopenharmony_cimyri10ge_tx_done(struct myri10ge_slice_state *ss, int mcp_index) 137862306a36Sopenharmony_ci{ 137962306a36Sopenharmony_ci struct pci_dev *pdev = ss->mgp->pdev; 138062306a36Sopenharmony_ci struct myri10ge_tx_buf *tx = &ss->tx; 138162306a36Sopenharmony_ci struct netdev_queue *dev_queue; 138262306a36Sopenharmony_ci struct sk_buff *skb; 138362306a36Sopenharmony_ci int idx, len; 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci while (tx->pkt_done != mcp_index) { 138662306a36Sopenharmony_ci idx = tx->done & tx->mask; 138762306a36Sopenharmony_ci skb = tx->info[idx].skb; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci /* Mark as free */ 139062306a36Sopenharmony_ci tx->info[idx].skb = NULL; 139162306a36Sopenharmony_ci if (tx->info[idx].last) { 139262306a36Sopenharmony_ci tx->pkt_done++; 139362306a36Sopenharmony_ci tx->info[idx].last = 0; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci tx->done++; 139662306a36Sopenharmony_ci len = dma_unmap_len(&tx->info[idx], len); 139762306a36Sopenharmony_ci dma_unmap_len_set(&tx->info[idx], len, 0); 139862306a36Sopenharmony_ci if (skb) { 139962306a36Sopenharmony_ci ss->stats.tx_bytes += skb->len; 140062306a36Sopenharmony_ci ss->stats.tx_packets++; 140162306a36Sopenharmony_ci dev_consume_skb_irq(skb); 140262306a36Sopenharmony_ci if (len) 140362306a36Sopenharmony_ci dma_unmap_single(&pdev->dev, 140462306a36Sopenharmony_ci dma_unmap_addr(&tx->info[idx], 140562306a36Sopenharmony_ci bus), len, 140662306a36Sopenharmony_ci DMA_TO_DEVICE); 140762306a36Sopenharmony_ci } else { 140862306a36Sopenharmony_ci if (len) 140962306a36Sopenharmony_ci dma_unmap_page(&pdev->dev, 141062306a36Sopenharmony_ci dma_unmap_addr(&tx->info[idx], 141162306a36Sopenharmony_ci bus), len, 141262306a36Sopenharmony_ci DMA_TO_DEVICE); 141362306a36Sopenharmony_ci } 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci dev_queue = netdev_get_tx_queue(ss->dev, ss - ss->mgp->ss); 141762306a36Sopenharmony_ci /* 141862306a36Sopenharmony_ci * Make a minimal effort to prevent the NIC from polling an 141962306a36Sopenharmony_ci * idle tx queue. If we can't get the lock we leave the queue 142062306a36Sopenharmony_ci * active. In this case, either a thread was about to start 142162306a36Sopenharmony_ci * using the queue anyway, or we lost a race and the NIC will 142262306a36Sopenharmony_ci * waste some of its resources polling an inactive queue for a 142362306a36Sopenharmony_ci * while. 142462306a36Sopenharmony_ci */ 142562306a36Sopenharmony_ci 142662306a36Sopenharmony_ci if ((ss->mgp->dev->real_num_tx_queues > 1) && 142762306a36Sopenharmony_ci __netif_tx_trylock(dev_queue)) { 142862306a36Sopenharmony_ci if (tx->req == tx->done) { 142962306a36Sopenharmony_ci tx->queue_active = 0; 143062306a36Sopenharmony_ci put_be32(htonl(1), tx->send_stop); 143162306a36Sopenharmony_ci mb(); 143262306a36Sopenharmony_ci } 143362306a36Sopenharmony_ci __netif_tx_unlock(dev_queue); 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ci /* start the queue if we've stopped it */ 143762306a36Sopenharmony_ci if (netif_tx_queue_stopped(dev_queue) && 143862306a36Sopenharmony_ci tx->req - tx->done < (tx->mask >> 1) && 143962306a36Sopenharmony_ci ss->mgp->running == MYRI10GE_ETH_RUNNING) { 144062306a36Sopenharmony_ci tx->wake_queue++; 144162306a36Sopenharmony_ci netif_tx_wake_queue(dev_queue); 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_cistatic inline int 144662306a36Sopenharmony_cimyri10ge_clean_rx_done(struct myri10ge_slice_state *ss, int budget) 144762306a36Sopenharmony_ci{ 144862306a36Sopenharmony_ci struct myri10ge_rx_done *rx_done = &ss->rx_done; 144962306a36Sopenharmony_ci struct myri10ge_priv *mgp = ss->mgp; 145062306a36Sopenharmony_ci unsigned long rx_bytes = 0; 145162306a36Sopenharmony_ci unsigned long rx_packets = 0; 145262306a36Sopenharmony_ci unsigned long rx_ok; 145362306a36Sopenharmony_ci int idx = rx_done->idx; 145462306a36Sopenharmony_ci int cnt = rx_done->cnt; 145562306a36Sopenharmony_ci int work_done = 0; 145662306a36Sopenharmony_ci u16 length; 145762306a36Sopenharmony_ci __wsum checksum; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci while (rx_done->entry[idx].length != 0 && work_done < budget) { 146062306a36Sopenharmony_ci length = ntohs(rx_done->entry[idx].length); 146162306a36Sopenharmony_ci rx_done->entry[idx].length = 0; 146262306a36Sopenharmony_ci checksum = csum_unfold(rx_done->entry[idx].checksum); 146362306a36Sopenharmony_ci rx_ok = myri10ge_rx_done(ss, length, checksum); 146462306a36Sopenharmony_ci rx_packets += rx_ok; 146562306a36Sopenharmony_ci rx_bytes += rx_ok * (unsigned long)length; 146662306a36Sopenharmony_ci cnt++; 146762306a36Sopenharmony_ci idx = cnt & (mgp->max_intr_slots - 1); 146862306a36Sopenharmony_ci work_done++; 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci rx_done->idx = idx; 147162306a36Sopenharmony_ci rx_done->cnt = cnt; 147262306a36Sopenharmony_ci ss->stats.rx_packets += rx_packets; 147362306a36Sopenharmony_ci ss->stats.rx_bytes += rx_bytes; 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci /* restock receive rings if needed */ 147662306a36Sopenharmony_ci if (ss->rx_small.fill_cnt - ss->rx_small.cnt < myri10ge_fill_thresh) 147762306a36Sopenharmony_ci myri10ge_alloc_rx_pages(mgp, &ss->rx_small, 147862306a36Sopenharmony_ci mgp->small_bytes + MXGEFW_PAD, 0); 147962306a36Sopenharmony_ci if (ss->rx_big.fill_cnt - ss->rx_big.cnt < myri10ge_fill_thresh) 148062306a36Sopenharmony_ci myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 0); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci return work_done; 148362306a36Sopenharmony_ci} 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_cistatic inline void myri10ge_check_statblock(struct myri10ge_priv *mgp) 148662306a36Sopenharmony_ci{ 148762306a36Sopenharmony_ci struct mcp_irq_data *stats = mgp->ss[0].fw_stats; 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci if (unlikely(stats->stats_updated)) { 149062306a36Sopenharmony_ci unsigned link_up = ntohl(stats->link_up); 149162306a36Sopenharmony_ci if (mgp->link_state != link_up) { 149262306a36Sopenharmony_ci mgp->link_state = link_up; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci if (mgp->link_state == MXGEFW_LINK_UP) { 149562306a36Sopenharmony_ci netif_info(mgp, link, mgp->dev, "link up\n"); 149662306a36Sopenharmony_ci netif_carrier_on(mgp->dev); 149762306a36Sopenharmony_ci mgp->link_changes++; 149862306a36Sopenharmony_ci } else { 149962306a36Sopenharmony_ci netif_info(mgp, link, mgp->dev, "link %s\n", 150062306a36Sopenharmony_ci (link_up == MXGEFW_LINK_MYRINET ? 150162306a36Sopenharmony_ci "mismatch (Myrinet detected)" : 150262306a36Sopenharmony_ci "down")); 150362306a36Sopenharmony_ci netif_carrier_off(mgp->dev); 150462306a36Sopenharmony_ci mgp->link_changes++; 150562306a36Sopenharmony_ci } 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci if (mgp->rdma_tags_available != 150862306a36Sopenharmony_ci ntohl(stats->rdma_tags_available)) { 150962306a36Sopenharmony_ci mgp->rdma_tags_available = 151062306a36Sopenharmony_ci ntohl(stats->rdma_tags_available); 151162306a36Sopenharmony_ci netdev_warn(mgp->dev, "RDMA timed out! %d tags left\n", 151262306a36Sopenharmony_ci mgp->rdma_tags_available); 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci mgp->down_cnt += stats->link_down; 151562306a36Sopenharmony_ci if (stats->link_down) 151662306a36Sopenharmony_ci wake_up(&mgp->down_wq); 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci} 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_cistatic int myri10ge_poll(struct napi_struct *napi, int budget) 152162306a36Sopenharmony_ci{ 152262306a36Sopenharmony_ci struct myri10ge_slice_state *ss = 152362306a36Sopenharmony_ci container_of(napi, struct myri10ge_slice_state, napi); 152462306a36Sopenharmony_ci int work_done; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 152762306a36Sopenharmony_ci if (ss->mgp->dca_enabled) 152862306a36Sopenharmony_ci myri10ge_update_dca(ss); 152962306a36Sopenharmony_ci#endif 153062306a36Sopenharmony_ci /* process as many rx events as NAPI will allow */ 153162306a36Sopenharmony_ci work_done = myri10ge_clean_rx_done(ss, budget); 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci if (work_done < budget) { 153462306a36Sopenharmony_ci napi_complete_done(napi, work_done); 153562306a36Sopenharmony_ci put_be32(htonl(3), ss->irq_claim); 153662306a36Sopenharmony_ci } 153762306a36Sopenharmony_ci return work_done; 153862306a36Sopenharmony_ci} 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_cistatic irqreturn_t myri10ge_intr(int irq, void *arg) 154162306a36Sopenharmony_ci{ 154262306a36Sopenharmony_ci struct myri10ge_slice_state *ss = arg; 154362306a36Sopenharmony_ci struct myri10ge_priv *mgp = ss->mgp; 154462306a36Sopenharmony_ci struct mcp_irq_data *stats = ss->fw_stats; 154562306a36Sopenharmony_ci struct myri10ge_tx_buf *tx = &ss->tx; 154662306a36Sopenharmony_ci u32 send_done_count; 154762306a36Sopenharmony_ci int i; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci /* an interrupt on a non-zero receive-only slice is implicitly 155062306a36Sopenharmony_ci * valid since MSI-X irqs are not shared */ 155162306a36Sopenharmony_ci if ((mgp->dev->real_num_tx_queues == 1) && (ss != mgp->ss)) { 155262306a36Sopenharmony_ci napi_schedule(&ss->napi); 155362306a36Sopenharmony_ci return IRQ_HANDLED; 155462306a36Sopenharmony_ci } 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci /* make sure it is our IRQ, and that the DMA has finished */ 155762306a36Sopenharmony_ci if (unlikely(!stats->valid)) 155862306a36Sopenharmony_ci return IRQ_NONE; 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci /* low bit indicates receives are present, so schedule 156162306a36Sopenharmony_ci * napi poll handler */ 156262306a36Sopenharmony_ci if (stats->valid & 1) 156362306a36Sopenharmony_ci napi_schedule(&ss->napi); 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci if (!mgp->msi_enabled && !mgp->msix_enabled) { 156662306a36Sopenharmony_ci put_be32(0, mgp->irq_deassert); 156762306a36Sopenharmony_ci if (!myri10ge_deassert_wait) 156862306a36Sopenharmony_ci stats->valid = 0; 156962306a36Sopenharmony_ci mb(); 157062306a36Sopenharmony_ci } else 157162306a36Sopenharmony_ci stats->valid = 0; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci /* Wait for IRQ line to go low, if using INTx */ 157462306a36Sopenharmony_ci i = 0; 157562306a36Sopenharmony_ci while (1) { 157662306a36Sopenharmony_ci i++; 157762306a36Sopenharmony_ci /* check for transmit completes and receives */ 157862306a36Sopenharmony_ci send_done_count = ntohl(stats->send_done_count); 157962306a36Sopenharmony_ci if (send_done_count != tx->pkt_done) 158062306a36Sopenharmony_ci myri10ge_tx_done(ss, (int)send_done_count); 158162306a36Sopenharmony_ci if (unlikely(i > myri10ge_max_irq_loops)) { 158262306a36Sopenharmony_ci netdev_warn(mgp->dev, "irq stuck?\n"); 158362306a36Sopenharmony_ci stats->valid = 0; 158462306a36Sopenharmony_ci schedule_work(&mgp->watchdog_work); 158562306a36Sopenharmony_ci } 158662306a36Sopenharmony_ci if (likely(stats->valid == 0)) 158762306a36Sopenharmony_ci break; 158862306a36Sopenharmony_ci cpu_relax(); 158962306a36Sopenharmony_ci barrier(); 159062306a36Sopenharmony_ci } 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci /* Only slice 0 updates stats */ 159362306a36Sopenharmony_ci if (ss == mgp->ss) 159462306a36Sopenharmony_ci myri10ge_check_statblock(mgp); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci put_be32(htonl(3), ss->irq_claim + 1); 159762306a36Sopenharmony_ci return IRQ_HANDLED; 159862306a36Sopenharmony_ci} 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_cistatic int 160162306a36Sopenharmony_cimyri10ge_get_link_ksettings(struct net_device *netdev, 160262306a36Sopenharmony_ci struct ethtool_link_ksettings *cmd) 160362306a36Sopenharmony_ci{ 160462306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 160562306a36Sopenharmony_ci char *ptr; 160662306a36Sopenharmony_ci int i; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 160962306a36Sopenharmony_ci cmd->base.speed = SPEED_10000; 161062306a36Sopenharmony_ci cmd->base.duplex = DUPLEX_FULL; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci /* 161362306a36Sopenharmony_ci * parse the product code to deterimine the interface type 161462306a36Sopenharmony_ci * (CX4, XFP, Quad Ribbon Fiber) by looking at the character 161562306a36Sopenharmony_ci * after the 3rd dash in the driver's cached copy of the 161662306a36Sopenharmony_ci * EEPROM's product code string. 161762306a36Sopenharmony_ci */ 161862306a36Sopenharmony_ci ptr = mgp->product_code_string; 161962306a36Sopenharmony_ci if (ptr == NULL) { 162062306a36Sopenharmony_ci netdev_err(netdev, "Missing product code\n"); 162162306a36Sopenharmony_ci return 0; 162262306a36Sopenharmony_ci } 162362306a36Sopenharmony_ci for (i = 0; i < 3; i++, ptr++) { 162462306a36Sopenharmony_ci ptr = strchr(ptr, '-'); 162562306a36Sopenharmony_ci if (ptr == NULL) { 162662306a36Sopenharmony_ci netdev_err(netdev, "Invalid product code %s\n", 162762306a36Sopenharmony_ci mgp->product_code_string); 162862306a36Sopenharmony_ci return 0; 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci } 163162306a36Sopenharmony_ci if (*ptr == '2') 163262306a36Sopenharmony_ci ptr++; 163362306a36Sopenharmony_ci if (*ptr == 'R' || *ptr == 'Q' || *ptr == 'S') { 163462306a36Sopenharmony_ci /* We've found either an XFP, quad ribbon fiber, or SFP+ */ 163562306a36Sopenharmony_ci cmd->base.port = PORT_FIBRE; 163662306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); 163762306a36Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); 163862306a36Sopenharmony_ci } else { 163962306a36Sopenharmony_ci cmd->base.port = PORT_OTHER; 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci return 0; 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_cistatic void 164662306a36Sopenharmony_cimyri10ge_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) 164762306a36Sopenharmony_ci{ 164862306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci strscpy(info->driver, "myri10ge", sizeof(info->driver)); 165162306a36Sopenharmony_ci strscpy(info->version, MYRI10GE_VERSION_STR, sizeof(info->version)); 165262306a36Sopenharmony_ci strscpy(info->fw_version, mgp->fw_version, sizeof(info->fw_version)); 165362306a36Sopenharmony_ci strscpy(info->bus_info, pci_name(mgp->pdev), sizeof(info->bus_info)); 165462306a36Sopenharmony_ci} 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_cistatic int myri10ge_get_coalesce(struct net_device *netdev, 165762306a36Sopenharmony_ci struct ethtool_coalesce *coal, 165862306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 165962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 166062306a36Sopenharmony_ci{ 166162306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci coal->rx_coalesce_usecs = mgp->intr_coal_delay; 166462306a36Sopenharmony_ci return 0; 166562306a36Sopenharmony_ci} 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_cistatic int myri10ge_set_coalesce(struct net_device *netdev, 166862306a36Sopenharmony_ci struct ethtool_coalesce *coal, 166962306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 167062306a36Sopenharmony_ci struct netlink_ext_ack *extack) 167162306a36Sopenharmony_ci{ 167262306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci mgp->intr_coal_delay = coal->rx_coalesce_usecs; 167562306a36Sopenharmony_ci put_be32(htonl(mgp->intr_coal_delay), mgp->intr_coal_delay_ptr); 167662306a36Sopenharmony_ci return 0; 167762306a36Sopenharmony_ci} 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_cistatic void 168062306a36Sopenharmony_cimyri10ge_get_pauseparam(struct net_device *netdev, 168162306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 168262306a36Sopenharmony_ci{ 168362306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci pause->autoneg = 0; 168662306a36Sopenharmony_ci pause->rx_pause = mgp->pause; 168762306a36Sopenharmony_ci pause->tx_pause = mgp->pause; 168862306a36Sopenharmony_ci} 168962306a36Sopenharmony_ci 169062306a36Sopenharmony_cistatic int 169162306a36Sopenharmony_cimyri10ge_set_pauseparam(struct net_device *netdev, 169262306a36Sopenharmony_ci struct ethtool_pauseparam *pause) 169362306a36Sopenharmony_ci{ 169462306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (pause->tx_pause != mgp->pause) 169762306a36Sopenharmony_ci return myri10ge_change_pause(mgp, pause->tx_pause); 169862306a36Sopenharmony_ci if (pause->rx_pause != mgp->pause) 169962306a36Sopenharmony_ci return myri10ge_change_pause(mgp, pause->rx_pause); 170062306a36Sopenharmony_ci if (pause->autoneg != 0) 170162306a36Sopenharmony_ci return -EINVAL; 170262306a36Sopenharmony_ci return 0; 170362306a36Sopenharmony_ci} 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_cistatic void 170662306a36Sopenharmony_cimyri10ge_get_ringparam(struct net_device *netdev, 170762306a36Sopenharmony_ci struct ethtool_ringparam *ring, 170862306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 170962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 171062306a36Sopenharmony_ci{ 171162306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci ring->rx_mini_max_pending = mgp->ss[0].rx_small.mask + 1; 171462306a36Sopenharmony_ci ring->rx_max_pending = mgp->ss[0].rx_big.mask + 1; 171562306a36Sopenharmony_ci ring->rx_jumbo_max_pending = 0; 171662306a36Sopenharmony_ci ring->tx_max_pending = mgp->ss[0].tx.mask + 1; 171762306a36Sopenharmony_ci ring->rx_mini_pending = ring->rx_mini_max_pending; 171862306a36Sopenharmony_ci ring->rx_pending = ring->rx_max_pending; 171962306a36Sopenharmony_ci ring->rx_jumbo_pending = ring->rx_jumbo_max_pending; 172062306a36Sopenharmony_ci ring->tx_pending = ring->tx_max_pending; 172162306a36Sopenharmony_ci} 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_cistatic const char myri10ge_gstrings_main_stats[][ETH_GSTRING_LEN] = { 172462306a36Sopenharmony_ci "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors", 172562306a36Sopenharmony_ci "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions", 172662306a36Sopenharmony_ci "rx_length_errors", "rx_over_errors", "rx_crc_errors", 172762306a36Sopenharmony_ci "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors", 172862306a36Sopenharmony_ci "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors", 172962306a36Sopenharmony_ci "tx_heartbeat_errors", "tx_window_errors", 173062306a36Sopenharmony_ci /* device-specific stats */ 173162306a36Sopenharmony_ci "tx_boundary", "irq", "MSI", "MSIX", 173262306a36Sopenharmony_ci "read_dma_bw_MBs", "write_dma_bw_MBs", "read_write_dma_bw_MBs", 173362306a36Sopenharmony_ci "serial_number", "watchdog_resets", 173462306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 173562306a36Sopenharmony_ci "dca_capable_firmware", "dca_device_present", 173662306a36Sopenharmony_ci#endif 173762306a36Sopenharmony_ci "link_changes", "link_up", "dropped_link_overflow", 173862306a36Sopenharmony_ci "dropped_link_error_or_filtered", 173962306a36Sopenharmony_ci "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32", 174062306a36Sopenharmony_ci "dropped_unicast_filtered", "dropped_multicast_filtered", 174162306a36Sopenharmony_ci "dropped_runt", "dropped_overrun", "dropped_no_small_buffer", 174262306a36Sopenharmony_ci "dropped_no_big_buffer" 174362306a36Sopenharmony_ci}; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_cistatic const char myri10ge_gstrings_slice_stats[][ETH_GSTRING_LEN] = { 174662306a36Sopenharmony_ci "----------- slice ---------", 174762306a36Sopenharmony_ci "tx_pkt_start", "tx_pkt_done", "tx_req", "tx_done", 174862306a36Sopenharmony_ci "rx_small_cnt", "rx_big_cnt", 174962306a36Sopenharmony_ci "wake_queue", "stop_queue", "tx_linearized", 175062306a36Sopenharmony_ci}; 175162306a36Sopenharmony_ci 175262306a36Sopenharmony_ci#define MYRI10GE_NET_STATS_LEN 21 175362306a36Sopenharmony_ci#define MYRI10GE_MAIN_STATS_LEN ARRAY_SIZE(myri10ge_gstrings_main_stats) 175462306a36Sopenharmony_ci#define MYRI10GE_SLICE_STATS_LEN ARRAY_SIZE(myri10ge_gstrings_slice_stats) 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_cistatic void 175762306a36Sopenharmony_cimyri10ge_get_strings(struct net_device *netdev, u32 stringset, u8 * data) 175862306a36Sopenharmony_ci{ 175962306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 176062306a36Sopenharmony_ci int i; 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci switch (stringset) { 176362306a36Sopenharmony_ci case ETH_SS_STATS: 176462306a36Sopenharmony_ci memcpy(data, *myri10ge_gstrings_main_stats, 176562306a36Sopenharmony_ci sizeof(myri10ge_gstrings_main_stats)); 176662306a36Sopenharmony_ci data += sizeof(myri10ge_gstrings_main_stats); 176762306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 176862306a36Sopenharmony_ci memcpy(data, *myri10ge_gstrings_slice_stats, 176962306a36Sopenharmony_ci sizeof(myri10ge_gstrings_slice_stats)); 177062306a36Sopenharmony_ci data += sizeof(myri10ge_gstrings_slice_stats); 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci break; 177362306a36Sopenharmony_ci } 177462306a36Sopenharmony_ci} 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_cistatic int myri10ge_get_sset_count(struct net_device *netdev, int sset) 177762306a36Sopenharmony_ci{ 177862306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci switch (sset) { 178162306a36Sopenharmony_ci case ETH_SS_STATS: 178262306a36Sopenharmony_ci return MYRI10GE_MAIN_STATS_LEN + 178362306a36Sopenharmony_ci mgp->num_slices * MYRI10GE_SLICE_STATS_LEN; 178462306a36Sopenharmony_ci default: 178562306a36Sopenharmony_ci return -EOPNOTSUPP; 178662306a36Sopenharmony_ci } 178762306a36Sopenharmony_ci} 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_cistatic void 179062306a36Sopenharmony_cimyri10ge_get_ethtool_stats(struct net_device *netdev, 179162306a36Sopenharmony_ci struct ethtool_stats *stats, u64 * data) 179262306a36Sopenharmony_ci{ 179362306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 179462306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 179562306a36Sopenharmony_ci struct rtnl_link_stats64 link_stats; 179662306a36Sopenharmony_ci int slice; 179762306a36Sopenharmony_ci int i; 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci /* force stats update */ 180062306a36Sopenharmony_ci memset(&link_stats, 0, sizeof(link_stats)); 180162306a36Sopenharmony_ci (void)myri10ge_get_stats(netdev, &link_stats); 180262306a36Sopenharmony_ci for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++) 180362306a36Sopenharmony_ci data[i] = ((u64 *)&link_stats)[i]; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci data[i++] = (unsigned int)mgp->tx_boundary; 180662306a36Sopenharmony_ci data[i++] = (unsigned int)mgp->pdev->irq; 180762306a36Sopenharmony_ci data[i++] = (unsigned int)mgp->msi_enabled; 180862306a36Sopenharmony_ci data[i++] = (unsigned int)mgp->msix_enabled; 180962306a36Sopenharmony_ci data[i++] = (unsigned int)mgp->read_dma; 181062306a36Sopenharmony_ci data[i++] = (unsigned int)mgp->write_dma; 181162306a36Sopenharmony_ci data[i++] = (unsigned int)mgp->read_write_dma; 181262306a36Sopenharmony_ci data[i++] = (unsigned int)mgp->serial_number; 181362306a36Sopenharmony_ci data[i++] = (unsigned int)mgp->watchdog_resets; 181462306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 181562306a36Sopenharmony_ci data[i++] = (unsigned int)(mgp->ss[0].dca_tag != NULL); 181662306a36Sopenharmony_ci data[i++] = (unsigned int)(mgp->dca_enabled); 181762306a36Sopenharmony_ci#endif 181862306a36Sopenharmony_ci data[i++] = (unsigned int)mgp->link_changes; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci /* firmware stats are useful only in the first slice */ 182162306a36Sopenharmony_ci ss = &mgp->ss[0]; 182262306a36Sopenharmony_ci data[i++] = (unsigned int)ntohl(ss->fw_stats->link_up); 182362306a36Sopenharmony_ci data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_link_overflow); 182462306a36Sopenharmony_ci data[i++] = 182562306a36Sopenharmony_ci (unsigned int)ntohl(ss->fw_stats->dropped_link_error_or_filtered); 182662306a36Sopenharmony_ci data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_pause); 182762306a36Sopenharmony_ci data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_bad_phy); 182862306a36Sopenharmony_ci data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_bad_crc32); 182962306a36Sopenharmony_ci data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_unicast_filtered); 183062306a36Sopenharmony_ci data[i++] = 183162306a36Sopenharmony_ci (unsigned int)ntohl(ss->fw_stats->dropped_multicast_filtered); 183262306a36Sopenharmony_ci data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_runt); 183362306a36Sopenharmony_ci data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_overrun); 183462306a36Sopenharmony_ci data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_small_buffer); 183562306a36Sopenharmony_ci data[i++] = (unsigned int)ntohl(ss->fw_stats->dropped_no_big_buffer); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci for (slice = 0; slice < mgp->num_slices; slice++) { 183862306a36Sopenharmony_ci ss = &mgp->ss[slice]; 183962306a36Sopenharmony_ci data[i++] = slice; 184062306a36Sopenharmony_ci data[i++] = (unsigned int)ss->tx.pkt_start; 184162306a36Sopenharmony_ci data[i++] = (unsigned int)ss->tx.pkt_done; 184262306a36Sopenharmony_ci data[i++] = (unsigned int)ss->tx.req; 184362306a36Sopenharmony_ci data[i++] = (unsigned int)ss->tx.done; 184462306a36Sopenharmony_ci data[i++] = (unsigned int)ss->rx_small.cnt; 184562306a36Sopenharmony_ci data[i++] = (unsigned int)ss->rx_big.cnt; 184662306a36Sopenharmony_ci data[i++] = (unsigned int)ss->tx.wake_queue; 184762306a36Sopenharmony_ci data[i++] = (unsigned int)ss->tx.stop_queue; 184862306a36Sopenharmony_ci data[i++] = (unsigned int)ss->tx.linearized; 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci} 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_cistatic void myri10ge_set_msglevel(struct net_device *netdev, u32 value) 185362306a36Sopenharmony_ci{ 185462306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 185562306a36Sopenharmony_ci mgp->msg_enable = value; 185662306a36Sopenharmony_ci} 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_cistatic u32 myri10ge_get_msglevel(struct net_device *netdev) 185962306a36Sopenharmony_ci{ 186062306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 186162306a36Sopenharmony_ci return mgp->msg_enable; 186262306a36Sopenharmony_ci} 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci/* 186562306a36Sopenharmony_ci * Use a low-level command to change the LED behavior. Rather than 186662306a36Sopenharmony_ci * blinking (which is the normal case), when identify is used, the 186762306a36Sopenharmony_ci * yellow LED turns solid. 186862306a36Sopenharmony_ci */ 186962306a36Sopenharmony_cistatic int myri10ge_led(struct myri10ge_priv *mgp, int on) 187062306a36Sopenharmony_ci{ 187162306a36Sopenharmony_ci struct mcp_gen_header *hdr; 187262306a36Sopenharmony_ci struct device *dev = &mgp->pdev->dev; 187362306a36Sopenharmony_ci size_t hdr_off, pattern_off, hdr_len; 187462306a36Sopenharmony_ci u32 pattern = 0xfffffffe; 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci /* find running firmware header */ 187762306a36Sopenharmony_ci hdr_off = swab32(readl(mgp->sram + MCP_HEADER_PTR_OFFSET)); 187862306a36Sopenharmony_ci if ((hdr_off & 3) || hdr_off + sizeof(*hdr) > mgp->sram_size) { 187962306a36Sopenharmony_ci dev_err(dev, "Running firmware has bad header offset (%d)\n", 188062306a36Sopenharmony_ci (int)hdr_off); 188162306a36Sopenharmony_ci return -EIO; 188262306a36Sopenharmony_ci } 188362306a36Sopenharmony_ci hdr_len = swab32(readl(mgp->sram + hdr_off + 188462306a36Sopenharmony_ci offsetof(struct mcp_gen_header, header_length))); 188562306a36Sopenharmony_ci pattern_off = hdr_off + offsetof(struct mcp_gen_header, led_pattern); 188662306a36Sopenharmony_ci if (pattern_off >= (hdr_len + hdr_off)) { 188762306a36Sopenharmony_ci dev_info(dev, "Firmware does not support LED identification\n"); 188862306a36Sopenharmony_ci return -EINVAL; 188962306a36Sopenharmony_ci } 189062306a36Sopenharmony_ci if (!on) 189162306a36Sopenharmony_ci pattern = swab32(readl(mgp->sram + pattern_off + 4)); 189262306a36Sopenharmony_ci writel(swab32(pattern), mgp->sram + pattern_off); 189362306a36Sopenharmony_ci return 0; 189462306a36Sopenharmony_ci} 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_cistatic int 189762306a36Sopenharmony_cimyri10ge_phys_id(struct net_device *netdev, enum ethtool_phys_id_state state) 189862306a36Sopenharmony_ci{ 189962306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(netdev); 190062306a36Sopenharmony_ci int rc; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci switch (state) { 190362306a36Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 190462306a36Sopenharmony_ci rc = myri10ge_led(mgp, 1); 190562306a36Sopenharmony_ci break; 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 190862306a36Sopenharmony_ci rc = myri10ge_led(mgp, 0); 190962306a36Sopenharmony_ci break; 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci default: 191262306a36Sopenharmony_ci rc = -EINVAL; 191362306a36Sopenharmony_ci } 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci return rc; 191662306a36Sopenharmony_ci} 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_cistatic const struct ethtool_ops myri10ge_ethtool_ops = { 191962306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS, 192062306a36Sopenharmony_ci .get_drvinfo = myri10ge_get_drvinfo, 192162306a36Sopenharmony_ci .get_coalesce = myri10ge_get_coalesce, 192262306a36Sopenharmony_ci .set_coalesce = myri10ge_set_coalesce, 192362306a36Sopenharmony_ci .get_pauseparam = myri10ge_get_pauseparam, 192462306a36Sopenharmony_ci .set_pauseparam = myri10ge_set_pauseparam, 192562306a36Sopenharmony_ci .get_ringparam = myri10ge_get_ringparam, 192662306a36Sopenharmony_ci .get_link = ethtool_op_get_link, 192762306a36Sopenharmony_ci .get_strings = myri10ge_get_strings, 192862306a36Sopenharmony_ci .get_sset_count = myri10ge_get_sset_count, 192962306a36Sopenharmony_ci .get_ethtool_stats = myri10ge_get_ethtool_stats, 193062306a36Sopenharmony_ci .set_msglevel = myri10ge_set_msglevel, 193162306a36Sopenharmony_ci .get_msglevel = myri10ge_get_msglevel, 193262306a36Sopenharmony_ci .set_phys_id = myri10ge_phys_id, 193362306a36Sopenharmony_ci .get_link_ksettings = myri10ge_get_link_ksettings, 193462306a36Sopenharmony_ci}; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_cistatic int myri10ge_allocate_rings(struct myri10ge_slice_state *ss) 193762306a36Sopenharmony_ci{ 193862306a36Sopenharmony_ci struct myri10ge_priv *mgp = ss->mgp; 193962306a36Sopenharmony_ci struct myri10ge_cmd cmd; 194062306a36Sopenharmony_ci struct net_device *dev = mgp->dev; 194162306a36Sopenharmony_ci int tx_ring_size, rx_ring_size; 194262306a36Sopenharmony_ci int tx_ring_entries, rx_ring_entries; 194362306a36Sopenharmony_ci int i, slice, status; 194462306a36Sopenharmony_ci size_t bytes; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci /* get ring sizes */ 194762306a36Sopenharmony_ci slice = ss - mgp->ss; 194862306a36Sopenharmony_ci cmd.data0 = slice; 194962306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_RING_SIZE, &cmd, 0); 195062306a36Sopenharmony_ci tx_ring_size = cmd.data0; 195162306a36Sopenharmony_ci cmd.data0 = slice; 195262306a36Sopenharmony_ci status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_RX_RING_SIZE, &cmd, 0); 195362306a36Sopenharmony_ci if (status != 0) 195462306a36Sopenharmony_ci return status; 195562306a36Sopenharmony_ci rx_ring_size = cmd.data0; 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci tx_ring_entries = tx_ring_size / sizeof(struct mcp_kreq_ether_send); 195862306a36Sopenharmony_ci rx_ring_entries = rx_ring_size / sizeof(struct mcp_dma_addr); 195962306a36Sopenharmony_ci ss->tx.mask = tx_ring_entries - 1; 196062306a36Sopenharmony_ci ss->rx_small.mask = ss->rx_big.mask = rx_ring_entries - 1; 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci status = -ENOMEM; 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci /* allocate the host shadow rings */ 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci bytes = 8 + (MYRI10GE_MAX_SEND_DESC_TSO + 4) 196762306a36Sopenharmony_ci * sizeof(*ss->tx.req_list); 196862306a36Sopenharmony_ci ss->tx.req_bytes = kzalloc(bytes, GFP_KERNEL); 196962306a36Sopenharmony_ci if (ss->tx.req_bytes == NULL) 197062306a36Sopenharmony_ci goto abort_with_nothing; 197162306a36Sopenharmony_ci 197262306a36Sopenharmony_ci /* ensure req_list entries are aligned to 8 bytes */ 197362306a36Sopenharmony_ci ss->tx.req_list = (struct mcp_kreq_ether_send *) 197462306a36Sopenharmony_ci ALIGN((unsigned long)ss->tx.req_bytes, 8); 197562306a36Sopenharmony_ci ss->tx.queue_active = 0; 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci bytes = rx_ring_entries * sizeof(*ss->rx_small.shadow); 197862306a36Sopenharmony_ci ss->rx_small.shadow = kzalloc(bytes, GFP_KERNEL); 197962306a36Sopenharmony_ci if (ss->rx_small.shadow == NULL) 198062306a36Sopenharmony_ci goto abort_with_tx_req_bytes; 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci bytes = rx_ring_entries * sizeof(*ss->rx_big.shadow); 198362306a36Sopenharmony_ci ss->rx_big.shadow = kzalloc(bytes, GFP_KERNEL); 198462306a36Sopenharmony_ci if (ss->rx_big.shadow == NULL) 198562306a36Sopenharmony_ci goto abort_with_rx_small_shadow; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci /* allocate the host info rings */ 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci bytes = tx_ring_entries * sizeof(*ss->tx.info); 199062306a36Sopenharmony_ci ss->tx.info = kzalloc(bytes, GFP_KERNEL); 199162306a36Sopenharmony_ci if (ss->tx.info == NULL) 199262306a36Sopenharmony_ci goto abort_with_rx_big_shadow; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci bytes = rx_ring_entries * sizeof(*ss->rx_small.info); 199562306a36Sopenharmony_ci ss->rx_small.info = kzalloc(bytes, GFP_KERNEL); 199662306a36Sopenharmony_ci if (ss->rx_small.info == NULL) 199762306a36Sopenharmony_ci goto abort_with_tx_info; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci bytes = rx_ring_entries * sizeof(*ss->rx_big.info); 200062306a36Sopenharmony_ci ss->rx_big.info = kzalloc(bytes, GFP_KERNEL); 200162306a36Sopenharmony_ci if (ss->rx_big.info == NULL) 200262306a36Sopenharmony_ci goto abort_with_rx_small_info; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci /* Fill the receive rings */ 200562306a36Sopenharmony_ci ss->rx_big.cnt = 0; 200662306a36Sopenharmony_ci ss->rx_small.cnt = 0; 200762306a36Sopenharmony_ci ss->rx_big.fill_cnt = 0; 200862306a36Sopenharmony_ci ss->rx_small.fill_cnt = 0; 200962306a36Sopenharmony_ci ss->rx_small.page_offset = MYRI10GE_ALLOC_SIZE; 201062306a36Sopenharmony_ci ss->rx_big.page_offset = MYRI10GE_ALLOC_SIZE; 201162306a36Sopenharmony_ci ss->rx_small.watchdog_needed = 0; 201262306a36Sopenharmony_ci ss->rx_big.watchdog_needed = 0; 201362306a36Sopenharmony_ci if (mgp->small_bytes == 0) { 201462306a36Sopenharmony_ci ss->rx_small.fill_cnt = ss->rx_small.mask + 1; 201562306a36Sopenharmony_ci } else { 201662306a36Sopenharmony_ci myri10ge_alloc_rx_pages(mgp, &ss->rx_small, 201762306a36Sopenharmony_ci mgp->small_bytes + MXGEFW_PAD, 0); 201862306a36Sopenharmony_ci } 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci if (ss->rx_small.fill_cnt < ss->rx_small.mask + 1) { 202162306a36Sopenharmony_ci netdev_err(dev, "slice-%d: alloced only %d small bufs\n", 202262306a36Sopenharmony_ci slice, ss->rx_small.fill_cnt); 202362306a36Sopenharmony_ci goto abort_with_rx_small_ring; 202462306a36Sopenharmony_ci } 202562306a36Sopenharmony_ci 202662306a36Sopenharmony_ci myri10ge_alloc_rx_pages(mgp, &ss->rx_big, mgp->big_bytes, 0); 202762306a36Sopenharmony_ci if (ss->rx_big.fill_cnt < ss->rx_big.mask + 1) { 202862306a36Sopenharmony_ci netdev_err(dev, "slice-%d: alloced only %d big bufs\n", 202962306a36Sopenharmony_ci slice, ss->rx_big.fill_cnt); 203062306a36Sopenharmony_ci goto abort_with_rx_big_ring; 203162306a36Sopenharmony_ci } 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci return 0; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ciabort_with_rx_big_ring: 203662306a36Sopenharmony_ci for (i = ss->rx_big.cnt; i < ss->rx_big.fill_cnt; i++) { 203762306a36Sopenharmony_ci int idx = i & ss->rx_big.mask; 203862306a36Sopenharmony_ci myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_big.info[idx], 203962306a36Sopenharmony_ci mgp->big_bytes); 204062306a36Sopenharmony_ci put_page(ss->rx_big.info[idx].page); 204162306a36Sopenharmony_ci } 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ciabort_with_rx_small_ring: 204462306a36Sopenharmony_ci if (mgp->small_bytes == 0) 204562306a36Sopenharmony_ci ss->rx_small.fill_cnt = ss->rx_small.cnt; 204662306a36Sopenharmony_ci for (i = ss->rx_small.cnt; i < ss->rx_small.fill_cnt; i++) { 204762306a36Sopenharmony_ci int idx = i & ss->rx_small.mask; 204862306a36Sopenharmony_ci myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_small.info[idx], 204962306a36Sopenharmony_ci mgp->small_bytes + MXGEFW_PAD); 205062306a36Sopenharmony_ci put_page(ss->rx_small.info[idx].page); 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci kfree(ss->rx_big.info); 205462306a36Sopenharmony_ci 205562306a36Sopenharmony_ciabort_with_rx_small_info: 205662306a36Sopenharmony_ci kfree(ss->rx_small.info); 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_ciabort_with_tx_info: 205962306a36Sopenharmony_ci kfree(ss->tx.info); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ciabort_with_rx_big_shadow: 206262306a36Sopenharmony_ci kfree(ss->rx_big.shadow); 206362306a36Sopenharmony_ci 206462306a36Sopenharmony_ciabort_with_rx_small_shadow: 206562306a36Sopenharmony_ci kfree(ss->rx_small.shadow); 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_ciabort_with_tx_req_bytes: 206862306a36Sopenharmony_ci kfree(ss->tx.req_bytes); 206962306a36Sopenharmony_ci ss->tx.req_bytes = NULL; 207062306a36Sopenharmony_ci ss->tx.req_list = NULL; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ciabort_with_nothing: 207362306a36Sopenharmony_ci return status; 207462306a36Sopenharmony_ci} 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_cistatic void myri10ge_free_rings(struct myri10ge_slice_state *ss) 207762306a36Sopenharmony_ci{ 207862306a36Sopenharmony_ci struct myri10ge_priv *mgp = ss->mgp; 207962306a36Sopenharmony_ci struct sk_buff *skb; 208062306a36Sopenharmony_ci struct myri10ge_tx_buf *tx; 208162306a36Sopenharmony_ci int i, len, idx; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci /* If not allocated, skip it */ 208462306a36Sopenharmony_ci if (ss->tx.req_list == NULL) 208562306a36Sopenharmony_ci return; 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci for (i = ss->rx_big.cnt; i < ss->rx_big.fill_cnt; i++) { 208862306a36Sopenharmony_ci idx = i & ss->rx_big.mask; 208962306a36Sopenharmony_ci if (i == ss->rx_big.fill_cnt - 1) 209062306a36Sopenharmony_ci ss->rx_big.info[idx].page_offset = MYRI10GE_ALLOC_SIZE; 209162306a36Sopenharmony_ci myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_big.info[idx], 209262306a36Sopenharmony_ci mgp->big_bytes); 209362306a36Sopenharmony_ci put_page(ss->rx_big.info[idx].page); 209462306a36Sopenharmony_ci } 209562306a36Sopenharmony_ci 209662306a36Sopenharmony_ci if (mgp->small_bytes == 0) 209762306a36Sopenharmony_ci ss->rx_small.fill_cnt = ss->rx_small.cnt; 209862306a36Sopenharmony_ci for (i = ss->rx_small.cnt; i < ss->rx_small.fill_cnt; i++) { 209962306a36Sopenharmony_ci idx = i & ss->rx_small.mask; 210062306a36Sopenharmony_ci if (i == ss->rx_small.fill_cnt - 1) 210162306a36Sopenharmony_ci ss->rx_small.info[idx].page_offset = 210262306a36Sopenharmony_ci MYRI10GE_ALLOC_SIZE; 210362306a36Sopenharmony_ci myri10ge_unmap_rx_page(mgp->pdev, &ss->rx_small.info[idx], 210462306a36Sopenharmony_ci mgp->small_bytes + MXGEFW_PAD); 210562306a36Sopenharmony_ci put_page(ss->rx_small.info[idx].page); 210662306a36Sopenharmony_ci } 210762306a36Sopenharmony_ci tx = &ss->tx; 210862306a36Sopenharmony_ci while (tx->done != tx->req) { 210962306a36Sopenharmony_ci idx = tx->done & tx->mask; 211062306a36Sopenharmony_ci skb = tx->info[idx].skb; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci /* Mark as free */ 211362306a36Sopenharmony_ci tx->info[idx].skb = NULL; 211462306a36Sopenharmony_ci tx->done++; 211562306a36Sopenharmony_ci len = dma_unmap_len(&tx->info[idx], len); 211662306a36Sopenharmony_ci dma_unmap_len_set(&tx->info[idx], len, 0); 211762306a36Sopenharmony_ci if (skb) { 211862306a36Sopenharmony_ci ss->stats.tx_dropped++; 211962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 212062306a36Sopenharmony_ci if (len) 212162306a36Sopenharmony_ci dma_unmap_single(&mgp->pdev->dev, 212262306a36Sopenharmony_ci dma_unmap_addr(&tx->info[idx], 212362306a36Sopenharmony_ci bus), len, 212462306a36Sopenharmony_ci DMA_TO_DEVICE); 212562306a36Sopenharmony_ci } else { 212662306a36Sopenharmony_ci if (len) 212762306a36Sopenharmony_ci dma_unmap_page(&mgp->pdev->dev, 212862306a36Sopenharmony_ci dma_unmap_addr(&tx->info[idx], 212962306a36Sopenharmony_ci bus), len, 213062306a36Sopenharmony_ci DMA_TO_DEVICE); 213162306a36Sopenharmony_ci } 213262306a36Sopenharmony_ci } 213362306a36Sopenharmony_ci kfree(ss->rx_big.info); 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci kfree(ss->rx_small.info); 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci kfree(ss->tx.info); 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci kfree(ss->rx_big.shadow); 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci kfree(ss->rx_small.shadow); 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci kfree(ss->tx.req_bytes); 214462306a36Sopenharmony_ci ss->tx.req_bytes = NULL; 214562306a36Sopenharmony_ci ss->tx.req_list = NULL; 214662306a36Sopenharmony_ci} 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_cistatic int myri10ge_request_irq(struct myri10ge_priv *mgp) 214962306a36Sopenharmony_ci{ 215062306a36Sopenharmony_ci struct pci_dev *pdev = mgp->pdev; 215162306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 215262306a36Sopenharmony_ci struct net_device *netdev = mgp->dev; 215362306a36Sopenharmony_ci int i; 215462306a36Sopenharmony_ci int status; 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci mgp->msi_enabled = 0; 215762306a36Sopenharmony_ci mgp->msix_enabled = 0; 215862306a36Sopenharmony_ci status = 0; 215962306a36Sopenharmony_ci if (myri10ge_msi) { 216062306a36Sopenharmony_ci if (mgp->num_slices > 1) { 216162306a36Sopenharmony_ci status = pci_enable_msix_range(pdev, mgp->msix_vectors, 216262306a36Sopenharmony_ci mgp->num_slices, mgp->num_slices); 216362306a36Sopenharmony_ci if (status < 0) { 216462306a36Sopenharmony_ci dev_err(&pdev->dev, 216562306a36Sopenharmony_ci "Error %d setting up MSI-X\n", status); 216662306a36Sopenharmony_ci return status; 216762306a36Sopenharmony_ci } 216862306a36Sopenharmony_ci mgp->msix_enabled = 1; 216962306a36Sopenharmony_ci } 217062306a36Sopenharmony_ci if (mgp->msix_enabled == 0) { 217162306a36Sopenharmony_ci status = pci_enable_msi(pdev); 217262306a36Sopenharmony_ci if (status != 0) { 217362306a36Sopenharmony_ci dev_err(&pdev->dev, 217462306a36Sopenharmony_ci "Error %d setting up MSI; falling back to xPIC\n", 217562306a36Sopenharmony_ci status); 217662306a36Sopenharmony_ci } else { 217762306a36Sopenharmony_ci mgp->msi_enabled = 1; 217862306a36Sopenharmony_ci } 217962306a36Sopenharmony_ci } 218062306a36Sopenharmony_ci } 218162306a36Sopenharmony_ci if (mgp->msix_enabled) { 218262306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 218362306a36Sopenharmony_ci ss = &mgp->ss[i]; 218462306a36Sopenharmony_ci snprintf(ss->irq_desc, sizeof(ss->irq_desc), 218562306a36Sopenharmony_ci "%s:slice-%d", netdev->name, i); 218662306a36Sopenharmony_ci status = request_irq(mgp->msix_vectors[i].vector, 218762306a36Sopenharmony_ci myri10ge_intr, 0, ss->irq_desc, 218862306a36Sopenharmony_ci ss); 218962306a36Sopenharmony_ci if (status != 0) { 219062306a36Sopenharmony_ci dev_err(&pdev->dev, 219162306a36Sopenharmony_ci "slice %d failed to allocate IRQ\n", i); 219262306a36Sopenharmony_ci i--; 219362306a36Sopenharmony_ci while (i >= 0) { 219462306a36Sopenharmony_ci free_irq(mgp->msix_vectors[i].vector, 219562306a36Sopenharmony_ci &mgp->ss[i]); 219662306a36Sopenharmony_ci i--; 219762306a36Sopenharmony_ci } 219862306a36Sopenharmony_ci pci_disable_msix(pdev); 219962306a36Sopenharmony_ci return status; 220062306a36Sopenharmony_ci } 220162306a36Sopenharmony_ci } 220262306a36Sopenharmony_ci } else { 220362306a36Sopenharmony_ci status = request_irq(pdev->irq, myri10ge_intr, IRQF_SHARED, 220462306a36Sopenharmony_ci mgp->dev->name, &mgp->ss[0]); 220562306a36Sopenharmony_ci if (status != 0) { 220662306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to allocate IRQ\n"); 220762306a36Sopenharmony_ci if (mgp->msi_enabled) 220862306a36Sopenharmony_ci pci_disable_msi(pdev); 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci } 221162306a36Sopenharmony_ci return status; 221262306a36Sopenharmony_ci} 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_cistatic void myri10ge_free_irq(struct myri10ge_priv *mgp) 221562306a36Sopenharmony_ci{ 221662306a36Sopenharmony_ci struct pci_dev *pdev = mgp->pdev; 221762306a36Sopenharmony_ci int i; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci if (mgp->msix_enabled) { 222062306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) 222162306a36Sopenharmony_ci free_irq(mgp->msix_vectors[i].vector, &mgp->ss[i]); 222262306a36Sopenharmony_ci } else { 222362306a36Sopenharmony_ci free_irq(pdev->irq, &mgp->ss[0]); 222462306a36Sopenharmony_ci } 222562306a36Sopenharmony_ci if (mgp->msi_enabled) 222662306a36Sopenharmony_ci pci_disable_msi(pdev); 222762306a36Sopenharmony_ci if (mgp->msix_enabled) 222862306a36Sopenharmony_ci pci_disable_msix(pdev); 222962306a36Sopenharmony_ci} 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_cistatic int myri10ge_get_txrx(struct myri10ge_priv *mgp, int slice) 223262306a36Sopenharmony_ci{ 223362306a36Sopenharmony_ci struct myri10ge_cmd cmd; 223462306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 223562306a36Sopenharmony_ci int status; 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci ss = &mgp->ss[slice]; 223862306a36Sopenharmony_ci status = 0; 223962306a36Sopenharmony_ci if (slice == 0 || (mgp->dev->real_num_tx_queues > 1)) { 224062306a36Sopenharmony_ci cmd.data0 = slice; 224162306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SEND_OFFSET, 224262306a36Sopenharmony_ci &cmd, 0); 224362306a36Sopenharmony_ci ss->tx.lanai = (struct mcp_kreq_ether_send __iomem *) 224462306a36Sopenharmony_ci (mgp->sram + cmd.data0); 224562306a36Sopenharmony_ci } 224662306a36Sopenharmony_ci cmd.data0 = slice; 224762306a36Sopenharmony_ci status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_SMALL_RX_OFFSET, 224862306a36Sopenharmony_ci &cmd, 0); 224962306a36Sopenharmony_ci ss->rx_small.lanai = (struct mcp_kreq_ether_recv __iomem *) 225062306a36Sopenharmony_ci (mgp->sram + cmd.data0); 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci cmd.data0 = slice; 225362306a36Sopenharmony_ci status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_BIG_RX_OFFSET, &cmd, 0); 225462306a36Sopenharmony_ci ss->rx_big.lanai = (struct mcp_kreq_ether_recv __iomem *) 225562306a36Sopenharmony_ci (mgp->sram + cmd.data0); 225662306a36Sopenharmony_ci 225762306a36Sopenharmony_ci ss->tx.send_go = (__iomem __be32 *) 225862306a36Sopenharmony_ci (mgp->sram + MXGEFW_ETH_SEND_GO + 64 * slice); 225962306a36Sopenharmony_ci ss->tx.send_stop = (__iomem __be32 *) 226062306a36Sopenharmony_ci (mgp->sram + MXGEFW_ETH_SEND_STOP + 64 * slice); 226162306a36Sopenharmony_ci return status; 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci} 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_cistatic int myri10ge_set_stats(struct myri10ge_priv *mgp, int slice) 226662306a36Sopenharmony_ci{ 226762306a36Sopenharmony_ci struct myri10ge_cmd cmd; 226862306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 226962306a36Sopenharmony_ci int status; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci ss = &mgp->ss[slice]; 227262306a36Sopenharmony_ci cmd.data0 = MYRI10GE_LOWPART_TO_U32(ss->fw_stats_bus); 227362306a36Sopenharmony_ci cmd.data1 = MYRI10GE_HIGHPART_TO_U32(ss->fw_stats_bus); 227462306a36Sopenharmony_ci cmd.data2 = sizeof(struct mcp_irq_data) | (slice << 16); 227562306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_STATS_DMA_V2, &cmd, 0); 227662306a36Sopenharmony_ci if (status == -ENOSYS) { 227762306a36Sopenharmony_ci dma_addr_t bus = ss->fw_stats_bus; 227862306a36Sopenharmony_ci if (slice != 0) 227962306a36Sopenharmony_ci return -EINVAL; 228062306a36Sopenharmony_ci bus += offsetof(struct mcp_irq_data, send_done_count); 228162306a36Sopenharmony_ci cmd.data0 = MYRI10GE_LOWPART_TO_U32(bus); 228262306a36Sopenharmony_ci cmd.data1 = MYRI10GE_HIGHPART_TO_U32(bus); 228362306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, 228462306a36Sopenharmony_ci MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, 228562306a36Sopenharmony_ci &cmd, 0); 228662306a36Sopenharmony_ci /* Firmware cannot support multicast without STATS_DMA_V2 */ 228762306a36Sopenharmony_ci mgp->fw_multicast_support = 0; 228862306a36Sopenharmony_ci } else { 228962306a36Sopenharmony_ci mgp->fw_multicast_support = 1; 229062306a36Sopenharmony_ci } 229162306a36Sopenharmony_ci return 0; 229262306a36Sopenharmony_ci} 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_cistatic int myri10ge_open(struct net_device *dev) 229562306a36Sopenharmony_ci{ 229662306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 229762306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(dev); 229862306a36Sopenharmony_ci struct myri10ge_cmd cmd; 229962306a36Sopenharmony_ci int i, status, big_pow2, slice; 230062306a36Sopenharmony_ci u8 __iomem *itable; 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci if (mgp->running != MYRI10GE_ETH_STOPPED) 230362306a36Sopenharmony_ci return -EBUSY; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci mgp->running = MYRI10GE_ETH_STARTING; 230662306a36Sopenharmony_ci status = myri10ge_reset(mgp); 230762306a36Sopenharmony_ci if (status != 0) { 230862306a36Sopenharmony_ci netdev_err(dev, "failed reset\n"); 230962306a36Sopenharmony_ci goto abort_with_nothing; 231062306a36Sopenharmony_ci } 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci if (mgp->num_slices > 1) { 231362306a36Sopenharmony_ci cmd.data0 = mgp->num_slices; 231462306a36Sopenharmony_ci cmd.data1 = MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE; 231562306a36Sopenharmony_ci if (mgp->dev->real_num_tx_queues > 1) 231662306a36Sopenharmony_ci cmd.data1 |= MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES; 231762306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ENABLE_RSS_QUEUES, 231862306a36Sopenharmony_ci &cmd, 0); 231962306a36Sopenharmony_ci if (status != 0) { 232062306a36Sopenharmony_ci netdev_err(dev, "failed to set number of slices\n"); 232162306a36Sopenharmony_ci goto abort_with_nothing; 232262306a36Sopenharmony_ci } 232362306a36Sopenharmony_ci /* setup the indirection table */ 232462306a36Sopenharmony_ci cmd.data0 = mgp->num_slices; 232562306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_TABLE_SIZE, 232662306a36Sopenharmony_ci &cmd, 0); 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci status |= myri10ge_send_cmd(mgp, 232962306a36Sopenharmony_ci MXGEFW_CMD_GET_RSS_TABLE_OFFSET, 233062306a36Sopenharmony_ci &cmd, 0); 233162306a36Sopenharmony_ci if (status != 0) { 233262306a36Sopenharmony_ci netdev_err(dev, "failed to setup rss tables\n"); 233362306a36Sopenharmony_ci goto abort_with_nothing; 233462306a36Sopenharmony_ci } 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci /* just enable an identity mapping */ 233762306a36Sopenharmony_ci itable = mgp->sram + cmd.data0; 233862306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) 233962306a36Sopenharmony_ci __raw_writeb(i, &itable[i]); 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci cmd.data0 = 1; 234262306a36Sopenharmony_ci cmd.data1 = myri10ge_rss_hash; 234362306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_RSS_ENABLE, 234462306a36Sopenharmony_ci &cmd, 0); 234562306a36Sopenharmony_ci if (status != 0) { 234662306a36Sopenharmony_ci netdev_err(dev, "failed to enable slices\n"); 234762306a36Sopenharmony_ci goto abort_with_nothing; 234862306a36Sopenharmony_ci } 234962306a36Sopenharmony_ci } 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci status = myri10ge_request_irq(mgp); 235262306a36Sopenharmony_ci if (status != 0) 235362306a36Sopenharmony_ci goto abort_with_nothing; 235462306a36Sopenharmony_ci 235562306a36Sopenharmony_ci /* decide what small buffer size to use. For good TCP rx 235662306a36Sopenharmony_ci * performance, it is important to not receive 1514 byte 235762306a36Sopenharmony_ci * frames into jumbo buffers, as it confuses the socket buffer 235862306a36Sopenharmony_ci * accounting code, leading to drops and erratic performance. 235962306a36Sopenharmony_ci */ 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_ci if (dev->mtu <= ETH_DATA_LEN) 236262306a36Sopenharmony_ci /* enough for a TCP header */ 236362306a36Sopenharmony_ci mgp->small_bytes = (128 > SMP_CACHE_BYTES) 236462306a36Sopenharmony_ci ? (128 - MXGEFW_PAD) 236562306a36Sopenharmony_ci : (SMP_CACHE_BYTES - MXGEFW_PAD); 236662306a36Sopenharmony_ci else 236762306a36Sopenharmony_ci /* enough for a vlan encapsulated ETH_DATA_LEN frame */ 236862306a36Sopenharmony_ci mgp->small_bytes = VLAN_ETH_FRAME_LEN; 236962306a36Sopenharmony_ci 237062306a36Sopenharmony_ci /* Override the small buffer size? */ 237162306a36Sopenharmony_ci if (myri10ge_small_bytes >= 0) 237262306a36Sopenharmony_ci mgp->small_bytes = myri10ge_small_bytes; 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci /* Firmware needs the big buff size as a power of 2. Lie and 237562306a36Sopenharmony_ci * tell him the buffer is larger, because we only use 1 237662306a36Sopenharmony_ci * buffer/pkt, and the mtu will prevent overruns. 237762306a36Sopenharmony_ci */ 237862306a36Sopenharmony_ci big_pow2 = dev->mtu + ETH_HLEN + VLAN_HLEN + MXGEFW_PAD; 237962306a36Sopenharmony_ci if (big_pow2 < MYRI10GE_ALLOC_SIZE / 2) { 238062306a36Sopenharmony_ci while (!is_power_of_2(big_pow2)) 238162306a36Sopenharmony_ci big_pow2++; 238262306a36Sopenharmony_ci mgp->big_bytes = dev->mtu + ETH_HLEN + VLAN_HLEN + MXGEFW_PAD; 238362306a36Sopenharmony_ci } else { 238462306a36Sopenharmony_ci big_pow2 = MYRI10GE_ALLOC_SIZE; 238562306a36Sopenharmony_ci mgp->big_bytes = big_pow2; 238662306a36Sopenharmony_ci } 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci /* setup the per-slice data structures */ 238962306a36Sopenharmony_ci for (slice = 0; slice < mgp->num_slices; slice++) { 239062306a36Sopenharmony_ci ss = &mgp->ss[slice]; 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci status = myri10ge_get_txrx(mgp, slice); 239362306a36Sopenharmony_ci if (status != 0) { 239462306a36Sopenharmony_ci netdev_err(dev, "failed to get ring sizes or locations\n"); 239562306a36Sopenharmony_ci goto abort_with_rings; 239662306a36Sopenharmony_ci } 239762306a36Sopenharmony_ci status = myri10ge_allocate_rings(ss); 239862306a36Sopenharmony_ci if (status != 0) 239962306a36Sopenharmony_ci goto abort_with_rings; 240062306a36Sopenharmony_ci 240162306a36Sopenharmony_ci /* only firmware which supports multiple TX queues 240262306a36Sopenharmony_ci * supports setting up the tx stats on non-zero 240362306a36Sopenharmony_ci * slices */ 240462306a36Sopenharmony_ci if (slice == 0 || mgp->dev->real_num_tx_queues > 1) 240562306a36Sopenharmony_ci status = myri10ge_set_stats(mgp, slice); 240662306a36Sopenharmony_ci if (status) { 240762306a36Sopenharmony_ci netdev_err(dev, "Couldn't set stats DMA\n"); 240862306a36Sopenharmony_ci goto abort_with_rings; 240962306a36Sopenharmony_ci } 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci /* must happen prior to any irq */ 241262306a36Sopenharmony_ci napi_enable(&(ss)->napi); 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci /* now give firmware buffers sizes, and MTU */ 241662306a36Sopenharmony_ci cmd.data0 = dev->mtu + ETH_HLEN + VLAN_HLEN; 241762306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_MTU, &cmd, 0); 241862306a36Sopenharmony_ci cmd.data0 = mgp->small_bytes; 241962306a36Sopenharmony_ci status |= 242062306a36Sopenharmony_ci myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, &cmd, 0); 242162306a36Sopenharmony_ci cmd.data0 = big_pow2; 242262306a36Sopenharmony_ci status |= 242362306a36Sopenharmony_ci myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_BIG_BUFFER_SIZE, &cmd, 0); 242462306a36Sopenharmony_ci if (status) { 242562306a36Sopenharmony_ci netdev_err(dev, "Couldn't set buffer sizes\n"); 242662306a36Sopenharmony_ci goto abort_with_rings; 242762306a36Sopenharmony_ci } 242862306a36Sopenharmony_ci 242962306a36Sopenharmony_ci /* 243062306a36Sopenharmony_ci * Set Linux style TSO mode; this is needed only on newer 243162306a36Sopenharmony_ci * firmware versions. Older versions default to Linux 243262306a36Sopenharmony_ci * style TSO 243362306a36Sopenharmony_ci */ 243462306a36Sopenharmony_ci cmd.data0 = 0; 243562306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_TSO_MODE, &cmd, 0); 243662306a36Sopenharmony_ci if (status && status != -ENOSYS) { 243762306a36Sopenharmony_ci netdev_err(dev, "Couldn't set TSO mode\n"); 243862306a36Sopenharmony_ci goto abort_with_rings; 243962306a36Sopenharmony_ci } 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_ci mgp->link_state = ~0U; 244262306a36Sopenharmony_ci mgp->rdma_tags_available = 15; 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0); 244562306a36Sopenharmony_ci if (status) { 244662306a36Sopenharmony_ci netdev_err(dev, "Couldn't bring up link\n"); 244762306a36Sopenharmony_ci goto abort_with_rings; 244862306a36Sopenharmony_ci } 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci mgp->running = MYRI10GE_ETH_RUNNING; 245162306a36Sopenharmony_ci mgp->watchdog_timer.expires = jiffies + myri10ge_watchdog_timeout * HZ; 245262306a36Sopenharmony_ci add_timer(&mgp->watchdog_timer); 245362306a36Sopenharmony_ci netif_tx_wake_all_queues(dev); 245462306a36Sopenharmony_ci 245562306a36Sopenharmony_ci return 0; 245662306a36Sopenharmony_ci 245762306a36Sopenharmony_ciabort_with_rings: 245862306a36Sopenharmony_ci while (slice) { 245962306a36Sopenharmony_ci slice--; 246062306a36Sopenharmony_ci napi_disable(&mgp->ss[slice].napi); 246162306a36Sopenharmony_ci } 246262306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) 246362306a36Sopenharmony_ci myri10ge_free_rings(&mgp->ss[i]); 246462306a36Sopenharmony_ci 246562306a36Sopenharmony_ci myri10ge_free_irq(mgp); 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ciabort_with_nothing: 246862306a36Sopenharmony_ci mgp->running = MYRI10GE_ETH_STOPPED; 246962306a36Sopenharmony_ci return -ENOMEM; 247062306a36Sopenharmony_ci} 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_cistatic int myri10ge_close(struct net_device *dev) 247362306a36Sopenharmony_ci{ 247462306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(dev); 247562306a36Sopenharmony_ci struct myri10ge_cmd cmd; 247662306a36Sopenharmony_ci int status, old_down_cnt; 247762306a36Sopenharmony_ci int i; 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci if (mgp->running != MYRI10GE_ETH_RUNNING) 248062306a36Sopenharmony_ci return 0; 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci if (mgp->ss[0].tx.req_bytes == NULL) 248362306a36Sopenharmony_ci return 0; 248462306a36Sopenharmony_ci 248562306a36Sopenharmony_ci del_timer_sync(&mgp->watchdog_timer); 248662306a36Sopenharmony_ci mgp->running = MYRI10GE_ETH_STOPPING; 248762306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) 248862306a36Sopenharmony_ci napi_disable(&mgp->ss[i].napi); 248962306a36Sopenharmony_ci 249062306a36Sopenharmony_ci netif_carrier_off(dev); 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci netif_tx_stop_all_queues(dev); 249362306a36Sopenharmony_ci if (mgp->rebooted == 0) { 249462306a36Sopenharmony_ci old_down_cnt = mgp->down_cnt; 249562306a36Sopenharmony_ci mb(); 249662306a36Sopenharmony_ci status = 249762306a36Sopenharmony_ci myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_DOWN, &cmd, 0); 249862306a36Sopenharmony_ci if (status) 249962306a36Sopenharmony_ci netdev_err(dev, "Couldn't bring down link\n"); 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci wait_event_timeout(mgp->down_wq, old_down_cnt != mgp->down_cnt, 250262306a36Sopenharmony_ci HZ); 250362306a36Sopenharmony_ci if (old_down_cnt == mgp->down_cnt) 250462306a36Sopenharmony_ci netdev_err(dev, "never got down irq\n"); 250562306a36Sopenharmony_ci } 250662306a36Sopenharmony_ci netif_tx_disable(dev); 250762306a36Sopenharmony_ci myri10ge_free_irq(mgp); 250862306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) 250962306a36Sopenharmony_ci myri10ge_free_rings(&mgp->ss[i]); 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci mgp->running = MYRI10GE_ETH_STOPPED; 251262306a36Sopenharmony_ci return 0; 251362306a36Sopenharmony_ci} 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci/* copy an array of struct mcp_kreq_ether_send's to the mcp. Copy 251662306a36Sopenharmony_ci * backwards one at a time and handle ring wraps */ 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_cistatic inline void 251962306a36Sopenharmony_cimyri10ge_submit_req_backwards(struct myri10ge_tx_buf *tx, 252062306a36Sopenharmony_ci struct mcp_kreq_ether_send *src, int cnt) 252162306a36Sopenharmony_ci{ 252262306a36Sopenharmony_ci int idx, starting_slot; 252362306a36Sopenharmony_ci starting_slot = tx->req; 252462306a36Sopenharmony_ci while (cnt > 1) { 252562306a36Sopenharmony_ci cnt--; 252662306a36Sopenharmony_ci idx = (starting_slot + cnt) & tx->mask; 252762306a36Sopenharmony_ci myri10ge_pio_copy(&tx->lanai[idx], &src[cnt], sizeof(*src)); 252862306a36Sopenharmony_ci mb(); 252962306a36Sopenharmony_ci } 253062306a36Sopenharmony_ci} 253162306a36Sopenharmony_ci 253262306a36Sopenharmony_ci/* 253362306a36Sopenharmony_ci * copy an array of struct mcp_kreq_ether_send's to the mcp. Copy 253462306a36Sopenharmony_ci * at most 32 bytes at a time, so as to avoid involving the software 253562306a36Sopenharmony_ci * pio handler in the nic. We re-write the first segment's flags 253662306a36Sopenharmony_ci * to mark them valid only after writing the entire chain. 253762306a36Sopenharmony_ci */ 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_cistatic inline void 254062306a36Sopenharmony_cimyri10ge_submit_req(struct myri10ge_tx_buf *tx, struct mcp_kreq_ether_send *src, 254162306a36Sopenharmony_ci int cnt) 254262306a36Sopenharmony_ci{ 254362306a36Sopenharmony_ci int idx, i; 254462306a36Sopenharmony_ci struct mcp_kreq_ether_send __iomem *dstp, *dst; 254562306a36Sopenharmony_ci struct mcp_kreq_ether_send *srcp; 254662306a36Sopenharmony_ci u8 last_flags; 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci idx = tx->req & tx->mask; 254962306a36Sopenharmony_ci 255062306a36Sopenharmony_ci last_flags = src->flags; 255162306a36Sopenharmony_ci src->flags = 0; 255262306a36Sopenharmony_ci mb(); 255362306a36Sopenharmony_ci dst = dstp = &tx->lanai[idx]; 255462306a36Sopenharmony_ci srcp = src; 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci if ((idx + cnt) < tx->mask) { 255762306a36Sopenharmony_ci for (i = 0; i < (cnt - 1); i += 2) { 255862306a36Sopenharmony_ci myri10ge_pio_copy(dstp, srcp, 2 * sizeof(*src)); 255962306a36Sopenharmony_ci mb(); /* force write every 32 bytes */ 256062306a36Sopenharmony_ci srcp += 2; 256162306a36Sopenharmony_ci dstp += 2; 256262306a36Sopenharmony_ci } 256362306a36Sopenharmony_ci } else { 256462306a36Sopenharmony_ci /* submit all but the first request, and ensure 256562306a36Sopenharmony_ci * that it is submitted below */ 256662306a36Sopenharmony_ci myri10ge_submit_req_backwards(tx, src, cnt); 256762306a36Sopenharmony_ci i = 0; 256862306a36Sopenharmony_ci } 256962306a36Sopenharmony_ci if (i < cnt) { 257062306a36Sopenharmony_ci /* submit the first request */ 257162306a36Sopenharmony_ci myri10ge_pio_copy(dstp, srcp, sizeof(*src)); 257262306a36Sopenharmony_ci mb(); /* barrier before setting valid flag */ 257362306a36Sopenharmony_ci } 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_ci /* re-write the last 32-bits with the valid flags */ 257662306a36Sopenharmony_ci src->flags = last_flags; 257762306a36Sopenharmony_ci put_be32(*((__be32 *) src + 3), (__be32 __iomem *) dst + 3); 257862306a36Sopenharmony_ci tx->req += cnt; 257962306a36Sopenharmony_ci mb(); 258062306a36Sopenharmony_ci} 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_cistatic void myri10ge_unmap_tx_dma(struct myri10ge_priv *mgp, 258362306a36Sopenharmony_ci struct myri10ge_tx_buf *tx, int idx) 258462306a36Sopenharmony_ci{ 258562306a36Sopenharmony_ci unsigned int len; 258662306a36Sopenharmony_ci int last_idx; 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci /* Free any DMA resources we've alloced and clear out the skb slot */ 258962306a36Sopenharmony_ci last_idx = (idx + 1) & tx->mask; 259062306a36Sopenharmony_ci idx = tx->req & tx->mask; 259162306a36Sopenharmony_ci do { 259262306a36Sopenharmony_ci len = dma_unmap_len(&tx->info[idx], len); 259362306a36Sopenharmony_ci if (len) { 259462306a36Sopenharmony_ci if (tx->info[idx].skb != NULL) 259562306a36Sopenharmony_ci dma_unmap_single(&mgp->pdev->dev, 259662306a36Sopenharmony_ci dma_unmap_addr(&tx->info[idx], 259762306a36Sopenharmony_ci bus), len, 259862306a36Sopenharmony_ci DMA_TO_DEVICE); 259962306a36Sopenharmony_ci else 260062306a36Sopenharmony_ci dma_unmap_page(&mgp->pdev->dev, 260162306a36Sopenharmony_ci dma_unmap_addr(&tx->info[idx], 260262306a36Sopenharmony_ci bus), len, 260362306a36Sopenharmony_ci DMA_TO_DEVICE); 260462306a36Sopenharmony_ci dma_unmap_len_set(&tx->info[idx], len, 0); 260562306a36Sopenharmony_ci tx->info[idx].skb = NULL; 260662306a36Sopenharmony_ci } 260762306a36Sopenharmony_ci idx = (idx + 1) & tx->mask; 260862306a36Sopenharmony_ci } while (idx != last_idx); 260962306a36Sopenharmony_ci} 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci/* 261262306a36Sopenharmony_ci * Transmit a packet. We need to split the packet so that a single 261362306a36Sopenharmony_ci * segment does not cross myri10ge->tx_boundary, so this makes segment 261462306a36Sopenharmony_ci * counting tricky. So rather than try to count segments up front, we 261562306a36Sopenharmony_ci * just give up if there are too few segments to hold a reasonably 261662306a36Sopenharmony_ci * fragmented packet currently available. If we run 261762306a36Sopenharmony_ci * out of segments while preparing a packet for DMA, we just linearize 261862306a36Sopenharmony_ci * it and try again. 261962306a36Sopenharmony_ci */ 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_cistatic netdev_tx_t myri10ge_xmit(struct sk_buff *skb, 262262306a36Sopenharmony_ci struct net_device *dev) 262362306a36Sopenharmony_ci{ 262462306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(dev); 262562306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 262662306a36Sopenharmony_ci struct mcp_kreq_ether_send *req; 262762306a36Sopenharmony_ci struct myri10ge_tx_buf *tx; 262862306a36Sopenharmony_ci skb_frag_t *frag; 262962306a36Sopenharmony_ci struct netdev_queue *netdev_queue; 263062306a36Sopenharmony_ci dma_addr_t bus; 263162306a36Sopenharmony_ci u32 low; 263262306a36Sopenharmony_ci __be32 high_swapped; 263362306a36Sopenharmony_ci unsigned int len; 263462306a36Sopenharmony_ci int idx, avail, frag_cnt, frag_idx, count, mss, max_segments; 263562306a36Sopenharmony_ci u16 pseudo_hdr_offset, cksum_offset, queue; 263662306a36Sopenharmony_ci int cum_len, seglen, boundary, rdma_count; 263762306a36Sopenharmony_ci u8 flags, odd_flag; 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci queue = skb_get_queue_mapping(skb); 264062306a36Sopenharmony_ci ss = &mgp->ss[queue]; 264162306a36Sopenharmony_ci netdev_queue = netdev_get_tx_queue(mgp->dev, queue); 264262306a36Sopenharmony_ci tx = &ss->tx; 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_ciagain: 264562306a36Sopenharmony_ci req = tx->req_list; 264662306a36Sopenharmony_ci avail = tx->mask - 1 - (tx->req - tx->done); 264762306a36Sopenharmony_ci 264862306a36Sopenharmony_ci mss = 0; 264962306a36Sopenharmony_ci max_segments = MXGEFW_MAX_SEND_DESC; 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci if (skb_is_gso(skb)) { 265262306a36Sopenharmony_ci mss = skb_shinfo(skb)->gso_size; 265362306a36Sopenharmony_ci max_segments = MYRI10GE_MAX_SEND_DESC_TSO; 265462306a36Sopenharmony_ci } 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci if ((unlikely(avail < max_segments))) { 265762306a36Sopenharmony_ci /* we are out of transmit resources */ 265862306a36Sopenharmony_ci tx->stop_queue++; 265962306a36Sopenharmony_ci netif_tx_stop_queue(netdev_queue); 266062306a36Sopenharmony_ci return NETDEV_TX_BUSY; 266162306a36Sopenharmony_ci } 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci /* Setup checksum offloading, if needed */ 266462306a36Sopenharmony_ci cksum_offset = 0; 266562306a36Sopenharmony_ci pseudo_hdr_offset = 0; 266662306a36Sopenharmony_ci odd_flag = 0; 266762306a36Sopenharmony_ci flags = (MXGEFW_FLAGS_NO_TSO | MXGEFW_FLAGS_FIRST); 266862306a36Sopenharmony_ci if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { 266962306a36Sopenharmony_ci cksum_offset = skb_checksum_start_offset(skb); 267062306a36Sopenharmony_ci pseudo_hdr_offset = cksum_offset + skb->csum_offset; 267162306a36Sopenharmony_ci /* If the headers are excessively large, then we must 267262306a36Sopenharmony_ci * fall back to a software checksum */ 267362306a36Sopenharmony_ci if (unlikely(!mss && (cksum_offset > 255 || 267462306a36Sopenharmony_ci pseudo_hdr_offset > 127))) { 267562306a36Sopenharmony_ci if (skb_checksum_help(skb)) 267662306a36Sopenharmony_ci goto drop; 267762306a36Sopenharmony_ci cksum_offset = 0; 267862306a36Sopenharmony_ci pseudo_hdr_offset = 0; 267962306a36Sopenharmony_ci } else { 268062306a36Sopenharmony_ci odd_flag = MXGEFW_FLAGS_ALIGN_ODD; 268162306a36Sopenharmony_ci flags |= MXGEFW_FLAGS_CKSUM; 268262306a36Sopenharmony_ci } 268362306a36Sopenharmony_ci } 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci cum_len = 0; 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci if (mss) { /* TSO */ 268862306a36Sopenharmony_ci /* this removes any CKSUM flag from before */ 268962306a36Sopenharmony_ci flags = (MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST); 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci /* negative cum_len signifies to the 269262306a36Sopenharmony_ci * send loop that we are still in the 269362306a36Sopenharmony_ci * header portion of the TSO packet. 269462306a36Sopenharmony_ci * TSO header can be at most 1KB long */ 269562306a36Sopenharmony_ci cum_len = -skb_tcp_all_headers(skb); 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci /* for IPv6 TSO, the checksum offset stores the 269862306a36Sopenharmony_ci * TCP header length, to save the firmware from 269962306a36Sopenharmony_ci * the need to parse the headers */ 270062306a36Sopenharmony_ci if (skb_is_gso_v6(skb)) { 270162306a36Sopenharmony_ci cksum_offset = tcp_hdrlen(skb); 270262306a36Sopenharmony_ci /* Can only handle headers <= max_tso6 long */ 270362306a36Sopenharmony_ci if (unlikely(-cum_len > mgp->max_tso6)) 270462306a36Sopenharmony_ci return myri10ge_sw_tso(skb, dev); 270562306a36Sopenharmony_ci } 270662306a36Sopenharmony_ci /* for TSO, pseudo_hdr_offset holds mss. 270762306a36Sopenharmony_ci * The firmware figures out where to put 270862306a36Sopenharmony_ci * the checksum by parsing the header. */ 270962306a36Sopenharmony_ci pseudo_hdr_offset = mss; 271062306a36Sopenharmony_ci } else 271162306a36Sopenharmony_ci /* Mark small packets, and pad out tiny packets */ 271262306a36Sopenharmony_ci if (skb->len <= MXGEFW_SEND_SMALL_SIZE) { 271362306a36Sopenharmony_ci flags |= MXGEFW_FLAGS_SMALL; 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci /* pad frames to at least ETH_ZLEN bytes */ 271662306a36Sopenharmony_ci if (eth_skb_pad(skb)) { 271762306a36Sopenharmony_ci /* The packet is gone, so we must 271862306a36Sopenharmony_ci * return 0 */ 271962306a36Sopenharmony_ci ss->stats.tx_dropped += 1; 272062306a36Sopenharmony_ci return NETDEV_TX_OK; 272162306a36Sopenharmony_ci } 272262306a36Sopenharmony_ci } 272362306a36Sopenharmony_ci 272462306a36Sopenharmony_ci /* map the skb for DMA */ 272562306a36Sopenharmony_ci len = skb_headlen(skb); 272662306a36Sopenharmony_ci bus = dma_map_single(&mgp->pdev->dev, skb->data, len, DMA_TO_DEVICE); 272762306a36Sopenharmony_ci if (unlikely(dma_mapping_error(&mgp->pdev->dev, bus))) 272862306a36Sopenharmony_ci goto drop; 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci idx = tx->req & tx->mask; 273162306a36Sopenharmony_ci tx->info[idx].skb = skb; 273262306a36Sopenharmony_ci dma_unmap_addr_set(&tx->info[idx], bus, bus); 273362306a36Sopenharmony_ci dma_unmap_len_set(&tx->info[idx], len, len); 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci frag_cnt = skb_shinfo(skb)->nr_frags; 273662306a36Sopenharmony_ci frag_idx = 0; 273762306a36Sopenharmony_ci count = 0; 273862306a36Sopenharmony_ci rdma_count = 0; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci /* "rdma_count" is the number of RDMAs belonging to the 274162306a36Sopenharmony_ci * current packet BEFORE the current send request. For 274262306a36Sopenharmony_ci * non-TSO packets, this is equal to "count". 274362306a36Sopenharmony_ci * For TSO packets, rdma_count needs to be reset 274462306a36Sopenharmony_ci * to 0 after a segment cut. 274562306a36Sopenharmony_ci * 274662306a36Sopenharmony_ci * The rdma_count field of the send request is 274762306a36Sopenharmony_ci * the number of RDMAs of the packet starting at 274862306a36Sopenharmony_ci * that request. For TSO send requests with one ore more cuts 274962306a36Sopenharmony_ci * in the middle, this is the number of RDMAs starting 275062306a36Sopenharmony_ci * after the last cut in the request. All previous 275162306a36Sopenharmony_ci * segments before the last cut implicitly have 1 RDMA. 275262306a36Sopenharmony_ci * 275362306a36Sopenharmony_ci * Since the number of RDMAs is not known beforehand, 275462306a36Sopenharmony_ci * it must be filled-in retroactively - after each 275562306a36Sopenharmony_ci * segmentation cut or at the end of the entire packet. 275662306a36Sopenharmony_ci */ 275762306a36Sopenharmony_ci 275862306a36Sopenharmony_ci while (1) { 275962306a36Sopenharmony_ci /* Break the SKB or Fragment up into pieces which 276062306a36Sopenharmony_ci * do not cross mgp->tx_boundary */ 276162306a36Sopenharmony_ci low = MYRI10GE_LOWPART_TO_U32(bus); 276262306a36Sopenharmony_ci high_swapped = htonl(MYRI10GE_HIGHPART_TO_U32(bus)); 276362306a36Sopenharmony_ci while (len) { 276462306a36Sopenharmony_ci u8 flags_next; 276562306a36Sopenharmony_ci int cum_len_next; 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_ci if (unlikely(count == max_segments)) 276862306a36Sopenharmony_ci goto abort_linearize; 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci boundary = 277162306a36Sopenharmony_ci (low + mgp->tx_boundary) & ~(mgp->tx_boundary - 1); 277262306a36Sopenharmony_ci seglen = boundary - low; 277362306a36Sopenharmony_ci if (seglen > len) 277462306a36Sopenharmony_ci seglen = len; 277562306a36Sopenharmony_ci flags_next = flags & ~MXGEFW_FLAGS_FIRST; 277662306a36Sopenharmony_ci cum_len_next = cum_len + seglen; 277762306a36Sopenharmony_ci if (mss) { /* TSO */ 277862306a36Sopenharmony_ci (req - rdma_count)->rdma_count = rdma_count + 1; 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci if (likely(cum_len >= 0)) { /* payload */ 278162306a36Sopenharmony_ci int next_is_first, chop; 278262306a36Sopenharmony_ci 278362306a36Sopenharmony_ci chop = (cum_len_next > mss); 278462306a36Sopenharmony_ci cum_len_next = cum_len_next % mss; 278562306a36Sopenharmony_ci next_is_first = (cum_len_next == 0); 278662306a36Sopenharmony_ci flags |= chop * MXGEFW_FLAGS_TSO_CHOP; 278762306a36Sopenharmony_ci flags_next |= next_is_first * 278862306a36Sopenharmony_ci MXGEFW_FLAGS_FIRST; 278962306a36Sopenharmony_ci rdma_count |= -(chop | next_is_first); 279062306a36Sopenharmony_ci rdma_count += chop & ~next_is_first; 279162306a36Sopenharmony_ci } else if (likely(cum_len_next >= 0)) { /* header ends */ 279262306a36Sopenharmony_ci int small; 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_ci rdma_count = -1; 279562306a36Sopenharmony_ci cum_len_next = 0; 279662306a36Sopenharmony_ci seglen = -cum_len; 279762306a36Sopenharmony_ci small = (mss <= MXGEFW_SEND_SMALL_SIZE); 279862306a36Sopenharmony_ci flags_next = MXGEFW_FLAGS_TSO_PLD | 279962306a36Sopenharmony_ci MXGEFW_FLAGS_FIRST | 280062306a36Sopenharmony_ci (small * MXGEFW_FLAGS_SMALL); 280162306a36Sopenharmony_ci } 280262306a36Sopenharmony_ci } 280362306a36Sopenharmony_ci req->addr_high = high_swapped; 280462306a36Sopenharmony_ci req->addr_low = htonl(low); 280562306a36Sopenharmony_ci req->pseudo_hdr_offset = htons(pseudo_hdr_offset); 280662306a36Sopenharmony_ci req->pad = 0; /* complete solid 16-byte block; does this matter? */ 280762306a36Sopenharmony_ci req->rdma_count = 1; 280862306a36Sopenharmony_ci req->length = htons(seglen); 280962306a36Sopenharmony_ci req->cksum_offset = cksum_offset; 281062306a36Sopenharmony_ci req->flags = flags | ((cum_len & 1) * odd_flag); 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci low += seglen; 281362306a36Sopenharmony_ci len -= seglen; 281462306a36Sopenharmony_ci cum_len = cum_len_next; 281562306a36Sopenharmony_ci flags = flags_next; 281662306a36Sopenharmony_ci req++; 281762306a36Sopenharmony_ci count++; 281862306a36Sopenharmony_ci rdma_count++; 281962306a36Sopenharmony_ci if (cksum_offset != 0 && !(mss && skb_is_gso_v6(skb))) { 282062306a36Sopenharmony_ci if (unlikely(cksum_offset > seglen)) 282162306a36Sopenharmony_ci cksum_offset -= seglen; 282262306a36Sopenharmony_ci else 282362306a36Sopenharmony_ci cksum_offset = 0; 282462306a36Sopenharmony_ci } 282562306a36Sopenharmony_ci } 282662306a36Sopenharmony_ci if (frag_idx == frag_cnt) 282762306a36Sopenharmony_ci break; 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci /* map next fragment for DMA */ 283062306a36Sopenharmony_ci frag = &skb_shinfo(skb)->frags[frag_idx]; 283162306a36Sopenharmony_ci frag_idx++; 283262306a36Sopenharmony_ci len = skb_frag_size(frag); 283362306a36Sopenharmony_ci bus = skb_frag_dma_map(&mgp->pdev->dev, frag, 0, len, 283462306a36Sopenharmony_ci DMA_TO_DEVICE); 283562306a36Sopenharmony_ci if (unlikely(dma_mapping_error(&mgp->pdev->dev, bus))) { 283662306a36Sopenharmony_ci myri10ge_unmap_tx_dma(mgp, tx, idx); 283762306a36Sopenharmony_ci goto drop; 283862306a36Sopenharmony_ci } 283962306a36Sopenharmony_ci idx = (count + tx->req) & tx->mask; 284062306a36Sopenharmony_ci dma_unmap_addr_set(&tx->info[idx], bus, bus); 284162306a36Sopenharmony_ci dma_unmap_len_set(&tx->info[idx], len, len); 284262306a36Sopenharmony_ci } 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci (req - rdma_count)->rdma_count = rdma_count; 284562306a36Sopenharmony_ci if (mss) 284662306a36Sopenharmony_ci do { 284762306a36Sopenharmony_ci req--; 284862306a36Sopenharmony_ci req->flags |= MXGEFW_FLAGS_TSO_LAST; 284962306a36Sopenharmony_ci } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP | 285062306a36Sopenharmony_ci MXGEFW_FLAGS_FIRST))); 285162306a36Sopenharmony_ci idx = ((count - 1) + tx->req) & tx->mask; 285262306a36Sopenharmony_ci tx->info[idx].last = 1; 285362306a36Sopenharmony_ci myri10ge_submit_req(tx, tx->req_list, count); 285462306a36Sopenharmony_ci /* if using multiple tx queues, make sure NIC polls the 285562306a36Sopenharmony_ci * current slice */ 285662306a36Sopenharmony_ci if ((mgp->dev->real_num_tx_queues > 1) && tx->queue_active == 0) { 285762306a36Sopenharmony_ci tx->queue_active = 1; 285862306a36Sopenharmony_ci put_be32(htonl(1), tx->send_go); 285962306a36Sopenharmony_ci mb(); 286062306a36Sopenharmony_ci } 286162306a36Sopenharmony_ci tx->pkt_start++; 286262306a36Sopenharmony_ci if ((avail - count) < MXGEFW_MAX_SEND_DESC) { 286362306a36Sopenharmony_ci tx->stop_queue++; 286462306a36Sopenharmony_ci netif_tx_stop_queue(netdev_queue); 286562306a36Sopenharmony_ci } 286662306a36Sopenharmony_ci return NETDEV_TX_OK; 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ciabort_linearize: 286962306a36Sopenharmony_ci myri10ge_unmap_tx_dma(mgp, tx, idx); 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci if (skb_is_gso(skb)) { 287262306a36Sopenharmony_ci netdev_err(mgp->dev, "TSO but wanted to linearize?!?!?\n"); 287362306a36Sopenharmony_ci goto drop; 287462306a36Sopenharmony_ci } 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci if (skb_linearize(skb)) 287762306a36Sopenharmony_ci goto drop; 287862306a36Sopenharmony_ci 287962306a36Sopenharmony_ci tx->linearized++; 288062306a36Sopenharmony_ci goto again; 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_cidrop: 288362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 288462306a36Sopenharmony_ci ss->stats.tx_dropped += 1; 288562306a36Sopenharmony_ci return NETDEV_TX_OK; 288662306a36Sopenharmony_ci 288762306a36Sopenharmony_ci} 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_cistatic netdev_tx_t myri10ge_sw_tso(struct sk_buff *skb, 289062306a36Sopenharmony_ci struct net_device *dev) 289162306a36Sopenharmony_ci{ 289262306a36Sopenharmony_ci struct sk_buff *segs, *curr, *next; 289362306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(dev); 289462306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 289562306a36Sopenharmony_ci netdev_tx_t status; 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ci segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6); 289862306a36Sopenharmony_ci if (IS_ERR(segs)) 289962306a36Sopenharmony_ci goto drop; 290062306a36Sopenharmony_ci 290162306a36Sopenharmony_ci skb_list_walk_safe(segs, curr, next) { 290262306a36Sopenharmony_ci skb_mark_not_on_list(curr); 290362306a36Sopenharmony_ci status = myri10ge_xmit(curr, dev); 290462306a36Sopenharmony_ci if (status != 0) { 290562306a36Sopenharmony_ci dev_kfree_skb_any(curr); 290662306a36Sopenharmony_ci skb_list_walk_safe(next, curr, next) { 290762306a36Sopenharmony_ci curr->next = NULL; 290862306a36Sopenharmony_ci dev_kfree_skb_any(curr); 290962306a36Sopenharmony_ci } 291062306a36Sopenharmony_ci goto drop; 291162306a36Sopenharmony_ci } 291262306a36Sopenharmony_ci } 291362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 291462306a36Sopenharmony_ci return NETDEV_TX_OK; 291562306a36Sopenharmony_ci 291662306a36Sopenharmony_cidrop: 291762306a36Sopenharmony_ci ss = &mgp->ss[skb_get_queue_mapping(skb)]; 291862306a36Sopenharmony_ci dev_kfree_skb_any(skb); 291962306a36Sopenharmony_ci ss->stats.tx_dropped += 1; 292062306a36Sopenharmony_ci return NETDEV_TX_OK; 292162306a36Sopenharmony_ci} 292262306a36Sopenharmony_ci 292362306a36Sopenharmony_cistatic void myri10ge_get_stats(struct net_device *dev, 292462306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 292562306a36Sopenharmony_ci{ 292662306a36Sopenharmony_ci const struct myri10ge_priv *mgp = netdev_priv(dev); 292762306a36Sopenharmony_ci const struct myri10ge_slice_netstats *slice_stats; 292862306a36Sopenharmony_ci int i; 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 293162306a36Sopenharmony_ci slice_stats = &mgp->ss[i].stats; 293262306a36Sopenharmony_ci stats->rx_packets += slice_stats->rx_packets; 293362306a36Sopenharmony_ci stats->tx_packets += slice_stats->tx_packets; 293462306a36Sopenharmony_ci stats->rx_bytes += slice_stats->rx_bytes; 293562306a36Sopenharmony_ci stats->tx_bytes += slice_stats->tx_bytes; 293662306a36Sopenharmony_ci stats->rx_dropped += slice_stats->rx_dropped; 293762306a36Sopenharmony_ci stats->tx_dropped += slice_stats->tx_dropped; 293862306a36Sopenharmony_ci } 293962306a36Sopenharmony_ci} 294062306a36Sopenharmony_ci 294162306a36Sopenharmony_cistatic void myri10ge_set_multicast_list(struct net_device *dev) 294262306a36Sopenharmony_ci{ 294362306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(dev); 294462306a36Sopenharmony_ci struct myri10ge_cmd cmd; 294562306a36Sopenharmony_ci struct netdev_hw_addr *ha; 294662306a36Sopenharmony_ci __be32 data[2] = { 0, 0 }; 294762306a36Sopenharmony_ci int err; 294862306a36Sopenharmony_ci 294962306a36Sopenharmony_ci /* can be called from atomic contexts, 295062306a36Sopenharmony_ci * pass 1 to force atomicity in myri10ge_send_cmd() */ 295162306a36Sopenharmony_ci myri10ge_change_promisc(mgp, dev->flags & IFF_PROMISC, 1); 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci /* This firmware is known to not support multicast */ 295462306a36Sopenharmony_ci if (!mgp->fw_multicast_support) 295562306a36Sopenharmony_ci return; 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci /* Disable multicast filtering */ 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci err = myri10ge_send_cmd(mgp, MXGEFW_ENABLE_ALLMULTI, &cmd, 1); 296062306a36Sopenharmony_ci if (err != 0) { 296162306a36Sopenharmony_ci netdev_err(dev, "Failed MXGEFW_ENABLE_ALLMULTI, error status: %d\n", 296262306a36Sopenharmony_ci err); 296362306a36Sopenharmony_ci goto abort; 296462306a36Sopenharmony_ci } 296562306a36Sopenharmony_ci 296662306a36Sopenharmony_ci if ((dev->flags & IFF_ALLMULTI) || mgp->adopted_rx_filter_bug) { 296762306a36Sopenharmony_ci /* request to disable multicast filtering, so quit here */ 296862306a36Sopenharmony_ci return; 296962306a36Sopenharmony_ci } 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci /* Flush the filters */ 297262306a36Sopenharmony_ci 297362306a36Sopenharmony_ci err = myri10ge_send_cmd(mgp, MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, 297462306a36Sopenharmony_ci &cmd, 1); 297562306a36Sopenharmony_ci if (err != 0) { 297662306a36Sopenharmony_ci netdev_err(dev, "Failed MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, error status: %d\n", 297762306a36Sopenharmony_ci err); 297862306a36Sopenharmony_ci goto abort; 297962306a36Sopenharmony_ci } 298062306a36Sopenharmony_ci 298162306a36Sopenharmony_ci /* Walk the multicast list, and add each address */ 298262306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 298362306a36Sopenharmony_ci memcpy(data, &ha->addr, ETH_ALEN); 298462306a36Sopenharmony_ci cmd.data0 = ntohl(data[0]); 298562306a36Sopenharmony_ci cmd.data1 = ntohl(data[1]); 298662306a36Sopenharmony_ci err = myri10ge_send_cmd(mgp, MXGEFW_JOIN_MULTICAST_GROUP, 298762306a36Sopenharmony_ci &cmd, 1); 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_ci if (err != 0) { 299062306a36Sopenharmony_ci netdev_err(dev, "Failed MXGEFW_JOIN_MULTICAST_GROUP, error status:%d %pM\n", 299162306a36Sopenharmony_ci err, ha->addr); 299262306a36Sopenharmony_ci goto abort; 299362306a36Sopenharmony_ci } 299462306a36Sopenharmony_ci } 299562306a36Sopenharmony_ci /* Enable multicast filtering */ 299662306a36Sopenharmony_ci err = myri10ge_send_cmd(mgp, MXGEFW_DISABLE_ALLMULTI, &cmd, 1); 299762306a36Sopenharmony_ci if (err != 0) { 299862306a36Sopenharmony_ci netdev_err(dev, "Failed MXGEFW_DISABLE_ALLMULTI, error status: %d\n", 299962306a36Sopenharmony_ci err); 300062306a36Sopenharmony_ci goto abort; 300162306a36Sopenharmony_ci } 300262306a36Sopenharmony_ci 300362306a36Sopenharmony_ci return; 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ciabort: 300662306a36Sopenharmony_ci return; 300762306a36Sopenharmony_ci} 300862306a36Sopenharmony_ci 300962306a36Sopenharmony_cistatic int myri10ge_set_mac_address(struct net_device *dev, void *addr) 301062306a36Sopenharmony_ci{ 301162306a36Sopenharmony_ci struct sockaddr *sa = addr; 301262306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(dev); 301362306a36Sopenharmony_ci int status; 301462306a36Sopenharmony_ci 301562306a36Sopenharmony_ci if (!is_valid_ether_addr(sa->sa_data)) 301662306a36Sopenharmony_ci return -EADDRNOTAVAIL; 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ci status = myri10ge_update_mac_address(mgp, sa->sa_data); 301962306a36Sopenharmony_ci if (status != 0) { 302062306a36Sopenharmony_ci netdev_err(dev, "changing mac address failed with %d\n", 302162306a36Sopenharmony_ci status); 302262306a36Sopenharmony_ci return status; 302362306a36Sopenharmony_ci } 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_ci /* change the dev structure */ 302662306a36Sopenharmony_ci eth_hw_addr_set(dev, sa->sa_data); 302762306a36Sopenharmony_ci return 0; 302862306a36Sopenharmony_ci} 302962306a36Sopenharmony_ci 303062306a36Sopenharmony_cistatic int myri10ge_change_mtu(struct net_device *dev, int new_mtu) 303162306a36Sopenharmony_ci{ 303262306a36Sopenharmony_ci struct myri10ge_priv *mgp = netdev_priv(dev); 303362306a36Sopenharmony_ci 303462306a36Sopenharmony_ci netdev_info(dev, "changing mtu from %d to %d\n", dev->mtu, new_mtu); 303562306a36Sopenharmony_ci if (mgp->running) { 303662306a36Sopenharmony_ci /* if we change the mtu on an active device, we must 303762306a36Sopenharmony_ci * reset the device so the firmware sees the change */ 303862306a36Sopenharmony_ci myri10ge_close(dev); 303962306a36Sopenharmony_ci dev->mtu = new_mtu; 304062306a36Sopenharmony_ci myri10ge_open(dev); 304162306a36Sopenharmony_ci } else 304262306a36Sopenharmony_ci dev->mtu = new_mtu; 304362306a36Sopenharmony_ci 304462306a36Sopenharmony_ci return 0; 304562306a36Sopenharmony_ci} 304662306a36Sopenharmony_ci 304762306a36Sopenharmony_ci/* 304862306a36Sopenharmony_ci * Enable ECRC to align PCI-E Completion packets on an 8-byte boundary. 304962306a36Sopenharmony_ci * Only do it if the bridge is a root port since we don't want to disturb 305062306a36Sopenharmony_ci * any other device, except if forced with myri10ge_ecrc_enable > 1. 305162306a36Sopenharmony_ci */ 305262306a36Sopenharmony_ci 305362306a36Sopenharmony_cistatic void myri10ge_enable_ecrc(struct myri10ge_priv *mgp) 305462306a36Sopenharmony_ci{ 305562306a36Sopenharmony_ci struct pci_dev *bridge = mgp->pdev->bus->self; 305662306a36Sopenharmony_ci struct device *dev = &mgp->pdev->dev; 305762306a36Sopenharmony_ci int cap; 305862306a36Sopenharmony_ci unsigned err_cap; 305962306a36Sopenharmony_ci int ret; 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci if (!myri10ge_ecrc_enable || !bridge) 306262306a36Sopenharmony_ci return; 306362306a36Sopenharmony_ci 306462306a36Sopenharmony_ci /* check that the bridge is a root port */ 306562306a36Sopenharmony_ci if (pci_pcie_type(bridge) != PCI_EXP_TYPE_ROOT_PORT) { 306662306a36Sopenharmony_ci if (myri10ge_ecrc_enable > 1) { 306762306a36Sopenharmony_ci struct pci_dev *prev_bridge, *old_bridge = bridge; 306862306a36Sopenharmony_ci 306962306a36Sopenharmony_ci /* Walk the hierarchy up to the root port 307062306a36Sopenharmony_ci * where ECRC has to be enabled */ 307162306a36Sopenharmony_ci do { 307262306a36Sopenharmony_ci prev_bridge = bridge; 307362306a36Sopenharmony_ci bridge = bridge->bus->self; 307462306a36Sopenharmony_ci if (!bridge || prev_bridge == bridge) { 307562306a36Sopenharmony_ci dev_err(dev, 307662306a36Sopenharmony_ci "Failed to find root port" 307762306a36Sopenharmony_ci " to force ECRC\n"); 307862306a36Sopenharmony_ci return; 307962306a36Sopenharmony_ci } 308062306a36Sopenharmony_ci } while (pci_pcie_type(bridge) != 308162306a36Sopenharmony_ci PCI_EXP_TYPE_ROOT_PORT); 308262306a36Sopenharmony_ci 308362306a36Sopenharmony_ci dev_info(dev, 308462306a36Sopenharmony_ci "Forcing ECRC on non-root port %s" 308562306a36Sopenharmony_ci " (enabling on root port %s)\n", 308662306a36Sopenharmony_ci pci_name(old_bridge), pci_name(bridge)); 308762306a36Sopenharmony_ci } else { 308862306a36Sopenharmony_ci dev_err(dev, 308962306a36Sopenharmony_ci "Not enabling ECRC on non-root port %s\n", 309062306a36Sopenharmony_ci pci_name(bridge)); 309162306a36Sopenharmony_ci return; 309262306a36Sopenharmony_ci } 309362306a36Sopenharmony_ci } 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci cap = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ERR); 309662306a36Sopenharmony_ci if (!cap) 309762306a36Sopenharmony_ci return; 309862306a36Sopenharmony_ci 309962306a36Sopenharmony_ci ret = pci_read_config_dword(bridge, cap + PCI_ERR_CAP, &err_cap); 310062306a36Sopenharmony_ci if (ret) { 310162306a36Sopenharmony_ci dev_err(dev, "failed reading ext-conf-space of %s\n", 310262306a36Sopenharmony_ci pci_name(bridge)); 310362306a36Sopenharmony_ci dev_err(dev, "\t pci=nommconf in use? " 310462306a36Sopenharmony_ci "or buggy/incomplete/absent ACPI MCFG attr?\n"); 310562306a36Sopenharmony_ci return; 310662306a36Sopenharmony_ci } 310762306a36Sopenharmony_ci if (!(err_cap & PCI_ERR_CAP_ECRC_GENC)) 310862306a36Sopenharmony_ci return; 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci err_cap |= PCI_ERR_CAP_ECRC_GENE; 311162306a36Sopenharmony_ci pci_write_config_dword(bridge, cap + PCI_ERR_CAP, err_cap); 311262306a36Sopenharmony_ci dev_info(dev, "Enabled ECRC on upstream bridge %s\n", pci_name(bridge)); 311362306a36Sopenharmony_ci} 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci/* 311662306a36Sopenharmony_ci * The Lanai Z8E PCI-E interface achieves higher Read-DMA throughput 311762306a36Sopenharmony_ci * when the PCI-E Completion packets are aligned on an 8-byte 311862306a36Sopenharmony_ci * boundary. Some PCI-E chip sets always align Completion packets; on 311962306a36Sopenharmony_ci * the ones that do not, the alignment can be enforced by enabling 312062306a36Sopenharmony_ci * ECRC generation (if supported). 312162306a36Sopenharmony_ci * 312262306a36Sopenharmony_ci * When PCI-E Completion packets are not aligned, it is actually more 312362306a36Sopenharmony_ci * efficient to limit Read-DMA transactions to 2KB, rather than 4KB. 312462306a36Sopenharmony_ci * 312562306a36Sopenharmony_ci * If the driver can neither enable ECRC nor verify that it has 312662306a36Sopenharmony_ci * already been enabled, then it must use a firmware image which works 312762306a36Sopenharmony_ci * around unaligned completion packets (myri10ge_rss_ethp_z8e.dat), and it 312862306a36Sopenharmony_ci * should also ensure that it never gives the device a Read-DMA which is 312962306a36Sopenharmony_ci * larger than 2KB by setting the tx_boundary to 2KB. If ECRC is 313062306a36Sopenharmony_ci * enabled, then the driver should use the aligned (myri10ge_rss_eth_z8e.dat) 313162306a36Sopenharmony_ci * firmware image, and set tx_boundary to 4KB. 313262306a36Sopenharmony_ci */ 313362306a36Sopenharmony_ci 313462306a36Sopenharmony_cistatic void myri10ge_firmware_probe(struct myri10ge_priv *mgp) 313562306a36Sopenharmony_ci{ 313662306a36Sopenharmony_ci struct pci_dev *pdev = mgp->pdev; 313762306a36Sopenharmony_ci struct device *dev = &pdev->dev; 313862306a36Sopenharmony_ci int status; 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci mgp->tx_boundary = 4096; 314162306a36Sopenharmony_ci /* 314262306a36Sopenharmony_ci * Verify the max read request size was set to 4KB 314362306a36Sopenharmony_ci * before trying the test with 4KB. 314462306a36Sopenharmony_ci */ 314562306a36Sopenharmony_ci status = pcie_get_readrq(pdev); 314662306a36Sopenharmony_ci if (status < 0) { 314762306a36Sopenharmony_ci dev_err(dev, "Couldn't read max read req size: %d\n", status); 314862306a36Sopenharmony_ci goto abort; 314962306a36Sopenharmony_ci } 315062306a36Sopenharmony_ci if (status != 4096) { 315162306a36Sopenharmony_ci dev_warn(dev, "Max Read Request size != 4096 (%d)\n", status); 315262306a36Sopenharmony_ci mgp->tx_boundary = 2048; 315362306a36Sopenharmony_ci } 315462306a36Sopenharmony_ci /* 315562306a36Sopenharmony_ci * load the optimized firmware (which assumes aligned PCIe 315662306a36Sopenharmony_ci * completions) in order to see if it works on this host. 315762306a36Sopenharmony_ci */ 315862306a36Sopenharmony_ci set_fw_name(mgp, myri10ge_fw_aligned, false); 315962306a36Sopenharmony_ci status = myri10ge_load_firmware(mgp, 1); 316062306a36Sopenharmony_ci if (status != 0) { 316162306a36Sopenharmony_ci goto abort; 316262306a36Sopenharmony_ci } 316362306a36Sopenharmony_ci 316462306a36Sopenharmony_ci /* 316562306a36Sopenharmony_ci * Enable ECRC if possible 316662306a36Sopenharmony_ci */ 316762306a36Sopenharmony_ci myri10ge_enable_ecrc(mgp); 316862306a36Sopenharmony_ci 316962306a36Sopenharmony_ci /* 317062306a36Sopenharmony_ci * Run a DMA test which watches for unaligned completions and 317162306a36Sopenharmony_ci * aborts on the first one seen. 317262306a36Sopenharmony_ci */ 317362306a36Sopenharmony_ci 317462306a36Sopenharmony_ci status = myri10ge_dma_test(mgp, MXGEFW_CMD_UNALIGNED_TEST); 317562306a36Sopenharmony_ci if (status == 0) 317662306a36Sopenharmony_ci return; /* keep the aligned firmware */ 317762306a36Sopenharmony_ci 317862306a36Sopenharmony_ci if (status != -E2BIG) 317962306a36Sopenharmony_ci dev_warn(dev, "DMA test failed: %d\n", status); 318062306a36Sopenharmony_ci if (status == -ENOSYS) 318162306a36Sopenharmony_ci dev_warn(dev, "Falling back to ethp! " 318262306a36Sopenharmony_ci "Please install up to date fw\n"); 318362306a36Sopenharmony_ciabort: 318462306a36Sopenharmony_ci /* fall back to using the unaligned firmware */ 318562306a36Sopenharmony_ci mgp->tx_boundary = 2048; 318662306a36Sopenharmony_ci set_fw_name(mgp, myri10ge_fw_unaligned, false); 318762306a36Sopenharmony_ci} 318862306a36Sopenharmony_ci 318962306a36Sopenharmony_cistatic void myri10ge_select_firmware(struct myri10ge_priv *mgp) 319062306a36Sopenharmony_ci{ 319162306a36Sopenharmony_ci int overridden = 0; 319262306a36Sopenharmony_ci 319362306a36Sopenharmony_ci if (myri10ge_force_firmware == 0) { 319462306a36Sopenharmony_ci int link_width; 319562306a36Sopenharmony_ci u16 lnk; 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_ci pcie_capability_read_word(mgp->pdev, PCI_EXP_LNKSTA, &lnk); 319862306a36Sopenharmony_ci link_width = (lnk >> 4) & 0x3f; 319962306a36Sopenharmony_ci 320062306a36Sopenharmony_ci /* Check to see if Link is less than 8 or if the 320162306a36Sopenharmony_ci * upstream bridge is known to provide aligned 320262306a36Sopenharmony_ci * completions */ 320362306a36Sopenharmony_ci if (link_width < 8) { 320462306a36Sopenharmony_ci dev_info(&mgp->pdev->dev, "PCIE x%d Link\n", 320562306a36Sopenharmony_ci link_width); 320662306a36Sopenharmony_ci mgp->tx_boundary = 4096; 320762306a36Sopenharmony_ci set_fw_name(mgp, myri10ge_fw_aligned, false); 320862306a36Sopenharmony_ci } else { 320962306a36Sopenharmony_ci myri10ge_firmware_probe(mgp); 321062306a36Sopenharmony_ci } 321162306a36Sopenharmony_ci } else { 321262306a36Sopenharmony_ci if (myri10ge_force_firmware == 1) { 321362306a36Sopenharmony_ci dev_info(&mgp->pdev->dev, 321462306a36Sopenharmony_ci "Assuming aligned completions (forced)\n"); 321562306a36Sopenharmony_ci mgp->tx_boundary = 4096; 321662306a36Sopenharmony_ci set_fw_name(mgp, myri10ge_fw_aligned, false); 321762306a36Sopenharmony_ci } else { 321862306a36Sopenharmony_ci dev_info(&mgp->pdev->dev, 321962306a36Sopenharmony_ci "Assuming unaligned completions (forced)\n"); 322062306a36Sopenharmony_ci mgp->tx_boundary = 2048; 322162306a36Sopenharmony_ci set_fw_name(mgp, myri10ge_fw_unaligned, false); 322262306a36Sopenharmony_ci } 322362306a36Sopenharmony_ci } 322462306a36Sopenharmony_ci 322562306a36Sopenharmony_ci kernel_param_lock(THIS_MODULE); 322662306a36Sopenharmony_ci if (myri10ge_fw_name != NULL) { 322762306a36Sopenharmony_ci char *fw_name = kstrdup(myri10ge_fw_name, GFP_KERNEL); 322862306a36Sopenharmony_ci if (fw_name) { 322962306a36Sopenharmony_ci overridden = 1; 323062306a36Sopenharmony_ci set_fw_name(mgp, fw_name, true); 323162306a36Sopenharmony_ci } 323262306a36Sopenharmony_ci } 323362306a36Sopenharmony_ci kernel_param_unlock(THIS_MODULE); 323462306a36Sopenharmony_ci 323562306a36Sopenharmony_ci if (mgp->board_number < MYRI10GE_MAX_BOARDS && 323662306a36Sopenharmony_ci myri10ge_fw_names[mgp->board_number] != NULL && 323762306a36Sopenharmony_ci strlen(myri10ge_fw_names[mgp->board_number])) { 323862306a36Sopenharmony_ci set_fw_name(mgp, myri10ge_fw_names[mgp->board_number], false); 323962306a36Sopenharmony_ci overridden = 1; 324062306a36Sopenharmony_ci } 324162306a36Sopenharmony_ci if (overridden) 324262306a36Sopenharmony_ci dev_info(&mgp->pdev->dev, "overriding firmware to %s\n", 324362306a36Sopenharmony_ci mgp->fw_name); 324462306a36Sopenharmony_ci} 324562306a36Sopenharmony_ci 324662306a36Sopenharmony_cistatic void myri10ge_mask_surprise_down(struct pci_dev *pdev) 324762306a36Sopenharmony_ci{ 324862306a36Sopenharmony_ci struct pci_dev *bridge = pdev->bus->self; 324962306a36Sopenharmony_ci int cap; 325062306a36Sopenharmony_ci u32 mask; 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ci if (bridge == NULL) 325362306a36Sopenharmony_ci return; 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci cap = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ERR); 325662306a36Sopenharmony_ci if (cap) { 325762306a36Sopenharmony_ci /* a sram parity error can cause a surprise link 325862306a36Sopenharmony_ci * down; since we expect and can recover from sram 325962306a36Sopenharmony_ci * parity errors, mask surprise link down events */ 326062306a36Sopenharmony_ci pci_read_config_dword(bridge, cap + PCI_ERR_UNCOR_MASK, &mask); 326162306a36Sopenharmony_ci mask |= 0x20; 326262306a36Sopenharmony_ci pci_write_config_dword(bridge, cap + PCI_ERR_UNCOR_MASK, mask); 326362306a36Sopenharmony_ci } 326462306a36Sopenharmony_ci} 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_cistatic int __maybe_unused myri10ge_suspend(struct device *dev) 326762306a36Sopenharmony_ci{ 326862306a36Sopenharmony_ci struct myri10ge_priv *mgp; 326962306a36Sopenharmony_ci struct net_device *netdev; 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_ci mgp = dev_get_drvdata(dev); 327262306a36Sopenharmony_ci if (mgp == NULL) 327362306a36Sopenharmony_ci return -EINVAL; 327462306a36Sopenharmony_ci netdev = mgp->dev; 327562306a36Sopenharmony_ci 327662306a36Sopenharmony_ci netif_device_detach(netdev); 327762306a36Sopenharmony_ci if (netif_running(netdev)) { 327862306a36Sopenharmony_ci netdev_info(netdev, "closing\n"); 327962306a36Sopenharmony_ci rtnl_lock(); 328062306a36Sopenharmony_ci myri10ge_close(netdev); 328162306a36Sopenharmony_ci rtnl_unlock(); 328262306a36Sopenharmony_ci } 328362306a36Sopenharmony_ci myri10ge_dummy_rdma(mgp, 0); 328462306a36Sopenharmony_ci 328562306a36Sopenharmony_ci return 0; 328662306a36Sopenharmony_ci} 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_cistatic int __maybe_unused myri10ge_resume(struct device *dev) 328962306a36Sopenharmony_ci{ 329062306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev); 329162306a36Sopenharmony_ci struct myri10ge_priv *mgp; 329262306a36Sopenharmony_ci struct net_device *netdev; 329362306a36Sopenharmony_ci int status; 329462306a36Sopenharmony_ci u16 vendor; 329562306a36Sopenharmony_ci 329662306a36Sopenharmony_ci mgp = pci_get_drvdata(pdev); 329762306a36Sopenharmony_ci if (mgp == NULL) 329862306a36Sopenharmony_ci return -EINVAL; 329962306a36Sopenharmony_ci netdev = mgp->dev; 330062306a36Sopenharmony_ci msleep(5); /* give card time to respond */ 330162306a36Sopenharmony_ci pci_read_config_word(mgp->pdev, PCI_VENDOR_ID, &vendor); 330262306a36Sopenharmony_ci if (vendor == 0xffff) { 330362306a36Sopenharmony_ci netdev_err(mgp->dev, "device disappeared!\n"); 330462306a36Sopenharmony_ci return -EIO; 330562306a36Sopenharmony_ci } 330662306a36Sopenharmony_ci 330762306a36Sopenharmony_ci myri10ge_reset(mgp); 330862306a36Sopenharmony_ci myri10ge_dummy_rdma(mgp, 1); 330962306a36Sopenharmony_ci 331062306a36Sopenharmony_ci if (netif_running(netdev)) { 331162306a36Sopenharmony_ci rtnl_lock(); 331262306a36Sopenharmony_ci status = myri10ge_open(netdev); 331362306a36Sopenharmony_ci rtnl_unlock(); 331462306a36Sopenharmony_ci if (status != 0) 331562306a36Sopenharmony_ci goto abort_with_enabled; 331662306a36Sopenharmony_ci 331762306a36Sopenharmony_ci } 331862306a36Sopenharmony_ci netif_device_attach(netdev); 331962306a36Sopenharmony_ci 332062306a36Sopenharmony_ci return 0; 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ciabort_with_enabled: 332362306a36Sopenharmony_ci return -EIO; 332462306a36Sopenharmony_ci} 332562306a36Sopenharmony_ci 332662306a36Sopenharmony_cistatic u32 myri10ge_read_reboot(struct myri10ge_priv *mgp) 332762306a36Sopenharmony_ci{ 332862306a36Sopenharmony_ci struct pci_dev *pdev = mgp->pdev; 332962306a36Sopenharmony_ci int vs = mgp->vendor_specific_offset; 333062306a36Sopenharmony_ci u32 reboot; 333162306a36Sopenharmony_ci 333262306a36Sopenharmony_ci /*enter read32 mode */ 333362306a36Sopenharmony_ci pci_write_config_byte(pdev, vs + 0x10, 0x3); 333462306a36Sopenharmony_ci 333562306a36Sopenharmony_ci /*read REBOOT_STATUS (0xfffffff0) */ 333662306a36Sopenharmony_ci pci_write_config_dword(pdev, vs + 0x18, 0xfffffff0); 333762306a36Sopenharmony_ci pci_read_config_dword(pdev, vs + 0x14, &reboot); 333862306a36Sopenharmony_ci return reboot; 333962306a36Sopenharmony_ci} 334062306a36Sopenharmony_ci 334162306a36Sopenharmony_cistatic void 334262306a36Sopenharmony_cimyri10ge_check_slice(struct myri10ge_slice_state *ss, int *reset_needed, 334362306a36Sopenharmony_ci int *busy_slice_cnt, u32 rx_pause_cnt) 334462306a36Sopenharmony_ci{ 334562306a36Sopenharmony_ci struct myri10ge_priv *mgp = ss->mgp; 334662306a36Sopenharmony_ci int slice = ss - mgp->ss; 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci if (ss->tx.req != ss->tx.done && 334962306a36Sopenharmony_ci ss->tx.done == ss->watchdog_tx_done && 335062306a36Sopenharmony_ci ss->watchdog_tx_req != ss->watchdog_tx_done) { 335162306a36Sopenharmony_ci /* nic seems like it might be stuck.. */ 335262306a36Sopenharmony_ci if (rx_pause_cnt != mgp->watchdog_pause) { 335362306a36Sopenharmony_ci if (net_ratelimit()) 335462306a36Sopenharmony_ci netdev_warn(mgp->dev, "slice %d: TX paused, " 335562306a36Sopenharmony_ci "check link partner\n", slice); 335662306a36Sopenharmony_ci } else { 335762306a36Sopenharmony_ci netdev_warn(mgp->dev, 335862306a36Sopenharmony_ci "slice %d: TX stuck %d %d %d %d %d %d\n", 335962306a36Sopenharmony_ci slice, ss->tx.queue_active, ss->tx.req, 336062306a36Sopenharmony_ci ss->tx.done, ss->tx.pkt_start, 336162306a36Sopenharmony_ci ss->tx.pkt_done, 336262306a36Sopenharmony_ci (int)ntohl(mgp->ss[slice].fw_stats-> 336362306a36Sopenharmony_ci send_done_count)); 336462306a36Sopenharmony_ci *reset_needed = 1; 336562306a36Sopenharmony_ci ss->stuck = 1; 336662306a36Sopenharmony_ci } 336762306a36Sopenharmony_ci } 336862306a36Sopenharmony_ci if (ss->watchdog_tx_done != ss->tx.done || 336962306a36Sopenharmony_ci ss->watchdog_rx_done != ss->rx_done.cnt) { 337062306a36Sopenharmony_ci *busy_slice_cnt += 1; 337162306a36Sopenharmony_ci } 337262306a36Sopenharmony_ci ss->watchdog_tx_done = ss->tx.done; 337362306a36Sopenharmony_ci ss->watchdog_tx_req = ss->tx.req; 337462306a36Sopenharmony_ci ss->watchdog_rx_done = ss->rx_done.cnt; 337562306a36Sopenharmony_ci} 337662306a36Sopenharmony_ci 337762306a36Sopenharmony_ci/* 337862306a36Sopenharmony_ci * This watchdog is used to check whether the board has suffered 337962306a36Sopenharmony_ci * from a parity error and needs to be recovered. 338062306a36Sopenharmony_ci */ 338162306a36Sopenharmony_cistatic void myri10ge_watchdog(struct work_struct *work) 338262306a36Sopenharmony_ci{ 338362306a36Sopenharmony_ci struct myri10ge_priv *mgp = 338462306a36Sopenharmony_ci container_of(work, struct myri10ge_priv, watchdog_work); 338562306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 338662306a36Sopenharmony_ci u32 reboot, rx_pause_cnt; 338762306a36Sopenharmony_ci int status, rebooted; 338862306a36Sopenharmony_ci int i; 338962306a36Sopenharmony_ci int reset_needed = 0; 339062306a36Sopenharmony_ci int busy_slice_cnt = 0; 339162306a36Sopenharmony_ci u16 cmd, vendor; 339262306a36Sopenharmony_ci 339362306a36Sopenharmony_ci mgp->watchdog_resets++; 339462306a36Sopenharmony_ci pci_read_config_word(mgp->pdev, PCI_COMMAND, &cmd); 339562306a36Sopenharmony_ci rebooted = 0; 339662306a36Sopenharmony_ci if ((cmd & PCI_COMMAND_MASTER) == 0) { 339762306a36Sopenharmony_ci /* Bus master DMA disabled? Check to see 339862306a36Sopenharmony_ci * if the card rebooted due to a parity error 339962306a36Sopenharmony_ci * For now, just report it */ 340062306a36Sopenharmony_ci reboot = myri10ge_read_reboot(mgp); 340162306a36Sopenharmony_ci netdev_err(mgp->dev, "NIC rebooted (0x%x),%s resetting\n", 340262306a36Sopenharmony_ci reboot, myri10ge_reset_recover ? "" : " not"); 340362306a36Sopenharmony_ci if (myri10ge_reset_recover == 0) 340462306a36Sopenharmony_ci return; 340562306a36Sopenharmony_ci rtnl_lock(); 340662306a36Sopenharmony_ci mgp->rebooted = 1; 340762306a36Sopenharmony_ci rebooted = 1; 340862306a36Sopenharmony_ci myri10ge_close(mgp->dev); 340962306a36Sopenharmony_ci myri10ge_reset_recover--; 341062306a36Sopenharmony_ci mgp->rebooted = 0; 341162306a36Sopenharmony_ci /* 341262306a36Sopenharmony_ci * A rebooted nic will come back with config space as 341362306a36Sopenharmony_ci * it was after power was applied to PCIe bus. 341462306a36Sopenharmony_ci * Attempt to restore config space which was saved 341562306a36Sopenharmony_ci * when the driver was loaded, or the last time the 341662306a36Sopenharmony_ci * nic was resumed from power saving mode. 341762306a36Sopenharmony_ci */ 341862306a36Sopenharmony_ci pci_restore_state(mgp->pdev); 341962306a36Sopenharmony_ci 342062306a36Sopenharmony_ci /* save state again for accounting reasons */ 342162306a36Sopenharmony_ci pci_save_state(mgp->pdev); 342262306a36Sopenharmony_ci 342362306a36Sopenharmony_ci } else { 342462306a36Sopenharmony_ci /* if we get back -1's from our slot, perhaps somebody 342562306a36Sopenharmony_ci * powered off our card. Don't try to reset it in 342662306a36Sopenharmony_ci * this case */ 342762306a36Sopenharmony_ci if (cmd == 0xffff) { 342862306a36Sopenharmony_ci pci_read_config_word(mgp->pdev, PCI_VENDOR_ID, &vendor); 342962306a36Sopenharmony_ci if (vendor == 0xffff) { 343062306a36Sopenharmony_ci netdev_err(mgp->dev, "device disappeared!\n"); 343162306a36Sopenharmony_ci return; 343262306a36Sopenharmony_ci } 343362306a36Sopenharmony_ci } 343462306a36Sopenharmony_ci /* Perhaps it is a software error. See if stuck slice 343562306a36Sopenharmony_ci * has recovered, reset if not */ 343662306a36Sopenharmony_ci rx_pause_cnt = ntohl(mgp->ss[0].fw_stats->dropped_pause); 343762306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 343862306a36Sopenharmony_ci ss = mgp->ss; 343962306a36Sopenharmony_ci if (ss->stuck) { 344062306a36Sopenharmony_ci myri10ge_check_slice(ss, &reset_needed, 344162306a36Sopenharmony_ci &busy_slice_cnt, 344262306a36Sopenharmony_ci rx_pause_cnt); 344362306a36Sopenharmony_ci ss->stuck = 0; 344462306a36Sopenharmony_ci } 344562306a36Sopenharmony_ci } 344662306a36Sopenharmony_ci if (!reset_needed) { 344762306a36Sopenharmony_ci netdev_dbg(mgp->dev, "not resetting\n"); 344862306a36Sopenharmony_ci return; 344962306a36Sopenharmony_ci } 345062306a36Sopenharmony_ci 345162306a36Sopenharmony_ci netdev_err(mgp->dev, "device timeout, resetting\n"); 345262306a36Sopenharmony_ci } 345362306a36Sopenharmony_ci 345462306a36Sopenharmony_ci if (!rebooted) { 345562306a36Sopenharmony_ci rtnl_lock(); 345662306a36Sopenharmony_ci myri10ge_close(mgp->dev); 345762306a36Sopenharmony_ci } 345862306a36Sopenharmony_ci status = myri10ge_load_firmware(mgp, 1); 345962306a36Sopenharmony_ci if (status != 0) 346062306a36Sopenharmony_ci netdev_err(mgp->dev, "failed to load firmware\n"); 346162306a36Sopenharmony_ci else 346262306a36Sopenharmony_ci myri10ge_open(mgp->dev); 346362306a36Sopenharmony_ci rtnl_unlock(); 346462306a36Sopenharmony_ci} 346562306a36Sopenharmony_ci 346662306a36Sopenharmony_ci/* 346762306a36Sopenharmony_ci * We use our own timer routine rather than relying upon 346862306a36Sopenharmony_ci * netdev->tx_timeout because we have a very large hardware transmit 346962306a36Sopenharmony_ci * queue. Due to the large queue, the netdev->tx_timeout function 347062306a36Sopenharmony_ci * cannot detect a NIC with a parity error in a timely fashion if the 347162306a36Sopenharmony_ci * NIC is lightly loaded. 347262306a36Sopenharmony_ci */ 347362306a36Sopenharmony_cistatic void myri10ge_watchdog_timer(struct timer_list *t) 347462306a36Sopenharmony_ci{ 347562306a36Sopenharmony_ci struct myri10ge_priv *mgp; 347662306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 347762306a36Sopenharmony_ci int i, reset_needed, busy_slice_cnt; 347862306a36Sopenharmony_ci u32 rx_pause_cnt; 347962306a36Sopenharmony_ci u16 cmd; 348062306a36Sopenharmony_ci 348162306a36Sopenharmony_ci mgp = from_timer(mgp, t, watchdog_timer); 348262306a36Sopenharmony_ci 348362306a36Sopenharmony_ci rx_pause_cnt = ntohl(mgp->ss[0].fw_stats->dropped_pause); 348462306a36Sopenharmony_ci busy_slice_cnt = 0; 348562306a36Sopenharmony_ci for (i = 0, reset_needed = 0; 348662306a36Sopenharmony_ci i < mgp->num_slices && reset_needed == 0; ++i) { 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_ci ss = &mgp->ss[i]; 348962306a36Sopenharmony_ci if (ss->rx_small.watchdog_needed) { 349062306a36Sopenharmony_ci myri10ge_alloc_rx_pages(mgp, &ss->rx_small, 349162306a36Sopenharmony_ci mgp->small_bytes + MXGEFW_PAD, 349262306a36Sopenharmony_ci 1); 349362306a36Sopenharmony_ci if (ss->rx_small.fill_cnt - ss->rx_small.cnt >= 349462306a36Sopenharmony_ci myri10ge_fill_thresh) 349562306a36Sopenharmony_ci ss->rx_small.watchdog_needed = 0; 349662306a36Sopenharmony_ci } 349762306a36Sopenharmony_ci if (ss->rx_big.watchdog_needed) { 349862306a36Sopenharmony_ci myri10ge_alloc_rx_pages(mgp, &ss->rx_big, 349962306a36Sopenharmony_ci mgp->big_bytes, 1); 350062306a36Sopenharmony_ci if (ss->rx_big.fill_cnt - ss->rx_big.cnt >= 350162306a36Sopenharmony_ci myri10ge_fill_thresh) 350262306a36Sopenharmony_ci ss->rx_big.watchdog_needed = 0; 350362306a36Sopenharmony_ci } 350462306a36Sopenharmony_ci myri10ge_check_slice(ss, &reset_needed, &busy_slice_cnt, 350562306a36Sopenharmony_ci rx_pause_cnt); 350662306a36Sopenharmony_ci } 350762306a36Sopenharmony_ci /* if we've sent or received no traffic, poll the NIC to 350862306a36Sopenharmony_ci * ensure it is still there. Otherwise, we risk not noticing 350962306a36Sopenharmony_ci * an error in a timely fashion */ 351062306a36Sopenharmony_ci if (busy_slice_cnt == 0) { 351162306a36Sopenharmony_ci pci_read_config_word(mgp->pdev, PCI_COMMAND, &cmd); 351262306a36Sopenharmony_ci if ((cmd & PCI_COMMAND_MASTER) == 0) { 351362306a36Sopenharmony_ci reset_needed = 1; 351462306a36Sopenharmony_ci } 351562306a36Sopenharmony_ci } 351662306a36Sopenharmony_ci mgp->watchdog_pause = rx_pause_cnt; 351762306a36Sopenharmony_ci 351862306a36Sopenharmony_ci if (reset_needed) { 351962306a36Sopenharmony_ci schedule_work(&mgp->watchdog_work); 352062306a36Sopenharmony_ci } else { 352162306a36Sopenharmony_ci /* rearm timer */ 352262306a36Sopenharmony_ci mod_timer(&mgp->watchdog_timer, 352362306a36Sopenharmony_ci jiffies + myri10ge_watchdog_timeout * HZ); 352462306a36Sopenharmony_ci } 352562306a36Sopenharmony_ci} 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_cistatic void myri10ge_free_slices(struct myri10ge_priv *mgp) 352862306a36Sopenharmony_ci{ 352962306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 353062306a36Sopenharmony_ci struct pci_dev *pdev = mgp->pdev; 353162306a36Sopenharmony_ci size_t bytes; 353262306a36Sopenharmony_ci int i; 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci if (mgp->ss == NULL) 353562306a36Sopenharmony_ci return; 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 353862306a36Sopenharmony_ci ss = &mgp->ss[i]; 353962306a36Sopenharmony_ci if (ss->rx_done.entry != NULL) { 354062306a36Sopenharmony_ci bytes = mgp->max_intr_slots * 354162306a36Sopenharmony_ci sizeof(*ss->rx_done.entry); 354262306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, bytes, 354362306a36Sopenharmony_ci ss->rx_done.entry, ss->rx_done.bus); 354462306a36Sopenharmony_ci ss->rx_done.entry = NULL; 354562306a36Sopenharmony_ci } 354662306a36Sopenharmony_ci if (ss->fw_stats != NULL) { 354762306a36Sopenharmony_ci bytes = sizeof(*ss->fw_stats); 354862306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, bytes, 354962306a36Sopenharmony_ci ss->fw_stats, ss->fw_stats_bus); 355062306a36Sopenharmony_ci ss->fw_stats = NULL; 355162306a36Sopenharmony_ci } 355262306a36Sopenharmony_ci __netif_napi_del(&ss->napi); 355362306a36Sopenharmony_ci } 355462306a36Sopenharmony_ci /* Wait till napi structs are no longer used, and then free ss. */ 355562306a36Sopenharmony_ci synchronize_net(); 355662306a36Sopenharmony_ci kfree(mgp->ss); 355762306a36Sopenharmony_ci mgp->ss = NULL; 355862306a36Sopenharmony_ci} 355962306a36Sopenharmony_ci 356062306a36Sopenharmony_cistatic int myri10ge_alloc_slices(struct myri10ge_priv *mgp) 356162306a36Sopenharmony_ci{ 356262306a36Sopenharmony_ci struct myri10ge_slice_state *ss; 356362306a36Sopenharmony_ci struct pci_dev *pdev = mgp->pdev; 356462306a36Sopenharmony_ci size_t bytes; 356562306a36Sopenharmony_ci int i; 356662306a36Sopenharmony_ci 356762306a36Sopenharmony_ci bytes = sizeof(*mgp->ss) * mgp->num_slices; 356862306a36Sopenharmony_ci mgp->ss = kzalloc(bytes, GFP_KERNEL); 356962306a36Sopenharmony_ci if (mgp->ss == NULL) { 357062306a36Sopenharmony_ci return -ENOMEM; 357162306a36Sopenharmony_ci } 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 357462306a36Sopenharmony_ci ss = &mgp->ss[i]; 357562306a36Sopenharmony_ci bytes = mgp->max_intr_slots * sizeof(*ss->rx_done.entry); 357662306a36Sopenharmony_ci ss->rx_done.entry = dma_alloc_coherent(&pdev->dev, bytes, 357762306a36Sopenharmony_ci &ss->rx_done.bus, 357862306a36Sopenharmony_ci GFP_KERNEL); 357962306a36Sopenharmony_ci if (ss->rx_done.entry == NULL) 358062306a36Sopenharmony_ci goto abort; 358162306a36Sopenharmony_ci bytes = sizeof(*ss->fw_stats); 358262306a36Sopenharmony_ci ss->fw_stats = dma_alloc_coherent(&pdev->dev, bytes, 358362306a36Sopenharmony_ci &ss->fw_stats_bus, 358462306a36Sopenharmony_ci GFP_KERNEL); 358562306a36Sopenharmony_ci if (ss->fw_stats == NULL) 358662306a36Sopenharmony_ci goto abort; 358762306a36Sopenharmony_ci ss->mgp = mgp; 358862306a36Sopenharmony_ci ss->dev = mgp->dev; 358962306a36Sopenharmony_ci netif_napi_add_weight(ss->dev, &ss->napi, myri10ge_poll, 359062306a36Sopenharmony_ci myri10ge_napi_weight); 359162306a36Sopenharmony_ci } 359262306a36Sopenharmony_ci return 0; 359362306a36Sopenharmony_ciabort: 359462306a36Sopenharmony_ci myri10ge_free_slices(mgp); 359562306a36Sopenharmony_ci return -ENOMEM; 359662306a36Sopenharmony_ci} 359762306a36Sopenharmony_ci 359862306a36Sopenharmony_ci/* 359962306a36Sopenharmony_ci * This function determines the number of slices supported. 360062306a36Sopenharmony_ci * The number slices is the minimum of the number of CPUS, 360162306a36Sopenharmony_ci * the number of MSI-X irqs supported, the number of slices 360262306a36Sopenharmony_ci * supported by the firmware 360362306a36Sopenharmony_ci */ 360462306a36Sopenharmony_cistatic void myri10ge_probe_slices(struct myri10ge_priv *mgp) 360562306a36Sopenharmony_ci{ 360662306a36Sopenharmony_ci struct myri10ge_cmd cmd; 360762306a36Sopenharmony_ci struct pci_dev *pdev = mgp->pdev; 360862306a36Sopenharmony_ci char *old_fw; 360962306a36Sopenharmony_ci bool old_allocated; 361062306a36Sopenharmony_ci int i, status, ncpus; 361162306a36Sopenharmony_ci 361262306a36Sopenharmony_ci mgp->num_slices = 1; 361362306a36Sopenharmony_ci ncpus = netif_get_num_default_rss_queues(); 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_ci if (myri10ge_max_slices == 1 || !pdev->msix_cap || 361662306a36Sopenharmony_ci (myri10ge_max_slices == -1 && ncpus < 2)) 361762306a36Sopenharmony_ci return; 361862306a36Sopenharmony_ci 361962306a36Sopenharmony_ci /* try to load the slice aware rss firmware */ 362062306a36Sopenharmony_ci old_fw = mgp->fw_name; 362162306a36Sopenharmony_ci old_allocated = mgp->fw_name_allocated; 362262306a36Sopenharmony_ci /* don't free old_fw if we override it. */ 362362306a36Sopenharmony_ci mgp->fw_name_allocated = false; 362462306a36Sopenharmony_ci 362562306a36Sopenharmony_ci if (myri10ge_fw_name != NULL) { 362662306a36Sopenharmony_ci dev_info(&mgp->pdev->dev, "overriding rss firmware to %s\n", 362762306a36Sopenharmony_ci myri10ge_fw_name); 362862306a36Sopenharmony_ci set_fw_name(mgp, myri10ge_fw_name, false); 362962306a36Sopenharmony_ci } else if (old_fw == myri10ge_fw_aligned) 363062306a36Sopenharmony_ci set_fw_name(mgp, myri10ge_fw_rss_aligned, false); 363162306a36Sopenharmony_ci else 363262306a36Sopenharmony_ci set_fw_name(mgp, myri10ge_fw_rss_unaligned, false); 363362306a36Sopenharmony_ci status = myri10ge_load_firmware(mgp, 0); 363462306a36Sopenharmony_ci if (status != 0) { 363562306a36Sopenharmony_ci dev_info(&pdev->dev, "Rss firmware not found\n"); 363662306a36Sopenharmony_ci if (old_allocated) 363762306a36Sopenharmony_ci kfree(old_fw); 363862306a36Sopenharmony_ci return; 363962306a36Sopenharmony_ci } 364062306a36Sopenharmony_ci 364162306a36Sopenharmony_ci /* hit the board with a reset to ensure it is alive */ 364262306a36Sopenharmony_ci memset(&cmd, 0, sizeof(cmd)); 364362306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_RESET, &cmd, 0); 364462306a36Sopenharmony_ci if (status != 0) { 364562306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, "failed reset\n"); 364662306a36Sopenharmony_ci goto abort_with_fw; 364762306a36Sopenharmony_ci } 364862306a36Sopenharmony_ci 364962306a36Sopenharmony_ci mgp->max_intr_slots = cmd.data0 / sizeof(struct mcp_slot); 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci /* tell it the size of the interrupt queues */ 365262306a36Sopenharmony_ci cmd.data0 = mgp->max_intr_slots * sizeof(struct mcp_slot); 365362306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_SIZE, &cmd, 0); 365462306a36Sopenharmony_ci if (status != 0) { 365562306a36Sopenharmony_ci dev_err(&mgp->pdev->dev, "failed MXGEFW_CMD_SET_INTRQ_SIZE\n"); 365662306a36Sopenharmony_ci goto abort_with_fw; 365762306a36Sopenharmony_ci } 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_ci /* ask the maximum number of slices it supports */ 366062306a36Sopenharmony_ci status = myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_MAX_RSS_QUEUES, &cmd, 0); 366162306a36Sopenharmony_ci if (status != 0) 366262306a36Sopenharmony_ci goto abort_with_fw; 366362306a36Sopenharmony_ci else 366462306a36Sopenharmony_ci mgp->num_slices = cmd.data0; 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci /* Only allow multiple slices if MSI-X is usable */ 366762306a36Sopenharmony_ci if (!myri10ge_msi) { 366862306a36Sopenharmony_ci goto abort_with_fw; 366962306a36Sopenharmony_ci } 367062306a36Sopenharmony_ci 367162306a36Sopenharmony_ci /* if the admin did not specify a limit to how many 367262306a36Sopenharmony_ci * slices we should use, cap it automatically to the 367362306a36Sopenharmony_ci * number of CPUs currently online */ 367462306a36Sopenharmony_ci if (myri10ge_max_slices == -1) 367562306a36Sopenharmony_ci myri10ge_max_slices = ncpus; 367662306a36Sopenharmony_ci 367762306a36Sopenharmony_ci if (mgp->num_slices > myri10ge_max_slices) 367862306a36Sopenharmony_ci mgp->num_slices = myri10ge_max_slices; 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_ci /* Now try to allocate as many MSI-X vectors as we have 368162306a36Sopenharmony_ci * slices. We give up on MSI-X if we can only get a single 368262306a36Sopenharmony_ci * vector. */ 368362306a36Sopenharmony_ci 368462306a36Sopenharmony_ci mgp->msix_vectors = kcalloc(mgp->num_slices, sizeof(*mgp->msix_vectors), 368562306a36Sopenharmony_ci GFP_KERNEL); 368662306a36Sopenharmony_ci if (mgp->msix_vectors == NULL) 368762306a36Sopenharmony_ci goto no_msix; 368862306a36Sopenharmony_ci for (i = 0; i < mgp->num_slices; i++) { 368962306a36Sopenharmony_ci mgp->msix_vectors[i].entry = i; 369062306a36Sopenharmony_ci } 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci while (mgp->num_slices > 1) { 369362306a36Sopenharmony_ci mgp->num_slices = rounddown_pow_of_two(mgp->num_slices); 369462306a36Sopenharmony_ci if (mgp->num_slices == 1) 369562306a36Sopenharmony_ci goto no_msix; 369662306a36Sopenharmony_ci status = pci_enable_msix_range(pdev, 369762306a36Sopenharmony_ci mgp->msix_vectors, 369862306a36Sopenharmony_ci mgp->num_slices, 369962306a36Sopenharmony_ci mgp->num_slices); 370062306a36Sopenharmony_ci if (status < 0) 370162306a36Sopenharmony_ci goto no_msix; 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci pci_disable_msix(pdev); 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci if (status == mgp->num_slices) { 370662306a36Sopenharmony_ci if (old_allocated) 370762306a36Sopenharmony_ci kfree(old_fw); 370862306a36Sopenharmony_ci return; 370962306a36Sopenharmony_ci } else { 371062306a36Sopenharmony_ci mgp->num_slices = status; 371162306a36Sopenharmony_ci } 371262306a36Sopenharmony_ci } 371362306a36Sopenharmony_ci 371462306a36Sopenharmony_cino_msix: 371562306a36Sopenharmony_ci if (mgp->msix_vectors != NULL) { 371662306a36Sopenharmony_ci kfree(mgp->msix_vectors); 371762306a36Sopenharmony_ci mgp->msix_vectors = NULL; 371862306a36Sopenharmony_ci } 371962306a36Sopenharmony_ci 372062306a36Sopenharmony_ciabort_with_fw: 372162306a36Sopenharmony_ci mgp->num_slices = 1; 372262306a36Sopenharmony_ci set_fw_name(mgp, old_fw, old_allocated); 372362306a36Sopenharmony_ci myri10ge_load_firmware(mgp, 0); 372462306a36Sopenharmony_ci} 372562306a36Sopenharmony_ci 372662306a36Sopenharmony_cistatic const struct net_device_ops myri10ge_netdev_ops = { 372762306a36Sopenharmony_ci .ndo_open = myri10ge_open, 372862306a36Sopenharmony_ci .ndo_stop = myri10ge_close, 372962306a36Sopenharmony_ci .ndo_start_xmit = myri10ge_xmit, 373062306a36Sopenharmony_ci .ndo_get_stats64 = myri10ge_get_stats, 373162306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 373262306a36Sopenharmony_ci .ndo_change_mtu = myri10ge_change_mtu, 373362306a36Sopenharmony_ci .ndo_set_rx_mode = myri10ge_set_multicast_list, 373462306a36Sopenharmony_ci .ndo_set_mac_address = myri10ge_set_mac_address, 373562306a36Sopenharmony_ci}; 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_cistatic int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 373862306a36Sopenharmony_ci{ 373962306a36Sopenharmony_ci struct net_device *netdev; 374062306a36Sopenharmony_ci struct myri10ge_priv *mgp; 374162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 374262306a36Sopenharmony_ci int status = -ENXIO; 374362306a36Sopenharmony_ci unsigned hdr_offset, ss_offset; 374462306a36Sopenharmony_ci static int board_number; 374562306a36Sopenharmony_ci 374662306a36Sopenharmony_ci netdev = alloc_etherdev_mq(sizeof(*mgp), MYRI10GE_MAX_SLICES); 374762306a36Sopenharmony_ci if (netdev == NULL) 374862306a36Sopenharmony_ci return -ENOMEM; 374962306a36Sopenharmony_ci 375062306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 375162306a36Sopenharmony_ci 375262306a36Sopenharmony_ci mgp = netdev_priv(netdev); 375362306a36Sopenharmony_ci mgp->dev = netdev; 375462306a36Sopenharmony_ci mgp->pdev = pdev; 375562306a36Sopenharmony_ci mgp->pause = myri10ge_flow_control; 375662306a36Sopenharmony_ci mgp->intr_coal_delay = myri10ge_intr_coal_delay; 375762306a36Sopenharmony_ci mgp->msg_enable = netif_msg_init(myri10ge_debug, MYRI10GE_MSG_DEFAULT); 375862306a36Sopenharmony_ci mgp->board_number = board_number; 375962306a36Sopenharmony_ci init_waitqueue_head(&mgp->down_wq); 376062306a36Sopenharmony_ci 376162306a36Sopenharmony_ci if (pci_enable_device(pdev)) { 376262306a36Sopenharmony_ci dev_err(&pdev->dev, "pci_enable_device call failed\n"); 376362306a36Sopenharmony_ci status = -ENODEV; 376462306a36Sopenharmony_ci goto abort_with_netdev; 376562306a36Sopenharmony_ci } 376662306a36Sopenharmony_ci 376762306a36Sopenharmony_ci /* Find the vendor-specific cap so we can check 376862306a36Sopenharmony_ci * the reboot register later on */ 376962306a36Sopenharmony_ci mgp->vendor_specific_offset 377062306a36Sopenharmony_ci = pci_find_capability(pdev, PCI_CAP_ID_VNDR); 377162306a36Sopenharmony_ci 377262306a36Sopenharmony_ci /* Set our max read request to 4KB */ 377362306a36Sopenharmony_ci status = pcie_set_readrq(pdev, 4096); 377462306a36Sopenharmony_ci if (status != 0) { 377562306a36Sopenharmony_ci dev_err(&pdev->dev, "Error %d writing PCI_EXP_DEVCTL\n", 377662306a36Sopenharmony_ci status); 377762306a36Sopenharmony_ci goto abort_with_enabled; 377862306a36Sopenharmony_ci } 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci myri10ge_mask_surprise_down(pdev); 378162306a36Sopenharmony_ci pci_set_master(pdev); 378262306a36Sopenharmony_ci status = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 378362306a36Sopenharmony_ci if (status != 0) { 378462306a36Sopenharmony_ci dev_err(&pdev->dev, "Error %d setting DMA mask\n", status); 378562306a36Sopenharmony_ci goto abort_with_enabled; 378662306a36Sopenharmony_ci } 378762306a36Sopenharmony_ci mgp->cmd = dma_alloc_coherent(&pdev->dev, sizeof(*mgp->cmd), 378862306a36Sopenharmony_ci &mgp->cmd_bus, GFP_KERNEL); 378962306a36Sopenharmony_ci if (!mgp->cmd) { 379062306a36Sopenharmony_ci status = -ENOMEM; 379162306a36Sopenharmony_ci goto abort_with_enabled; 379262306a36Sopenharmony_ci } 379362306a36Sopenharmony_ci 379462306a36Sopenharmony_ci mgp->board_span = pci_resource_len(pdev, 0); 379562306a36Sopenharmony_ci mgp->iomem_base = pci_resource_start(pdev, 0); 379662306a36Sopenharmony_ci mgp->wc_cookie = arch_phys_wc_add(mgp->iomem_base, mgp->board_span); 379762306a36Sopenharmony_ci mgp->sram = ioremap_wc(mgp->iomem_base, mgp->board_span); 379862306a36Sopenharmony_ci if (mgp->sram == NULL) { 379962306a36Sopenharmony_ci dev_err(&pdev->dev, "ioremap failed for %ld bytes at 0x%lx\n", 380062306a36Sopenharmony_ci mgp->board_span, mgp->iomem_base); 380162306a36Sopenharmony_ci status = -ENXIO; 380262306a36Sopenharmony_ci goto abort_with_mtrr; 380362306a36Sopenharmony_ci } 380462306a36Sopenharmony_ci hdr_offset = 380562306a36Sopenharmony_ci swab32(readl(mgp->sram + MCP_HEADER_PTR_OFFSET)) & 0xffffc; 380662306a36Sopenharmony_ci ss_offset = hdr_offset + offsetof(struct mcp_gen_header, string_specs); 380762306a36Sopenharmony_ci mgp->sram_size = swab32(readl(mgp->sram + ss_offset)); 380862306a36Sopenharmony_ci if (mgp->sram_size > mgp->board_span || 380962306a36Sopenharmony_ci mgp->sram_size <= MYRI10GE_FW_OFFSET) { 381062306a36Sopenharmony_ci dev_err(&pdev->dev, 381162306a36Sopenharmony_ci "invalid sram_size %dB or board span %ldB\n", 381262306a36Sopenharmony_ci mgp->sram_size, mgp->board_span); 381362306a36Sopenharmony_ci status = -EINVAL; 381462306a36Sopenharmony_ci goto abort_with_ioremap; 381562306a36Sopenharmony_ci } 381662306a36Sopenharmony_ci memcpy_fromio(mgp->eeprom_strings, 381762306a36Sopenharmony_ci mgp->sram + mgp->sram_size, MYRI10GE_EEPROM_STRINGS_SIZE); 381862306a36Sopenharmony_ci memset(mgp->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE - 2, 0, 2); 381962306a36Sopenharmony_ci status = myri10ge_read_mac_addr(mgp); 382062306a36Sopenharmony_ci if (status) 382162306a36Sopenharmony_ci goto abort_with_ioremap; 382262306a36Sopenharmony_ci 382362306a36Sopenharmony_ci eth_hw_addr_set(netdev, mgp->mac_addr); 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci myri10ge_select_firmware(mgp); 382662306a36Sopenharmony_ci 382762306a36Sopenharmony_ci status = myri10ge_load_firmware(mgp, 1); 382862306a36Sopenharmony_ci if (status != 0) { 382962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to load firmware\n"); 383062306a36Sopenharmony_ci goto abort_with_ioremap; 383162306a36Sopenharmony_ci } 383262306a36Sopenharmony_ci myri10ge_probe_slices(mgp); 383362306a36Sopenharmony_ci status = myri10ge_alloc_slices(mgp); 383462306a36Sopenharmony_ci if (status != 0) { 383562306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to alloc slice state\n"); 383662306a36Sopenharmony_ci goto abort_with_firmware; 383762306a36Sopenharmony_ci } 383862306a36Sopenharmony_ci netif_set_real_num_tx_queues(netdev, mgp->num_slices); 383962306a36Sopenharmony_ci netif_set_real_num_rx_queues(netdev, mgp->num_slices); 384062306a36Sopenharmony_ci status = myri10ge_reset(mgp); 384162306a36Sopenharmony_ci if (status != 0) { 384262306a36Sopenharmony_ci dev_err(&pdev->dev, "failed reset\n"); 384362306a36Sopenharmony_ci goto abort_with_slices; 384462306a36Sopenharmony_ci } 384562306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 384662306a36Sopenharmony_ci myri10ge_setup_dca(mgp); 384762306a36Sopenharmony_ci#endif 384862306a36Sopenharmony_ci pci_set_drvdata(pdev, mgp); 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci /* MTU range: 68 - 9000 */ 385162306a36Sopenharmony_ci netdev->min_mtu = ETH_MIN_MTU; 385262306a36Sopenharmony_ci netdev->max_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN; 385362306a36Sopenharmony_ci 385462306a36Sopenharmony_ci if (myri10ge_initial_mtu > netdev->max_mtu) 385562306a36Sopenharmony_ci myri10ge_initial_mtu = netdev->max_mtu; 385662306a36Sopenharmony_ci if (myri10ge_initial_mtu < netdev->min_mtu) 385762306a36Sopenharmony_ci myri10ge_initial_mtu = netdev->min_mtu; 385862306a36Sopenharmony_ci 385962306a36Sopenharmony_ci netdev->mtu = myri10ge_initial_mtu; 386062306a36Sopenharmony_ci 386162306a36Sopenharmony_ci netdev->netdev_ops = &myri10ge_netdev_ops; 386262306a36Sopenharmony_ci netdev->hw_features = mgp->features | NETIF_F_RXCSUM; 386362306a36Sopenharmony_ci 386462306a36Sopenharmony_ci /* fake NETIF_F_HW_VLAN_CTAG_RX for good GRO performance */ 386562306a36Sopenharmony_ci netdev->hw_features |= NETIF_F_HW_VLAN_CTAG_RX; 386662306a36Sopenharmony_ci 386762306a36Sopenharmony_ci netdev->features = netdev->hw_features | NETIF_F_HIGHDMA; 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_ci netdev->vlan_features |= mgp->features; 387062306a36Sopenharmony_ci if (mgp->fw_ver_tiny < 37) 387162306a36Sopenharmony_ci netdev->vlan_features &= ~NETIF_F_TSO6; 387262306a36Sopenharmony_ci if (mgp->fw_ver_tiny < 32) 387362306a36Sopenharmony_ci netdev->vlan_features &= ~NETIF_F_TSO; 387462306a36Sopenharmony_ci 387562306a36Sopenharmony_ci /* make sure we can get an irq, and that MSI can be 387662306a36Sopenharmony_ci * setup (if available). */ 387762306a36Sopenharmony_ci status = myri10ge_request_irq(mgp); 387862306a36Sopenharmony_ci if (status != 0) 387962306a36Sopenharmony_ci goto abort_with_slices; 388062306a36Sopenharmony_ci myri10ge_free_irq(mgp); 388162306a36Sopenharmony_ci 388262306a36Sopenharmony_ci /* Save configuration space to be restored if the 388362306a36Sopenharmony_ci * nic resets due to a parity error */ 388462306a36Sopenharmony_ci pci_save_state(pdev); 388562306a36Sopenharmony_ci 388662306a36Sopenharmony_ci /* Setup the watchdog timer */ 388762306a36Sopenharmony_ci timer_setup(&mgp->watchdog_timer, myri10ge_watchdog_timer, 0); 388862306a36Sopenharmony_ci 388962306a36Sopenharmony_ci netdev->ethtool_ops = &myri10ge_ethtool_ops; 389062306a36Sopenharmony_ci INIT_WORK(&mgp->watchdog_work, myri10ge_watchdog); 389162306a36Sopenharmony_ci status = register_netdev(netdev); 389262306a36Sopenharmony_ci if (status != 0) { 389362306a36Sopenharmony_ci dev_err(&pdev->dev, "register_netdev failed: %d\n", status); 389462306a36Sopenharmony_ci goto abort_with_state; 389562306a36Sopenharmony_ci } 389662306a36Sopenharmony_ci if (mgp->msix_enabled) 389762306a36Sopenharmony_ci dev_info(dev, "%d MSI-X IRQs, tx bndry %d, fw %s, MTRR %s, WC Enabled\n", 389862306a36Sopenharmony_ci mgp->num_slices, mgp->tx_boundary, mgp->fw_name, 389962306a36Sopenharmony_ci (mgp->wc_cookie > 0 ? "Enabled" : "Disabled")); 390062306a36Sopenharmony_ci else 390162306a36Sopenharmony_ci dev_info(dev, "%s IRQ %d, tx bndry %d, fw %s, MTRR %s, WC Enabled\n", 390262306a36Sopenharmony_ci mgp->msi_enabled ? "MSI" : "xPIC", 390362306a36Sopenharmony_ci pdev->irq, mgp->tx_boundary, mgp->fw_name, 390462306a36Sopenharmony_ci (mgp->wc_cookie > 0 ? "Enabled" : "Disabled")); 390562306a36Sopenharmony_ci 390662306a36Sopenharmony_ci board_number++; 390762306a36Sopenharmony_ci return 0; 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ciabort_with_state: 391062306a36Sopenharmony_ci pci_restore_state(pdev); 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_ciabort_with_slices: 391362306a36Sopenharmony_ci myri10ge_free_slices(mgp); 391462306a36Sopenharmony_ci 391562306a36Sopenharmony_ciabort_with_firmware: 391662306a36Sopenharmony_ci kfree(mgp->msix_vectors); 391762306a36Sopenharmony_ci myri10ge_dummy_rdma(mgp, 0); 391862306a36Sopenharmony_ci 391962306a36Sopenharmony_ciabort_with_ioremap: 392062306a36Sopenharmony_ci if (mgp->mac_addr_string != NULL) 392162306a36Sopenharmony_ci dev_err(&pdev->dev, 392262306a36Sopenharmony_ci "myri10ge_probe() failed: MAC=%s, SN=%ld\n", 392362306a36Sopenharmony_ci mgp->mac_addr_string, mgp->serial_number); 392462306a36Sopenharmony_ci iounmap(mgp->sram); 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_ciabort_with_mtrr: 392762306a36Sopenharmony_ci arch_phys_wc_del(mgp->wc_cookie); 392862306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd), 392962306a36Sopenharmony_ci mgp->cmd, mgp->cmd_bus); 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ciabort_with_enabled: 393262306a36Sopenharmony_ci pci_disable_device(pdev); 393362306a36Sopenharmony_ci 393462306a36Sopenharmony_ciabort_with_netdev: 393562306a36Sopenharmony_ci set_fw_name(mgp, NULL, false); 393662306a36Sopenharmony_ci free_netdev(netdev); 393762306a36Sopenharmony_ci return status; 393862306a36Sopenharmony_ci} 393962306a36Sopenharmony_ci 394062306a36Sopenharmony_ci/* 394162306a36Sopenharmony_ci * myri10ge_remove 394262306a36Sopenharmony_ci * 394362306a36Sopenharmony_ci * Does what is necessary to shutdown one Myrinet device. Called 394462306a36Sopenharmony_ci * once for each Myrinet card by the kernel when a module is 394562306a36Sopenharmony_ci * unloaded. 394662306a36Sopenharmony_ci */ 394762306a36Sopenharmony_cistatic void myri10ge_remove(struct pci_dev *pdev) 394862306a36Sopenharmony_ci{ 394962306a36Sopenharmony_ci struct myri10ge_priv *mgp; 395062306a36Sopenharmony_ci struct net_device *netdev; 395162306a36Sopenharmony_ci 395262306a36Sopenharmony_ci mgp = pci_get_drvdata(pdev); 395362306a36Sopenharmony_ci if (mgp == NULL) 395462306a36Sopenharmony_ci return; 395562306a36Sopenharmony_ci 395662306a36Sopenharmony_ci cancel_work_sync(&mgp->watchdog_work); 395762306a36Sopenharmony_ci netdev = mgp->dev; 395862306a36Sopenharmony_ci unregister_netdev(netdev); 395962306a36Sopenharmony_ci 396062306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 396162306a36Sopenharmony_ci myri10ge_teardown_dca(mgp); 396262306a36Sopenharmony_ci#endif 396362306a36Sopenharmony_ci myri10ge_dummy_rdma(mgp, 0); 396462306a36Sopenharmony_ci 396562306a36Sopenharmony_ci /* avoid a memory leak */ 396662306a36Sopenharmony_ci pci_restore_state(pdev); 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci iounmap(mgp->sram); 396962306a36Sopenharmony_ci arch_phys_wc_del(mgp->wc_cookie); 397062306a36Sopenharmony_ci myri10ge_free_slices(mgp); 397162306a36Sopenharmony_ci kfree(mgp->msix_vectors); 397262306a36Sopenharmony_ci dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd), 397362306a36Sopenharmony_ci mgp->cmd, mgp->cmd_bus); 397462306a36Sopenharmony_ci 397562306a36Sopenharmony_ci set_fw_name(mgp, NULL, false); 397662306a36Sopenharmony_ci free_netdev(netdev); 397762306a36Sopenharmony_ci pci_disable_device(pdev); 397862306a36Sopenharmony_ci} 397962306a36Sopenharmony_ci 398062306a36Sopenharmony_ci#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E 0x0008 398162306a36Sopenharmony_ci#define PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9 0x0009 398262306a36Sopenharmony_ci 398362306a36Sopenharmony_cistatic const struct pci_device_id myri10ge_pci_tbl[] = { 398462306a36Sopenharmony_ci {PCI_DEVICE(PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E)}, 398562306a36Sopenharmony_ci {PCI_DEVICE 398662306a36Sopenharmony_ci (PCI_VENDOR_ID_MYRICOM, PCI_DEVICE_ID_MYRICOM_MYRI10GE_Z8E_9)}, 398762306a36Sopenharmony_ci {0}, 398862306a36Sopenharmony_ci}; 398962306a36Sopenharmony_ci 399062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, myri10ge_pci_tbl); 399162306a36Sopenharmony_ci 399262306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(myri10ge_pm_ops, myri10ge_suspend, myri10ge_resume); 399362306a36Sopenharmony_ci 399462306a36Sopenharmony_cistatic struct pci_driver myri10ge_driver = { 399562306a36Sopenharmony_ci .name = "myri10ge", 399662306a36Sopenharmony_ci .probe = myri10ge_probe, 399762306a36Sopenharmony_ci .remove = myri10ge_remove, 399862306a36Sopenharmony_ci .id_table = myri10ge_pci_tbl, 399962306a36Sopenharmony_ci .driver.pm = &myri10ge_pm_ops, 400062306a36Sopenharmony_ci}; 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 400362306a36Sopenharmony_cistatic int 400462306a36Sopenharmony_cimyri10ge_notify_dca(struct notifier_block *nb, unsigned long event, void *p) 400562306a36Sopenharmony_ci{ 400662306a36Sopenharmony_ci int err = driver_for_each_device(&myri10ge_driver.driver, 400762306a36Sopenharmony_ci NULL, &event, 400862306a36Sopenharmony_ci myri10ge_notify_dca_device); 400962306a36Sopenharmony_ci 401062306a36Sopenharmony_ci if (err) 401162306a36Sopenharmony_ci return NOTIFY_BAD; 401262306a36Sopenharmony_ci return NOTIFY_DONE; 401362306a36Sopenharmony_ci} 401462306a36Sopenharmony_ci 401562306a36Sopenharmony_cistatic struct notifier_block myri10ge_dca_notifier = { 401662306a36Sopenharmony_ci .notifier_call = myri10ge_notify_dca, 401762306a36Sopenharmony_ci .next = NULL, 401862306a36Sopenharmony_ci .priority = 0, 401962306a36Sopenharmony_ci}; 402062306a36Sopenharmony_ci#endif /* CONFIG_MYRI10GE_DCA */ 402162306a36Sopenharmony_ci 402262306a36Sopenharmony_cistatic __init int myri10ge_init_module(void) 402362306a36Sopenharmony_ci{ 402462306a36Sopenharmony_ci pr_info("Version %s\n", MYRI10GE_VERSION_STR); 402562306a36Sopenharmony_ci 402662306a36Sopenharmony_ci if (myri10ge_rss_hash > MXGEFW_RSS_HASH_TYPE_MAX) { 402762306a36Sopenharmony_ci pr_err("Illegal rssh hash type %d, defaulting to source port\n", 402862306a36Sopenharmony_ci myri10ge_rss_hash); 402962306a36Sopenharmony_ci myri10ge_rss_hash = MXGEFW_RSS_HASH_TYPE_SRC_PORT; 403062306a36Sopenharmony_ci } 403162306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 403262306a36Sopenharmony_ci dca_register_notify(&myri10ge_dca_notifier); 403362306a36Sopenharmony_ci#endif 403462306a36Sopenharmony_ci if (myri10ge_max_slices > MYRI10GE_MAX_SLICES) 403562306a36Sopenharmony_ci myri10ge_max_slices = MYRI10GE_MAX_SLICES; 403662306a36Sopenharmony_ci 403762306a36Sopenharmony_ci return pci_register_driver(&myri10ge_driver); 403862306a36Sopenharmony_ci} 403962306a36Sopenharmony_ci 404062306a36Sopenharmony_cimodule_init(myri10ge_init_module); 404162306a36Sopenharmony_ci 404262306a36Sopenharmony_cistatic __exit void myri10ge_cleanup_module(void) 404362306a36Sopenharmony_ci{ 404462306a36Sopenharmony_ci#ifdef CONFIG_MYRI10GE_DCA 404562306a36Sopenharmony_ci dca_unregister_notify(&myri10ge_dca_notifier); 404662306a36Sopenharmony_ci#endif 404762306a36Sopenharmony_ci pci_unregister_driver(&myri10ge_driver); 404862306a36Sopenharmony_ci} 404962306a36Sopenharmony_ci 405062306a36Sopenharmony_cimodule_exit(myri10ge_cleanup_module); 4051