18c2ecf20Sopenharmony_ci/************************************************************************ 28c2ecf20Sopenharmony_ci * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC 38c2ecf20Sopenharmony_ci * Copyright(c) 2002-2010 Exar Corp. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This software may be used and distributed according to the terms of 68c2ecf20Sopenharmony_ci * the GNU General Public License (GPL), incorporated herein by reference. 78c2ecf20Sopenharmony_ci * Drivers based on or derived from this code fall under the GPL and must 88c2ecf20Sopenharmony_ci * retain the authorship, copyright and license notice. This file is not 98c2ecf20Sopenharmony_ci * a complete program and may only be used when the entire operating 108c2ecf20Sopenharmony_ci * system is licensed under the GPL. 118c2ecf20Sopenharmony_ci * See the file COPYING in this distribution for more information. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Credits: 148c2ecf20Sopenharmony_ci * Jeff Garzik : For pointing out the improper error condition 158c2ecf20Sopenharmony_ci * check in the s2io_xmit routine and also some 168c2ecf20Sopenharmony_ci * issues in the Tx watch dog function. Also for 178c2ecf20Sopenharmony_ci * patiently answering all those innumerable 188c2ecf20Sopenharmony_ci * questions regaring the 2.6 porting issues. 198c2ecf20Sopenharmony_ci * Stephen Hemminger : Providing proper 2.6 porting mechanism for some 208c2ecf20Sopenharmony_ci * macros available only in 2.6 Kernel. 218c2ecf20Sopenharmony_ci * Francois Romieu : For pointing out all code part that were 228c2ecf20Sopenharmony_ci * deprecated and also styling related comments. 238c2ecf20Sopenharmony_ci * Grant Grundler : For helping me get rid of some Architecture 248c2ecf20Sopenharmony_ci * dependent code. 258c2ecf20Sopenharmony_ci * Christopher Hellwig : Some more 2.6 specific issues in the driver. 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * The module loadable parameters that are supported by the driver and a brief 288c2ecf20Sopenharmony_ci * explanation of all the variables. 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * rx_ring_num : This can be used to program the number of receive rings used 318c2ecf20Sopenharmony_ci * in the driver. 328c2ecf20Sopenharmony_ci * rx_ring_sz: This defines the number of receive blocks each ring can have. 338c2ecf20Sopenharmony_ci * This is also an array of size 8. 348c2ecf20Sopenharmony_ci * rx_ring_mode: This defines the operation mode of all 8 rings. The valid 358c2ecf20Sopenharmony_ci * values are 1, 2. 368c2ecf20Sopenharmony_ci * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver. 378c2ecf20Sopenharmony_ci * tx_fifo_len: This too is an array of 8. Each element defines the number of 388c2ecf20Sopenharmony_ci * Tx descriptors that can be associated with each corresponding FIFO. 398c2ecf20Sopenharmony_ci * intr_type: This defines the type of interrupt. The values can be 0(INTA), 408c2ecf20Sopenharmony_ci * 2(MSI_X). Default value is '2(MSI_X)' 418c2ecf20Sopenharmony_ci * lro_max_pkts: This parameter defines maximum number of packets can be 428c2ecf20Sopenharmony_ci * aggregated as a single large packet 438c2ecf20Sopenharmony_ci * napi: This parameter used to enable/disable NAPI (polling Rx) 448c2ecf20Sopenharmony_ci * Possible values '1' for enable and '0' for disable. Default is '1' 458c2ecf20Sopenharmony_ci * vlan_tag_strip: This can be used to enable or disable vlan stripping. 468c2ecf20Sopenharmony_ci * Possible values '1' for enable , '0' for disable. 478c2ecf20Sopenharmony_ci * Default is '2' - which means disable in promisc mode 488c2ecf20Sopenharmony_ci * and enable in non-promiscuous mode. 498c2ecf20Sopenharmony_ci * multiq: This parameter used to enable/disable MULTIQUEUE support. 508c2ecf20Sopenharmony_ci * Possible values '1' for enable and '0' for disable. Default is '0' 518c2ecf20Sopenharmony_ci ************************************************************************/ 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#include <linux/module.h> 568c2ecf20Sopenharmony_ci#include <linux/types.h> 578c2ecf20Sopenharmony_ci#include <linux/errno.h> 588c2ecf20Sopenharmony_ci#include <linux/ioport.h> 598c2ecf20Sopenharmony_ci#include <linux/pci.h> 608c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 618c2ecf20Sopenharmony_ci#include <linux/kernel.h> 628c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 638c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 648c2ecf20Sopenharmony_ci#include <linux/mdio.h> 658c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 668c2ecf20Sopenharmony_ci#include <linux/init.h> 678c2ecf20Sopenharmony_ci#include <linux/delay.h> 688c2ecf20Sopenharmony_ci#include <linux/stddef.h> 698c2ecf20Sopenharmony_ci#include <linux/ioctl.h> 708c2ecf20Sopenharmony_ci#include <linux/timex.h> 718c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 728c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 738c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 748c2ecf20Sopenharmony_ci#include <linux/ip.h> 758c2ecf20Sopenharmony_ci#include <linux/tcp.h> 768c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 778c2ecf20Sopenharmony_ci#include <linux/io.h> 788c2ecf20Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 798c2ecf20Sopenharmony_ci#include <linux/slab.h> 808c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 818c2ecf20Sopenharmony_ci#include <net/tcp.h> 828c2ecf20Sopenharmony_ci#include <net/checksum.h> 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#include <asm/div64.h> 858c2ecf20Sopenharmony_ci#include <asm/irq.h> 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* local include */ 888c2ecf20Sopenharmony_ci#include "s2io.h" 898c2ecf20Sopenharmony_ci#include "s2io-regs.h" 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define DRV_VERSION "2.0.26.28" 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* S2io Driver name & version. */ 948c2ecf20Sopenharmony_cistatic const char s2io_driver_name[] = "Neterion"; 958c2ecf20Sopenharmony_cistatic const char s2io_driver_version[] = DRV_VERSION; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic const int rxd_size[2] = {32, 48}; 988c2ecf20Sopenharmony_cistatic const int rxd_count[2] = {127, 85}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic inline int RXD_IS_UP2DT(struct RxD_t *rxdp) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci int ret; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) && 1058c2ecf20Sopenharmony_ci (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK)); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci return ret; 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* 1118c2ecf20Sopenharmony_ci * Cards with following subsystem_id have a link state indication 1128c2ecf20Sopenharmony_ci * problem, 600B, 600C, 600D, 640B, 640C and 640D. 1138c2ecf20Sopenharmony_ci * macro below identifies these cards given the subsystem_id. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid) \ 1168c2ecf20Sopenharmony_ci (dev_type == XFRAME_I_DEVICE) ? \ 1178c2ecf20Sopenharmony_ci ((((subid >= 0x600B) && (subid <= 0x600D)) || \ 1188c2ecf20Sopenharmony_ci ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci#define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \ 1218c2ecf20Sopenharmony_ci ADAPTER_STATUS_RMAC_LOCAL_FAULT))) 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic inline int is_s2io_card_up(const struct s2io_nic *sp) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci return test_bit(__S2IO_STATE_CARD_UP, &sp->state); 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/* Ethtool related variables and Macros. */ 1298c2ecf20Sopenharmony_cistatic const char s2io_gstrings[][ETH_GSTRING_LEN] = { 1308c2ecf20Sopenharmony_ci "Register test\t(offline)", 1318c2ecf20Sopenharmony_ci "Eeprom test\t(offline)", 1328c2ecf20Sopenharmony_ci "Link test\t(online)", 1338c2ecf20Sopenharmony_ci "RLDRAM test\t(offline)", 1348c2ecf20Sopenharmony_ci "BIST Test\t(offline)" 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = { 1388c2ecf20Sopenharmony_ci {"tmac_frms"}, 1398c2ecf20Sopenharmony_ci {"tmac_data_octets"}, 1408c2ecf20Sopenharmony_ci {"tmac_drop_frms"}, 1418c2ecf20Sopenharmony_ci {"tmac_mcst_frms"}, 1428c2ecf20Sopenharmony_ci {"tmac_bcst_frms"}, 1438c2ecf20Sopenharmony_ci {"tmac_pause_ctrl_frms"}, 1448c2ecf20Sopenharmony_ci {"tmac_ttl_octets"}, 1458c2ecf20Sopenharmony_ci {"tmac_ucst_frms"}, 1468c2ecf20Sopenharmony_ci {"tmac_nucst_frms"}, 1478c2ecf20Sopenharmony_ci {"tmac_any_err_frms"}, 1488c2ecf20Sopenharmony_ci {"tmac_ttl_less_fb_octets"}, 1498c2ecf20Sopenharmony_ci {"tmac_vld_ip_octets"}, 1508c2ecf20Sopenharmony_ci {"tmac_vld_ip"}, 1518c2ecf20Sopenharmony_ci {"tmac_drop_ip"}, 1528c2ecf20Sopenharmony_ci {"tmac_icmp"}, 1538c2ecf20Sopenharmony_ci {"tmac_rst_tcp"}, 1548c2ecf20Sopenharmony_ci {"tmac_tcp"}, 1558c2ecf20Sopenharmony_ci {"tmac_udp"}, 1568c2ecf20Sopenharmony_ci {"rmac_vld_frms"}, 1578c2ecf20Sopenharmony_ci {"rmac_data_octets"}, 1588c2ecf20Sopenharmony_ci {"rmac_fcs_err_frms"}, 1598c2ecf20Sopenharmony_ci {"rmac_drop_frms"}, 1608c2ecf20Sopenharmony_ci {"rmac_vld_mcst_frms"}, 1618c2ecf20Sopenharmony_ci {"rmac_vld_bcst_frms"}, 1628c2ecf20Sopenharmony_ci {"rmac_in_rng_len_err_frms"}, 1638c2ecf20Sopenharmony_ci {"rmac_out_rng_len_err_frms"}, 1648c2ecf20Sopenharmony_ci {"rmac_long_frms"}, 1658c2ecf20Sopenharmony_ci {"rmac_pause_ctrl_frms"}, 1668c2ecf20Sopenharmony_ci {"rmac_unsup_ctrl_frms"}, 1678c2ecf20Sopenharmony_ci {"rmac_ttl_octets"}, 1688c2ecf20Sopenharmony_ci {"rmac_accepted_ucst_frms"}, 1698c2ecf20Sopenharmony_ci {"rmac_accepted_nucst_frms"}, 1708c2ecf20Sopenharmony_ci {"rmac_discarded_frms"}, 1718c2ecf20Sopenharmony_ci {"rmac_drop_events"}, 1728c2ecf20Sopenharmony_ci {"rmac_ttl_less_fb_octets"}, 1738c2ecf20Sopenharmony_ci {"rmac_ttl_frms"}, 1748c2ecf20Sopenharmony_ci {"rmac_usized_frms"}, 1758c2ecf20Sopenharmony_ci {"rmac_osized_frms"}, 1768c2ecf20Sopenharmony_ci {"rmac_frag_frms"}, 1778c2ecf20Sopenharmony_ci {"rmac_jabber_frms"}, 1788c2ecf20Sopenharmony_ci {"rmac_ttl_64_frms"}, 1798c2ecf20Sopenharmony_ci {"rmac_ttl_65_127_frms"}, 1808c2ecf20Sopenharmony_ci {"rmac_ttl_128_255_frms"}, 1818c2ecf20Sopenharmony_ci {"rmac_ttl_256_511_frms"}, 1828c2ecf20Sopenharmony_ci {"rmac_ttl_512_1023_frms"}, 1838c2ecf20Sopenharmony_ci {"rmac_ttl_1024_1518_frms"}, 1848c2ecf20Sopenharmony_ci {"rmac_ip"}, 1858c2ecf20Sopenharmony_ci {"rmac_ip_octets"}, 1868c2ecf20Sopenharmony_ci {"rmac_hdr_err_ip"}, 1878c2ecf20Sopenharmony_ci {"rmac_drop_ip"}, 1888c2ecf20Sopenharmony_ci {"rmac_icmp"}, 1898c2ecf20Sopenharmony_ci {"rmac_tcp"}, 1908c2ecf20Sopenharmony_ci {"rmac_udp"}, 1918c2ecf20Sopenharmony_ci {"rmac_err_drp_udp"}, 1928c2ecf20Sopenharmony_ci {"rmac_xgmii_err_sym"}, 1938c2ecf20Sopenharmony_ci {"rmac_frms_q0"}, 1948c2ecf20Sopenharmony_ci {"rmac_frms_q1"}, 1958c2ecf20Sopenharmony_ci {"rmac_frms_q2"}, 1968c2ecf20Sopenharmony_ci {"rmac_frms_q3"}, 1978c2ecf20Sopenharmony_ci {"rmac_frms_q4"}, 1988c2ecf20Sopenharmony_ci {"rmac_frms_q5"}, 1998c2ecf20Sopenharmony_ci {"rmac_frms_q6"}, 2008c2ecf20Sopenharmony_ci {"rmac_frms_q7"}, 2018c2ecf20Sopenharmony_ci {"rmac_full_q0"}, 2028c2ecf20Sopenharmony_ci {"rmac_full_q1"}, 2038c2ecf20Sopenharmony_ci {"rmac_full_q2"}, 2048c2ecf20Sopenharmony_ci {"rmac_full_q3"}, 2058c2ecf20Sopenharmony_ci {"rmac_full_q4"}, 2068c2ecf20Sopenharmony_ci {"rmac_full_q5"}, 2078c2ecf20Sopenharmony_ci {"rmac_full_q6"}, 2088c2ecf20Sopenharmony_ci {"rmac_full_q7"}, 2098c2ecf20Sopenharmony_ci {"rmac_pause_cnt"}, 2108c2ecf20Sopenharmony_ci {"rmac_xgmii_data_err_cnt"}, 2118c2ecf20Sopenharmony_ci {"rmac_xgmii_ctrl_err_cnt"}, 2128c2ecf20Sopenharmony_ci {"rmac_accepted_ip"}, 2138c2ecf20Sopenharmony_ci {"rmac_err_tcp"}, 2148c2ecf20Sopenharmony_ci {"rd_req_cnt"}, 2158c2ecf20Sopenharmony_ci {"new_rd_req_cnt"}, 2168c2ecf20Sopenharmony_ci {"new_rd_req_rtry_cnt"}, 2178c2ecf20Sopenharmony_ci {"rd_rtry_cnt"}, 2188c2ecf20Sopenharmony_ci {"wr_rtry_rd_ack_cnt"}, 2198c2ecf20Sopenharmony_ci {"wr_req_cnt"}, 2208c2ecf20Sopenharmony_ci {"new_wr_req_cnt"}, 2218c2ecf20Sopenharmony_ci {"new_wr_req_rtry_cnt"}, 2228c2ecf20Sopenharmony_ci {"wr_rtry_cnt"}, 2238c2ecf20Sopenharmony_ci {"wr_disc_cnt"}, 2248c2ecf20Sopenharmony_ci {"rd_rtry_wr_ack_cnt"}, 2258c2ecf20Sopenharmony_ci {"txp_wr_cnt"}, 2268c2ecf20Sopenharmony_ci {"txd_rd_cnt"}, 2278c2ecf20Sopenharmony_ci {"txd_wr_cnt"}, 2288c2ecf20Sopenharmony_ci {"rxd_rd_cnt"}, 2298c2ecf20Sopenharmony_ci {"rxd_wr_cnt"}, 2308c2ecf20Sopenharmony_ci {"txf_rd_cnt"}, 2318c2ecf20Sopenharmony_ci {"rxf_wr_cnt"} 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic const char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = { 2358c2ecf20Sopenharmony_ci {"rmac_ttl_1519_4095_frms"}, 2368c2ecf20Sopenharmony_ci {"rmac_ttl_4096_8191_frms"}, 2378c2ecf20Sopenharmony_ci {"rmac_ttl_8192_max_frms"}, 2388c2ecf20Sopenharmony_ci {"rmac_ttl_gt_max_frms"}, 2398c2ecf20Sopenharmony_ci {"rmac_osized_alt_frms"}, 2408c2ecf20Sopenharmony_ci {"rmac_jabber_alt_frms"}, 2418c2ecf20Sopenharmony_ci {"rmac_gt_max_alt_frms"}, 2428c2ecf20Sopenharmony_ci {"rmac_vlan_frms"}, 2438c2ecf20Sopenharmony_ci {"rmac_len_discard"}, 2448c2ecf20Sopenharmony_ci {"rmac_fcs_discard"}, 2458c2ecf20Sopenharmony_ci {"rmac_pf_discard"}, 2468c2ecf20Sopenharmony_ci {"rmac_da_discard"}, 2478c2ecf20Sopenharmony_ci {"rmac_red_discard"}, 2488c2ecf20Sopenharmony_ci {"rmac_rts_discard"}, 2498c2ecf20Sopenharmony_ci {"rmac_ingm_full_discard"}, 2508c2ecf20Sopenharmony_ci {"link_fault_cnt"} 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic const char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = { 2548c2ecf20Sopenharmony_ci {"\n DRIVER STATISTICS"}, 2558c2ecf20Sopenharmony_ci {"single_bit_ecc_errs"}, 2568c2ecf20Sopenharmony_ci {"double_bit_ecc_errs"}, 2578c2ecf20Sopenharmony_ci {"parity_err_cnt"}, 2588c2ecf20Sopenharmony_ci {"serious_err_cnt"}, 2598c2ecf20Sopenharmony_ci {"soft_reset_cnt"}, 2608c2ecf20Sopenharmony_ci {"fifo_full_cnt"}, 2618c2ecf20Sopenharmony_ci {"ring_0_full_cnt"}, 2628c2ecf20Sopenharmony_ci {"ring_1_full_cnt"}, 2638c2ecf20Sopenharmony_ci {"ring_2_full_cnt"}, 2648c2ecf20Sopenharmony_ci {"ring_3_full_cnt"}, 2658c2ecf20Sopenharmony_ci {"ring_4_full_cnt"}, 2668c2ecf20Sopenharmony_ci {"ring_5_full_cnt"}, 2678c2ecf20Sopenharmony_ci {"ring_6_full_cnt"}, 2688c2ecf20Sopenharmony_ci {"ring_7_full_cnt"}, 2698c2ecf20Sopenharmony_ci {"alarm_transceiver_temp_high"}, 2708c2ecf20Sopenharmony_ci {"alarm_transceiver_temp_low"}, 2718c2ecf20Sopenharmony_ci {"alarm_laser_bias_current_high"}, 2728c2ecf20Sopenharmony_ci {"alarm_laser_bias_current_low"}, 2738c2ecf20Sopenharmony_ci {"alarm_laser_output_power_high"}, 2748c2ecf20Sopenharmony_ci {"alarm_laser_output_power_low"}, 2758c2ecf20Sopenharmony_ci {"warn_transceiver_temp_high"}, 2768c2ecf20Sopenharmony_ci {"warn_transceiver_temp_low"}, 2778c2ecf20Sopenharmony_ci {"warn_laser_bias_current_high"}, 2788c2ecf20Sopenharmony_ci {"warn_laser_bias_current_low"}, 2798c2ecf20Sopenharmony_ci {"warn_laser_output_power_high"}, 2808c2ecf20Sopenharmony_ci {"warn_laser_output_power_low"}, 2818c2ecf20Sopenharmony_ci {"lro_aggregated_pkts"}, 2828c2ecf20Sopenharmony_ci {"lro_flush_both_count"}, 2838c2ecf20Sopenharmony_ci {"lro_out_of_sequence_pkts"}, 2848c2ecf20Sopenharmony_ci {"lro_flush_due_to_max_pkts"}, 2858c2ecf20Sopenharmony_ci {"lro_avg_aggr_pkts"}, 2868c2ecf20Sopenharmony_ci {"mem_alloc_fail_cnt"}, 2878c2ecf20Sopenharmony_ci {"pci_map_fail_cnt"}, 2888c2ecf20Sopenharmony_ci {"watchdog_timer_cnt"}, 2898c2ecf20Sopenharmony_ci {"mem_allocated"}, 2908c2ecf20Sopenharmony_ci {"mem_freed"}, 2918c2ecf20Sopenharmony_ci {"link_up_cnt"}, 2928c2ecf20Sopenharmony_ci {"link_down_cnt"}, 2938c2ecf20Sopenharmony_ci {"link_up_time"}, 2948c2ecf20Sopenharmony_ci {"link_down_time"}, 2958c2ecf20Sopenharmony_ci {"tx_tcode_buf_abort_cnt"}, 2968c2ecf20Sopenharmony_ci {"tx_tcode_desc_abort_cnt"}, 2978c2ecf20Sopenharmony_ci {"tx_tcode_parity_err_cnt"}, 2988c2ecf20Sopenharmony_ci {"tx_tcode_link_loss_cnt"}, 2998c2ecf20Sopenharmony_ci {"tx_tcode_list_proc_err_cnt"}, 3008c2ecf20Sopenharmony_ci {"rx_tcode_parity_err_cnt"}, 3018c2ecf20Sopenharmony_ci {"rx_tcode_abort_cnt"}, 3028c2ecf20Sopenharmony_ci {"rx_tcode_parity_abort_cnt"}, 3038c2ecf20Sopenharmony_ci {"rx_tcode_rda_fail_cnt"}, 3048c2ecf20Sopenharmony_ci {"rx_tcode_unkn_prot_cnt"}, 3058c2ecf20Sopenharmony_ci {"rx_tcode_fcs_err_cnt"}, 3068c2ecf20Sopenharmony_ci {"rx_tcode_buf_size_err_cnt"}, 3078c2ecf20Sopenharmony_ci {"rx_tcode_rxd_corrupt_cnt"}, 3088c2ecf20Sopenharmony_ci {"rx_tcode_unkn_err_cnt"}, 3098c2ecf20Sopenharmony_ci {"tda_err_cnt"}, 3108c2ecf20Sopenharmony_ci {"pfc_err_cnt"}, 3118c2ecf20Sopenharmony_ci {"pcc_err_cnt"}, 3128c2ecf20Sopenharmony_ci {"tti_err_cnt"}, 3138c2ecf20Sopenharmony_ci {"tpa_err_cnt"}, 3148c2ecf20Sopenharmony_ci {"sm_err_cnt"}, 3158c2ecf20Sopenharmony_ci {"lso_err_cnt"}, 3168c2ecf20Sopenharmony_ci {"mac_tmac_err_cnt"}, 3178c2ecf20Sopenharmony_ci {"mac_rmac_err_cnt"}, 3188c2ecf20Sopenharmony_ci {"xgxs_txgxs_err_cnt"}, 3198c2ecf20Sopenharmony_ci {"xgxs_rxgxs_err_cnt"}, 3208c2ecf20Sopenharmony_ci {"rc_err_cnt"}, 3218c2ecf20Sopenharmony_ci {"prc_pcix_err_cnt"}, 3228c2ecf20Sopenharmony_ci {"rpa_err_cnt"}, 3238c2ecf20Sopenharmony_ci {"rda_err_cnt"}, 3248c2ecf20Sopenharmony_ci {"rti_err_cnt"}, 3258c2ecf20Sopenharmony_ci {"mc_err_cnt"} 3268c2ecf20Sopenharmony_ci}; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci#define S2IO_XENA_STAT_LEN ARRAY_SIZE(ethtool_xena_stats_keys) 3298c2ecf20Sopenharmony_ci#define S2IO_ENHANCED_STAT_LEN ARRAY_SIZE(ethtool_enhanced_stats_keys) 3308c2ecf20Sopenharmony_ci#define S2IO_DRIVER_STAT_LEN ARRAY_SIZE(ethtool_driver_stats_keys) 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci#define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN) 3338c2ecf20Sopenharmony_ci#define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN) 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci#define XFRAME_I_STAT_STRINGS_LEN (XFRAME_I_STAT_LEN * ETH_GSTRING_LEN) 3368c2ecf20Sopenharmony_ci#define XFRAME_II_STAT_STRINGS_LEN (XFRAME_II_STAT_LEN * ETH_GSTRING_LEN) 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci#define S2IO_TEST_LEN ARRAY_SIZE(s2io_gstrings) 3398c2ecf20Sopenharmony_ci#define S2IO_STRINGS_LEN (S2IO_TEST_LEN * ETH_GSTRING_LEN) 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci/* copy mac addr to def_mac_addr array */ 3428c2ecf20Sopenharmony_cistatic void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci sp->def_mac_addr[offset].mac_addr[5] = (u8) (mac_addr); 3458c2ecf20Sopenharmony_ci sp->def_mac_addr[offset].mac_addr[4] = (u8) (mac_addr >> 8); 3468c2ecf20Sopenharmony_ci sp->def_mac_addr[offset].mac_addr[3] = (u8) (mac_addr >> 16); 3478c2ecf20Sopenharmony_ci sp->def_mac_addr[offset].mac_addr[2] = (u8) (mac_addr >> 24); 3488c2ecf20Sopenharmony_ci sp->def_mac_addr[offset].mac_addr[1] = (u8) (mac_addr >> 32); 3498c2ecf20Sopenharmony_ci sp->def_mac_addr[offset].mac_addr[0] = (u8) (mac_addr >> 40); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci/* 3538c2ecf20Sopenharmony_ci * Constants to be programmed into the Xena's registers, to configure 3548c2ecf20Sopenharmony_ci * the XAUI. 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci#define END_SIGN 0x0 3588c2ecf20Sopenharmony_cistatic const u64 herc_act_dtx_cfg[] = { 3598c2ecf20Sopenharmony_ci /* Set address */ 3608c2ecf20Sopenharmony_ci 0x8000051536750000ULL, 0x80000515367500E0ULL, 3618c2ecf20Sopenharmony_ci /* Write data */ 3628c2ecf20Sopenharmony_ci 0x8000051536750004ULL, 0x80000515367500E4ULL, 3638c2ecf20Sopenharmony_ci /* Set address */ 3648c2ecf20Sopenharmony_ci 0x80010515003F0000ULL, 0x80010515003F00E0ULL, 3658c2ecf20Sopenharmony_ci /* Write data */ 3668c2ecf20Sopenharmony_ci 0x80010515003F0004ULL, 0x80010515003F00E4ULL, 3678c2ecf20Sopenharmony_ci /* Set address */ 3688c2ecf20Sopenharmony_ci 0x801205150D440000ULL, 0x801205150D4400E0ULL, 3698c2ecf20Sopenharmony_ci /* Write data */ 3708c2ecf20Sopenharmony_ci 0x801205150D440004ULL, 0x801205150D4400E4ULL, 3718c2ecf20Sopenharmony_ci /* Set address */ 3728c2ecf20Sopenharmony_ci 0x80020515F2100000ULL, 0x80020515F21000E0ULL, 3738c2ecf20Sopenharmony_ci /* Write data */ 3748c2ecf20Sopenharmony_ci 0x80020515F2100004ULL, 0x80020515F21000E4ULL, 3758c2ecf20Sopenharmony_ci /* Done */ 3768c2ecf20Sopenharmony_ci END_SIGN 3778c2ecf20Sopenharmony_ci}; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic const u64 xena_dtx_cfg[] = { 3808c2ecf20Sopenharmony_ci /* Set address */ 3818c2ecf20Sopenharmony_ci 0x8000051500000000ULL, 0x80000515000000E0ULL, 3828c2ecf20Sopenharmony_ci /* Write data */ 3838c2ecf20Sopenharmony_ci 0x80000515D9350004ULL, 0x80000515D93500E4ULL, 3848c2ecf20Sopenharmony_ci /* Set address */ 3858c2ecf20Sopenharmony_ci 0x8001051500000000ULL, 0x80010515000000E0ULL, 3868c2ecf20Sopenharmony_ci /* Write data */ 3878c2ecf20Sopenharmony_ci 0x80010515001E0004ULL, 0x80010515001E00E4ULL, 3888c2ecf20Sopenharmony_ci /* Set address */ 3898c2ecf20Sopenharmony_ci 0x8002051500000000ULL, 0x80020515000000E0ULL, 3908c2ecf20Sopenharmony_ci /* Write data */ 3918c2ecf20Sopenharmony_ci 0x80020515F2100004ULL, 0x80020515F21000E4ULL, 3928c2ecf20Sopenharmony_ci END_SIGN 3938c2ecf20Sopenharmony_ci}; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci/* 3968c2ecf20Sopenharmony_ci * Constants for Fixing the MacAddress problem seen mostly on 3978c2ecf20Sopenharmony_ci * Alpha machines. 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_cistatic const u64 fix_mac[] = { 4008c2ecf20Sopenharmony_ci 0x0060000000000000ULL, 0x0060600000000000ULL, 4018c2ecf20Sopenharmony_ci 0x0040600000000000ULL, 0x0000600000000000ULL, 4028c2ecf20Sopenharmony_ci 0x0020600000000000ULL, 0x0060600000000000ULL, 4038c2ecf20Sopenharmony_ci 0x0020600000000000ULL, 0x0060600000000000ULL, 4048c2ecf20Sopenharmony_ci 0x0020600000000000ULL, 0x0060600000000000ULL, 4058c2ecf20Sopenharmony_ci 0x0020600000000000ULL, 0x0060600000000000ULL, 4068c2ecf20Sopenharmony_ci 0x0020600000000000ULL, 0x0060600000000000ULL, 4078c2ecf20Sopenharmony_ci 0x0020600000000000ULL, 0x0060600000000000ULL, 4088c2ecf20Sopenharmony_ci 0x0020600000000000ULL, 0x0060600000000000ULL, 4098c2ecf20Sopenharmony_ci 0x0020600000000000ULL, 0x0060600000000000ULL, 4108c2ecf20Sopenharmony_ci 0x0020600000000000ULL, 0x0060600000000000ULL, 4118c2ecf20Sopenharmony_ci 0x0020600000000000ULL, 0x0060600000000000ULL, 4128c2ecf20Sopenharmony_ci 0x0020600000000000ULL, 0x0000600000000000ULL, 4138c2ecf20Sopenharmony_ci 0x0040600000000000ULL, 0x0060600000000000ULL, 4148c2ecf20Sopenharmony_ci END_SIGN 4158c2ecf20Sopenharmony_ci}; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4188c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci/* Module Loadable parameters. */ 4228c2ecf20Sopenharmony_ciS2IO_PARM_INT(tx_fifo_num, FIFO_DEFAULT_NUM); 4238c2ecf20Sopenharmony_ciS2IO_PARM_INT(rx_ring_num, 1); 4248c2ecf20Sopenharmony_ciS2IO_PARM_INT(multiq, 0); 4258c2ecf20Sopenharmony_ciS2IO_PARM_INT(rx_ring_mode, 1); 4268c2ecf20Sopenharmony_ciS2IO_PARM_INT(use_continuous_tx_intrs, 1); 4278c2ecf20Sopenharmony_ciS2IO_PARM_INT(rmac_pause_time, 0x100); 4288c2ecf20Sopenharmony_ciS2IO_PARM_INT(mc_pause_threshold_q0q3, 187); 4298c2ecf20Sopenharmony_ciS2IO_PARM_INT(mc_pause_threshold_q4q7, 187); 4308c2ecf20Sopenharmony_ciS2IO_PARM_INT(shared_splits, 0); 4318c2ecf20Sopenharmony_ciS2IO_PARM_INT(tmac_util_period, 5); 4328c2ecf20Sopenharmony_ciS2IO_PARM_INT(rmac_util_period, 5); 4338c2ecf20Sopenharmony_ciS2IO_PARM_INT(l3l4hdr_size, 128); 4348c2ecf20Sopenharmony_ci/* 0 is no steering, 1 is Priority steering, 2 is Default steering */ 4358c2ecf20Sopenharmony_ciS2IO_PARM_INT(tx_steering_type, TX_DEFAULT_STEERING); 4368c2ecf20Sopenharmony_ci/* Frequency of Rx desc syncs expressed as power of 2 */ 4378c2ecf20Sopenharmony_ciS2IO_PARM_INT(rxsync_frequency, 3); 4388c2ecf20Sopenharmony_ci/* Interrupt type. Values can be 0(INTA), 2(MSI_X) */ 4398c2ecf20Sopenharmony_ciS2IO_PARM_INT(intr_type, 2); 4408c2ecf20Sopenharmony_ci/* Large receive offload feature */ 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci/* Max pkts to be aggregated by LRO at one time. If not specified, 4438c2ecf20Sopenharmony_ci * aggregation happens until we hit max IP pkt size(64K) 4448c2ecf20Sopenharmony_ci */ 4458c2ecf20Sopenharmony_ciS2IO_PARM_INT(lro_max_pkts, 0xFFFF); 4468c2ecf20Sopenharmony_ciS2IO_PARM_INT(indicate_max_pkts, 0); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ciS2IO_PARM_INT(napi, 1); 4498c2ecf20Sopenharmony_ciS2IO_PARM_INT(vlan_tag_strip, NO_STRIP_IN_PROMISC); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic unsigned int tx_fifo_len[MAX_TX_FIFOS] = 4528c2ecf20Sopenharmony_ci{DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN}; 4538c2ecf20Sopenharmony_cistatic unsigned int rx_ring_sz[MAX_RX_RINGS] = 4548c2ecf20Sopenharmony_ci{[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT}; 4558c2ecf20Sopenharmony_cistatic unsigned int rts_frm_len[MAX_RX_RINGS] = 4568c2ecf20Sopenharmony_ci{[0 ...(MAX_RX_RINGS - 1)] = 0 }; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cimodule_param_array(tx_fifo_len, uint, NULL, 0); 4598c2ecf20Sopenharmony_cimodule_param_array(rx_ring_sz, uint, NULL, 0); 4608c2ecf20Sopenharmony_cimodule_param_array(rts_frm_len, uint, NULL, 0); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci/* 4638c2ecf20Sopenharmony_ci * S2IO device table. 4648c2ecf20Sopenharmony_ci * This table lists all the devices that this driver supports. 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_cistatic const struct pci_device_id s2io_tbl[] = { 4678c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN, 4688c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID}, 4698c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI, 4708c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID}, 4718c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN, 4728c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID}, 4738c2ecf20Sopenharmony_ci {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI, 4748c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID}, 4758c2ecf20Sopenharmony_ci {0,} 4768c2ecf20Sopenharmony_ci}; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, s2io_tbl); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic const struct pci_error_handlers s2io_err_handler = { 4818c2ecf20Sopenharmony_ci .error_detected = s2io_io_error_detected, 4828c2ecf20Sopenharmony_ci .slot_reset = s2io_io_slot_reset, 4838c2ecf20Sopenharmony_ci .resume = s2io_io_resume, 4848c2ecf20Sopenharmony_ci}; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic struct pci_driver s2io_driver = { 4878c2ecf20Sopenharmony_ci .name = "S2IO", 4888c2ecf20Sopenharmony_ci .id_table = s2io_tbl, 4898c2ecf20Sopenharmony_ci .probe = s2io_init_nic, 4908c2ecf20Sopenharmony_ci .remove = s2io_rem_nic, 4918c2ecf20Sopenharmony_ci .err_handler = &s2io_err_handler, 4928c2ecf20Sopenharmony_ci}; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/* A simplifier macro used both by init and free shared_mem Fns(). */ 4958c2ecf20Sopenharmony_ci#define TXD_MEM_PAGE_CNT(len, per_each) DIV_ROUND_UP(len, per_each) 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci/* netqueue manipulation helper functions */ 4988c2ecf20Sopenharmony_cistatic inline void s2io_stop_all_tx_queue(struct s2io_nic *sp) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci if (!sp->config.multiq) { 5018c2ecf20Sopenharmony_ci int i; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci for (i = 0; i < sp->config.tx_fifo_num; i++) 5048c2ecf20Sopenharmony_ci sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_STOP; 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(sp->dev); 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic inline void s2io_stop_tx_queue(struct s2io_nic *sp, int fifo_no) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci if (!sp->config.multiq) 5128c2ecf20Sopenharmony_ci sp->mac_control.fifos[fifo_no].queue_state = 5138c2ecf20Sopenharmony_ci FIFO_QUEUE_STOP; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci netif_tx_stop_all_queues(sp->dev); 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic inline void s2io_start_all_tx_queue(struct s2io_nic *sp) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci if (!sp->config.multiq) { 5218c2ecf20Sopenharmony_ci int i; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci for (i = 0; i < sp->config.tx_fifo_num; i++) 5248c2ecf20Sopenharmony_ci sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci netif_tx_start_all_queues(sp->dev); 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistatic inline void s2io_wake_all_tx_queue(struct s2io_nic *sp) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci if (!sp->config.multiq) { 5328c2ecf20Sopenharmony_ci int i; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci for (i = 0; i < sp->config.tx_fifo_num; i++) 5358c2ecf20Sopenharmony_ci sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(sp->dev); 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic inline void s2io_wake_tx_queue( 5418c2ecf20Sopenharmony_ci struct fifo_info *fifo, int cnt, u8 multiq) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci if (multiq) { 5458c2ecf20Sopenharmony_ci if (cnt && __netif_subqueue_stopped(fifo->dev, fifo->fifo_no)) 5468c2ecf20Sopenharmony_ci netif_wake_subqueue(fifo->dev, fifo->fifo_no); 5478c2ecf20Sopenharmony_ci } else if (cnt && (fifo->queue_state == FIFO_QUEUE_STOP)) { 5488c2ecf20Sopenharmony_ci if (netif_queue_stopped(fifo->dev)) { 5498c2ecf20Sopenharmony_ci fifo->queue_state = FIFO_QUEUE_START; 5508c2ecf20Sopenharmony_ci netif_wake_queue(fifo->dev); 5518c2ecf20Sopenharmony_ci } 5528c2ecf20Sopenharmony_ci } 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci/** 5568c2ecf20Sopenharmony_ci * init_shared_mem - Allocation and Initialization of Memory 5578c2ecf20Sopenharmony_ci * @nic: Device private variable. 5588c2ecf20Sopenharmony_ci * Description: The function allocates all the memory areas shared 5598c2ecf20Sopenharmony_ci * between the NIC and the driver. This includes Tx descriptors, 5608c2ecf20Sopenharmony_ci * Rx descriptors and the statistics block. 5618c2ecf20Sopenharmony_ci */ 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic int init_shared_mem(struct s2io_nic *nic) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci u32 size; 5668c2ecf20Sopenharmony_ci void *tmp_v_addr, *tmp_v_addr_next; 5678c2ecf20Sopenharmony_ci dma_addr_t tmp_p_addr, tmp_p_addr_next; 5688c2ecf20Sopenharmony_ci struct RxD_block *pre_rxd_blk = NULL; 5698c2ecf20Sopenharmony_ci int i, j, blk_cnt; 5708c2ecf20Sopenharmony_ci int lst_size, lst_per_page; 5718c2ecf20Sopenharmony_ci struct net_device *dev = nic->dev; 5728c2ecf20Sopenharmony_ci unsigned long tmp; 5738c2ecf20Sopenharmony_ci struct buffAdd *ba; 5748c2ecf20Sopenharmony_ci struct config_param *config = &nic->config; 5758c2ecf20Sopenharmony_ci struct mac_info *mac_control = &nic->mac_control; 5768c2ecf20Sopenharmony_ci unsigned long long mem_allocated = 0; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* Allocation and initialization of TXDLs in FIFOs */ 5798c2ecf20Sopenharmony_ci size = 0; 5808c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) { 5818c2ecf20Sopenharmony_ci struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci size += tx_cfg->fifo_len; 5848c2ecf20Sopenharmony_ci } 5858c2ecf20Sopenharmony_ci if (size > MAX_AVAILABLE_TXDS) { 5868c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 5878c2ecf20Sopenharmony_ci "Too many TxDs requested: %d, max supported: %d\n", 5888c2ecf20Sopenharmony_ci size, MAX_AVAILABLE_TXDS); 5898c2ecf20Sopenharmony_ci return -EINVAL; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci size = 0; 5938c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) { 5948c2ecf20Sopenharmony_ci struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci size = tx_cfg->fifo_len; 5978c2ecf20Sopenharmony_ci /* 5988c2ecf20Sopenharmony_ci * Legal values are from 2 to 8192 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ci if (size < 2) { 6018c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Fifo %d: Invalid length (%d) - " 6028c2ecf20Sopenharmony_ci "Valid lengths are 2 through 8192\n", 6038c2ecf20Sopenharmony_ci i, size); 6048c2ecf20Sopenharmony_ci return -EINVAL; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci lst_size = (sizeof(struct TxD) * config->max_txds); 6098c2ecf20Sopenharmony_ci lst_per_page = PAGE_SIZE / lst_size; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) { 6128c2ecf20Sopenharmony_ci struct fifo_info *fifo = &mac_control->fifos[i]; 6138c2ecf20Sopenharmony_ci struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; 6148c2ecf20Sopenharmony_ci int fifo_len = tx_cfg->fifo_len; 6158c2ecf20Sopenharmony_ci int list_holder_size = fifo_len * sizeof(struct list_info_hold); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci fifo->list_info = kzalloc(list_holder_size, GFP_KERNEL); 6188c2ecf20Sopenharmony_ci if (!fifo->list_info) { 6198c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "Malloc failed for list_info\n"); 6208c2ecf20Sopenharmony_ci return -ENOMEM; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci mem_allocated += list_holder_size; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) { 6258c2ecf20Sopenharmony_ci int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len, 6268c2ecf20Sopenharmony_ci lst_per_page); 6278c2ecf20Sopenharmony_ci struct fifo_info *fifo = &mac_control->fifos[i]; 6288c2ecf20Sopenharmony_ci struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci fifo->tx_curr_put_info.offset = 0; 6318c2ecf20Sopenharmony_ci fifo->tx_curr_put_info.fifo_len = tx_cfg->fifo_len - 1; 6328c2ecf20Sopenharmony_ci fifo->tx_curr_get_info.offset = 0; 6338c2ecf20Sopenharmony_ci fifo->tx_curr_get_info.fifo_len = tx_cfg->fifo_len - 1; 6348c2ecf20Sopenharmony_ci fifo->fifo_no = i; 6358c2ecf20Sopenharmony_ci fifo->nic = nic; 6368c2ecf20Sopenharmony_ci fifo->max_txds = MAX_SKB_FRAGS + 2; 6378c2ecf20Sopenharmony_ci fifo->dev = dev; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci for (j = 0; j < page_num; j++) { 6408c2ecf20Sopenharmony_ci int k = 0; 6418c2ecf20Sopenharmony_ci dma_addr_t tmp_p; 6428c2ecf20Sopenharmony_ci void *tmp_v; 6438c2ecf20Sopenharmony_ci tmp_v = dma_alloc_coherent(&nic->pdev->dev, PAGE_SIZE, 6448c2ecf20Sopenharmony_ci &tmp_p, GFP_KERNEL); 6458c2ecf20Sopenharmony_ci if (!tmp_v) { 6468c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, 6478c2ecf20Sopenharmony_ci "dma_alloc_coherent failed for TxDL\n"); 6488c2ecf20Sopenharmony_ci return -ENOMEM; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci /* If we got a zero DMA address(can happen on 6518c2ecf20Sopenharmony_ci * certain platforms like PPC), reallocate. 6528c2ecf20Sopenharmony_ci * Store virtual address of page we don't want, 6538c2ecf20Sopenharmony_ci * to be freed later. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ci if (!tmp_p) { 6568c2ecf20Sopenharmony_ci mac_control->zerodma_virt_addr = tmp_v; 6578c2ecf20Sopenharmony_ci DBG_PRINT(INIT_DBG, 6588c2ecf20Sopenharmony_ci "%s: Zero DMA address for TxDL. " 6598c2ecf20Sopenharmony_ci "Virtual address %p\n", 6608c2ecf20Sopenharmony_ci dev->name, tmp_v); 6618c2ecf20Sopenharmony_ci tmp_v = dma_alloc_coherent(&nic->pdev->dev, 6628c2ecf20Sopenharmony_ci PAGE_SIZE, &tmp_p, 6638c2ecf20Sopenharmony_ci GFP_KERNEL); 6648c2ecf20Sopenharmony_ci if (!tmp_v) { 6658c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, 6668c2ecf20Sopenharmony_ci "dma_alloc_coherent failed for TxDL\n"); 6678c2ecf20Sopenharmony_ci return -ENOMEM; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci mem_allocated += PAGE_SIZE; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci while (k < lst_per_page) { 6728c2ecf20Sopenharmony_ci int l = (j * lst_per_page) + k; 6738c2ecf20Sopenharmony_ci if (l == tx_cfg->fifo_len) 6748c2ecf20Sopenharmony_ci break; 6758c2ecf20Sopenharmony_ci fifo->list_info[l].list_virt_addr = 6768c2ecf20Sopenharmony_ci tmp_v + (k * lst_size); 6778c2ecf20Sopenharmony_ci fifo->list_info[l].list_phy_addr = 6788c2ecf20Sopenharmony_ci tmp_p + (k * lst_size); 6798c2ecf20Sopenharmony_ci k++; 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) { 6858c2ecf20Sopenharmony_ci struct fifo_info *fifo = &mac_control->fifos[i]; 6868c2ecf20Sopenharmony_ci struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci size = tx_cfg->fifo_len; 6898c2ecf20Sopenharmony_ci fifo->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL); 6908c2ecf20Sopenharmony_ci if (!fifo->ufo_in_band_v) 6918c2ecf20Sopenharmony_ci return -ENOMEM; 6928c2ecf20Sopenharmony_ci mem_allocated += (size * sizeof(u64)); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* Allocation and initialization of RXDs in Rings */ 6968c2ecf20Sopenharmony_ci size = 0; 6978c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 6988c2ecf20Sopenharmony_ci struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; 6998c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (rx_cfg->num_rxd % (rxd_count[nic->rxd_mode] + 1)) { 7028c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Ring%d RxD count is not a " 7038c2ecf20Sopenharmony_ci "multiple of RxDs per Block\n", 7048c2ecf20Sopenharmony_ci dev->name, i); 7058c2ecf20Sopenharmony_ci return FAILURE; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci size += rx_cfg->num_rxd; 7088c2ecf20Sopenharmony_ci ring->block_count = rx_cfg->num_rxd / 7098c2ecf20Sopenharmony_ci (rxd_count[nic->rxd_mode] + 1); 7108c2ecf20Sopenharmony_ci ring->pkt_cnt = rx_cfg->num_rxd - ring->block_count; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci if (nic->rxd_mode == RXD_MODE_1) 7138c2ecf20Sopenharmony_ci size = (size * (sizeof(struct RxD1))); 7148c2ecf20Sopenharmony_ci else 7158c2ecf20Sopenharmony_ci size = (size * (sizeof(struct RxD3))); 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 7188c2ecf20Sopenharmony_ci struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; 7198c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci ring->rx_curr_get_info.block_index = 0; 7228c2ecf20Sopenharmony_ci ring->rx_curr_get_info.offset = 0; 7238c2ecf20Sopenharmony_ci ring->rx_curr_get_info.ring_len = rx_cfg->num_rxd - 1; 7248c2ecf20Sopenharmony_ci ring->rx_curr_put_info.block_index = 0; 7258c2ecf20Sopenharmony_ci ring->rx_curr_put_info.offset = 0; 7268c2ecf20Sopenharmony_ci ring->rx_curr_put_info.ring_len = rx_cfg->num_rxd - 1; 7278c2ecf20Sopenharmony_ci ring->nic = nic; 7288c2ecf20Sopenharmony_ci ring->ring_no = i; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci blk_cnt = rx_cfg->num_rxd / (rxd_count[nic->rxd_mode] + 1); 7318c2ecf20Sopenharmony_ci /* Allocating all the Rx blocks */ 7328c2ecf20Sopenharmony_ci for (j = 0; j < blk_cnt; j++) { 7338c2ecf20Sopenharmony_ci struct rx_block_info *rx_blocks; 7348c2ecf20Sopenharmony_ci int l; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci rx_blocks = &ring->rx_blocks[j]; 7378c2ecf20Sopenharmony_ci size = SIZE_OF_BLOCK; /* size is always page size */ 7388c2ecf20Sopenharmony_ci tmp_v_addr = dma_alloc_coherent(&nic->pdev->dev, size, 7398c2ecf20Sopenharmony_ci &tmp_p_addr, GFP_KERNEL); 7408c2ecf20Sopenharmony_ci if (tmp_v_addr == NULL) { 7418c2ecf20Sopenharmony_ci /* 7428c2ecf20Sopenharmony_ci * In case of failure, free_shared_mem() 7438c2ecf20Sopenharmony_ci * is called, which should free any 7448c2ecf20Sopenharmony_ci * memory that was alloced till the 7458c2ecf20Sopenharmony_ci * failure happened. 7468c2ecf20Sopenharmony_ci */ 7478c2ecf20Sopenharmony_ci rx_blocks->block_virt_addr = tmp_v_addr; 7488c2ecf20Sopenharmony_ci return -ENOMEM; 7498c2ecf20Sopenharmony_ci } 7508c2ecf20Sopenharmony_ci mem_allocated += size; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci size = sizeof(struct rxd_info) * 7538c2ecf20Sopenharmony_ci rxd_count[nic->rxd_mode]; 7548c2ecf20Sopenharmony_ci rx_blocks->block_virt_addr = tmp_v_addr; 7558c2ecf20Sopenharmony_ci rx_blocks->block_dma_addr = tmp_p_addr; 7568c2ecf20Sopenharmony_ci rx_blocks->rxds = kmalloc(size, GFP_KERNEL); 7578c2ecf20Sopenharmony_ci if (!rx_blocks->rxds) 7588c2ecf20Sopenharmony_ci return -ENOMEM; 7598c2ecf20Sopenharmony_ci mem_allocated += size; 7608c2ecf20Sopenharmony_ci for (l = 0; l < rxd_count[nic->rxd_mode]; l++) { 7618c2ecf20Sopenharmony_ci rx_blocks->rxds[l].virt_addr = 7628c2ecf20Sopenharmony_ci rx_blocks->block_virt_addr + 7638c2ecf20Sopenharmony_ci (rxd_size[nic->rxd_mode] * l); 7648c2ecf20Sopenharmony_ci rx_blocks->rxds[l].dma_addr = 7658c2ecf20Sopenharmony_ci rx_blocks->block_dma_addr + 7668c2ecf20Sopenharmony_ci (rxd_size[nic->rxd_mode] * l); 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci } 7698c2ecf20Sopenharmony_ci /* Interlinking all Rx Blocks */ 7708c2ecf20Sopenharmony_ci for (j = 0; j < blk_cnt; j++) { 7718c2ecf20Sopenharmony_ci int next = (j + 1) % blk_cnt; 7728c2ecf20Sopenharmony_ci tmp_v_addr = ring->rx_blocks[j].block_virt_addr; 7738c2ecf20Sopenharmony_ci tmp_v_addr_next = ring->rx_blocks[next].block_virt_addr; 7748c2ecf20Sopenharmony_ci tmp_p_addr = ring->rx_blocks[j].block_dma_addr; 7758c2ecf20Sopenharmony_ci tmp_p_addr_next = ring->rx_blocks[next].block_dma_addr; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci pre_rxd_blk = tmp_v_addr; 7788c2ecf20Sopenharmony_ci pre_rxd_blk->reserved_2_pNext_RxD_block = 7798c2ecf20Sopenharmony_ci (unsigned long)tmp_v_addr_next; 7808c2ecf20Sopenharmony_ci pre_rxd_blk->pNext_RxD_Blk_physical = 7818c2ecf20Sopenharmony_ci (u64)tmp_p_addr_next; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci if (nic->rxd_mode == RXD_MODE_3B) { 7858c2ecf20Sopenharmony_ci /* 7868c2ecf20Sopenharmony_ci * Allocation of Storages for buffer addresses in 2BUFF mode 7878c2ecf20Sopenharmony_ci * and the buffers as well. 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 7908c2ecf20Sopenharmony_ci struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; 7918c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci blk_cnt = rx_cfg->num_rxd / 7948c2ecf20Sopenharmony_ci (rxd_count[nic->rxd_mode] + 1); 7958c2ecf20Sopenharmony_ci size = sizeof(struct buffAdd *) * blk_cnt; 7968c2ecf20Sopenharmony_ci ring->ba = kmalloc(size, GFP_KERNEL); 7978c2ecf20Sopenharmony_ci if (!ring->ba) 7988c2ecf20Sopenharmony_ci return -ENOMEM; 7998c2ecf20Sopenharmony_ci mem_allocated += size; 8008c2ecf20Sopenharmony_ci for (j = 0; j < blk_cnt; j++) { 8018c2ecf20Sopenharmony_ci int k = 0; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci size = sizeof(struct buffAdd) * 8048c2ecf20Sopenharmony_ci (rxd_count[nic->rxd_mode] + 1); 8058c2ecf20Sopenharmony_ci ring->ba[j] = kmalloc(size, GFP_KERNEL); 8068c2ecf20Sopenharmony_ci if (!ring->ba[j]) 8078c2ecf20Sopenharmony_ci return -ENOMEM; 8088c2ecf20Sopenharmony_ci mem_allocated += size; 8098c2ecf20Sopenharmony_ci while (k != rxd_count[nic->rxd_mode]) { 8108c2ecf20Sopenharmony_ci ba = &ring->ba[j][k]; 8118c2ecf20Sopenharmony_ci size = BUF0_LEN + ALIGN_SIZE; 8128c2ecf20Sopenharmony_ci ba->ba_0_org = kmalloc(size, GFP_KERNEL); 8138c2ecf20Sopenharmony_ci if (!ba->ba_0_org) 8148c2ecf20Sopenharmony_ci return -ENOMEM; 8158c2ecf20Sopenharmony_ci mem_allocated += size; 8168c2ecf20Sopenharmony_ci tmp = (unsigned long)ba->ba_0_org; 8178c2ecf20Sopenharmony_ci tmp += ALIGN_SIZE; 8188c2ecf20Sopenharmony_ci tmp &= ~((unsigned long)ALIGN_SIZE); 8198c2ecf20Sopenharmony_ci ba->ba_0 = (void *)tmp; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci size = BUF1_LEN + ALIGN_SIZE; 8228c2ecf20Sopenharmony_ci ba->ba_1_org = kmalloc(size, GFP_KERNEL); 8238c2ecf20Sopenharmony_ci if (!ba->ba_1_org) 8248c2ecf20Sopenharmony_ci return -ENOMEM; 8258c2ecf20Sopenharmony_ci mem_allocated += size; 8268c2ecf20Sopenharmony_ci tmp = (unsigned long)ba->ba_1_org; 8278c2ecf20Sopenharmony_ci tmp += ALIGN_SIZE; 8288c2ecf20Sopenharmony_ci tmp &= ~((unsigned long)ALIGN_SIZE); 8298c2ecf20Sopenharmony_ci ba->ba_1 = (void *)tmp; 8308c2ecf20Sopenharmony_ci k++; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci } 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci /* Allocation and initialization of Statistics block */ 8378c2ecf20Sopenharmony_ci size = sizeof(struct stat_block); 8388c2ecf20Sopenharmony_ci mac_control->stats_mem = 8398c2ecf20Sopenharmony_ci dma_alloc_coherent(&nic->pdev->dev, size, 8408c2ecf20Sopenharmony_ci &mac_control->stats_mem_phy, GFP_KERNEL); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (!mac_control->stats_mem) { 8438c2ecf20Sopenharmony_ci /* 8448c2ecf20Sopenharmony_ci * In case of failure, free_shared_mem() is called, which 8458c2ecf20Sopenharmony_ci * should free any memory that was alloced till the 8468c2ecf20Sopenharmony_ci * failure happened. 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_ci return -ENOMEM; 8498c2ecf20Sopenharmony_ci } 8508c2ecf20Sopenharmony_ci mem_allocated += size; 8518c2ecf20Sopenharmony_ci mac_control->stats_mem_sz = size; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci tmp_v_addr = mac_control->stats_mem; 8548c2ecf20Sopenharmony_ci mac_control->stats_info = tmp_v_addr; 8558c2ecf20Sopenharmony_ci memset(tmp_v_addr, 0, size); 8568c2ecf20Sopenharmony_ci DBG_PRINT(INIT_DBG, "%s: Ring Mem PHY: 0x%llx\n", 8578c2ecf20Sopenharmony_ci dev_name(&nic->pdev->dev), (unsigned long long)tmp_p_addr); 8588c2ecf20Sopenharmony_ci mac_control->stats_info->sw_stat.mem_allocated += mem_allocated; 8598c2ecf20Sopenharmony_ci return SUCCESS; 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci/** 8638c2ecf20Sopenharmony_ci * free_shared_mem - Free the allocated Memory 8648c2ecf20Sopenharmony_ci * @nic: Device private variable. 8658c2ecf20Sopenharmony_ci * Description: This function is to free all memory locations allocated by 8668c2ecf20Sopenharmony_ci * the init_shared_mem() function and return it to the kernel. 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_cistatic void free_shared_mem(struct s2io_nic *nic) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci int i, j, blk_cnt, size; 8728c2ecf20Sopenharmony_ci void *tmp_v_addr; 8738c2ecf20Sopenharmony_ci dma_addr_t tmp_p_addr; 8748c2ecf20Sopenharmony_ci int lst_size, lst_per_page; 8758c2ecf20Sopenharmony_ci struct net_device *dev; 8768c2ecf20Sopenharmony_ci int page_num = 0; 8778c2ecf20Sopenharmony_ci struct config_param *config; 8788c2ecf20Sopenharmony_ci struct mac_info *mac_control; 8798c2ecf20Sopenharmony_ci struct stat_block *stats; 8808c2ecf20Sopenharmony_ci struct swStat *swstats; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if (!nic) 8838c2ecf20Sopenharmony_ci return; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci dev = nic->dev; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci config = &nic->config; 8888c2ecf20Sopenharmony_ci mac_control = &nic->mac_control; 8898c2ecf20Sopenharmony_ci stats = mac_control->stats_info; 8908c2ecf20Sopenharmony_ci swstats = &stats->sw_stat; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci lst_size = sizeof(struct TxD) * config->max_txds; 8938c2ecf20Sopenharmony_ci lst_per_page = PAGE_SIZE / lst_size; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) { 8968c2ecf20Sopenharmony_ci struct fifo_info *fifo = &mac_control->fifos[i]; 8978c2ecf20Sopenharmony_ci struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci page_num = TXD_MEM_PAGE_CNT(tx_cfg->fifo_len, lst_per_page); 9008c2ecf20Sopenharmony_ci for (j = 0; j < page_num; j++) { 9018c2ecf20Sopenharmony_ci int mem_blks = (j * lst_per_page); 9028c2ecf20Sopenharmony_ci struct list_info_hold *fli; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (!fifo->list_info) 9058c2ecf20Sopenharmony_ci return; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci fli = &fifo->list_info[mem_blks]; 9088c2ecf20Sopenharmony_ci if (!fli->list_virt_addr) 9098c2ecf20Sopenharmony_ci break; 9108c2ecf20Sopenharmony_ci dma_free_coherent(&nic->pdev->dev, PAGE_SIZE, 9118c2ecf20Sopenharmony_ci fli->list_virt_addr, 9128c2ecf20Sopenharmony_ci fli->list_phy_addr); 9138c2ecf20Sopenharmony_ci swstats->mem_freed += PAGE_SIZE; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci /* If we got a zero DMA address during allocation, 9168c2ecf20Sopenharmony_ci * free the page now 9178c2ecf20Sopenharmony_ci */ 9188c2ecf20Sopenharmony_ci if (mac_control->zerodma_virt_addr) { 9198c2ecf20Sopenharmony_ci dma_free_coherent(&nic->pdev->dev, PAGE_SIZE, 9208c2ecf20Sopenharmony_ci mac_control->zerodma_virt_addr, 9218c2ecf20Sopenharmony_ci (dma_addr_t)0); 9228c2ecf20Sopenharmony_ci DBG_PRINT(INIT_DBG, 9238c2ecf20Sopenharmony_ci "%s: Freeing TxDL with zero DMA address. " 9248c2ecf20Sopenharmony_ci "Virtual address %p\n", 9258c2ecf20Sopenharmony_ci dev->name, mac_control->zerodma_virt_addr); 9268c2ecf20Sopenharmony_ci swstats->mem_freed += PAGE_SIZE; 9278c2ecf20Sopenharmony_ci } 9288c2ecf20Sopenharmony_ci kfree(fifo->list_info); 9298c2ecf20Sopenharmony_ci swstats->mem_freed += tx_cfg->fifo_len * 9308c2ecf20Sopenharmony_ci sizeof(struct list_info_hold); 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci size = SIZE_OF_BLOCK; 9348c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 9358c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci blk_cnt = ring->block_count; 9388c2ecf20Sopenharmony_ci for (j = 0; j < blk_cnt; j++) { 9398c2ecf20Sopenharmony_ci tmp_v_addr = ring->rx_blocks[j].block_virt_addr; 9408c2ecf20Sopenharmony_ci tmp_p_addr = ring->rx_blocks[j].block_dma_addr; 9418c2ecf20Sopenharmony_ci if (tmp_v_addr == NULL) 9428c2ecf20Sopenharmony_ci break; 9438c2ecf20Sopenharmony_ci dma_free_coherent(&nic->pdev->dev, size, tmp_v_addr, 9448c2ecf20Sopenharmony_ci tmp_p_addr); 9458c2ecf20Sopenharmony_ci swstats->mem_freed += size; 9468c2ecf20Sopenharmony_ci kfree(ring->rx_blocks[j].rxds); 9478c2ecf20Sopenharmony_ci swstats->mem_freed += sizeof(struct rxd_info) * 9488c2ecf20Sopenharmony_ci rxd_count[nic->rxd_mode]; 9498c2ecf20Sopenharmony_ci } 9508c2ecf20Sopenharmony_ci } 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (nic->rxd_mode == RXD_MODE_3B) { 9538c2ecf20Sopenharmony_ci /* Freeing buffer storage addresses in 2BUFF mode. */ 9548c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 9558c2ecf20Sopenharmony_ci struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; 9568c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci blk_cnt = rx_cfg->num_rxd / 9598c2ecf20Sopenharmony_ci (rxd_count[nic->rxd_mode] + 1); 9608c2ecf20Sopenharmony_ci for (j = 0; j < blk_cnt; j++) { 9618c2ecf20Sopenharmony_ci int k = 0; 9628c2ecf20Sopenharmony_ci if (!ring->ba[j]) 9638c2ecf20Sopenharmony_ci continue; 9648c2ecf20Sopenharmony_ci while (k != rxd_count[nic->rxd_mode]) { 9658c2ecf20Sopenharmony_ci struct buffAdd *ba = &ring->ba[j][k]; 9668c2ecf20Sopenharmony_ci kfree(ba->ba_0_org); 9678c2ecf20Sopenharmony_ci swstats->mem_freed += 9688c2ecf20Sopenharmony_ci BUF0_LEN + ALIGN_SIZE; 9698c2ecf20Sopenharmony_ci kfree(ba->ba_1_org); 9708c2ecf20Sopenharmony_ci swstats->mem_freed += 9718c2ecf20Sopenharmony_ci BUF1_LEN + ALIGN_SIZE; 9728c2ecf20Sopenharmony_ci k++; 9738c2ecf20Sopenharmony_ci } 9748c2ecf20Sopenharmony_ci kfree(ring->ba[j]); 9758c2ecf20Sopenharmony_ci swstats->mem_freed += sizeof(struct buffAdd) * 9768c2ecf20Sopenharmony_ci (rxd_count[nic->rxd_mode] + 1); 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci kfree(ring->ba); 9798c2ecf20Sopenharmony_ci swstats->mem_freed += sizeof(struct buffAdd *) * 9808c2ecf20Sopenharmony_ci blk_cnt; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci for (i = 0; i < nic->config.tx_fifo_num; i++) { 9858c2ecf20Sopenharmony_ci struct fifo_info *fifo = &mac_control->fifos[i]; 9868c2ecf20Sopenharmony_ci struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci if (fifo->ufo_in_band_v) { 9898c2ecf20Sopenharmony_ci swstats->mem_freed += tx_cfg->fifo_len * 9908c2ecf20Sopenharmony_ci sizeof(u64); 9918c2ecf20Sopenharmony_ci kfree(fifo->ufo_in_band_v); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci } 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci if (mac_control->stats_mem) { 9968c2ecf20Sopenharmony_ci swstats->mem_freed += mac_control->stats_mem_sz; 9978c2ecf20Sopenharmony_ci dma_free_coherent(&nic->pdev->dev, mac_control->stats_mem_sz, 9988c2ecf20Sopenharmony_ci mac_control->stats_mem, 9998c2ecf20Sopenharmony_ci mac_control->stats_mem_phy); 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci/* 10048c2ecf20Sopenharmony_ci * s2io_verify_pci_mode - 10058c2ecf20Sopenharmony_ci */ 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cistatic int s2io_verify_pci_mode(struct s2io_nic *nic) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 10108c2ecf20Sopenharmony_ci register u64 val64 = 0; 10118c2ecf20Sopenharmony_ci int mode; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci val64 = readq(&bar0->pci_mode); 10148c2ecf20Sopenharmony_ci mode = (u8)GET_PCI_MODE(val64); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (val64 & PCI_MODE_UNKNOWN_MODE) 10178c2ecf20Sopenharmony_ci return -1; /* Unknown PCI mode */ 10188c2ecf20Sopenharmony_ci return mode; 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci#define NEC_VENID 0x1033 10228c2ecf20Sopenharmony_ci#define NEC_DEVID 0x0125 10238c2ecf20Sopenharmony_cistatic int s2io_on_nec_bridge(struct pci_dev *s2io_pdev) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci struct pci_dev *tdev = NULL; 10268c2ecf20Sopenharmony_ci for_each_pci_dev(tdev) { 10278c2ecf20Sopenharmony_ci if (tdev->vendor == NEC_VENID && tdev->device == NEC_DEVID) { 10288c2ecf20Sopenharmony_ci if (tdev->bus == s2io_pdev->bus->parent) { 10298c2ecf20Sopenharmony_ci pci_dev_put(tdev); 10308c2ecf20Sopenharmony_ci return 1; 10318c2ecf20Sopenharmony_ci } 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci } 10348c2ecf20Sopenharmony_ci return 0; 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_cistatic int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266}; 10388c2ecf20Sopenharmony_ci/* 10398c2ecf20Sopenharmony_ci * s2io_print_pci_mode - 10408c2ecf20Sopenharmony_ci */ 10418c2ecf20Sopenharmony_cistatic int s2io_print_pci_mode(struct s2io_nic *nic) 10428c2ecf20Sopenharmony_ci{ 10438c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 10448c2ecf20Sopenharmony_ci register u64 val64 = 0; 10458c2ecf20Sopenharmony_ci int mode; 10468c2ecf20Sopenharmony_ci struct config_param *config = &nic->config; 10478c2ecf20Sopenharmony_ci const char *pcimode; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci val64 = readq(&bar0->pci_mode); 10508c2ecf20Sopenharmony_ci mode = (u8)GET_PCI_MODE(val64); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci if (val64 & PCI_MODE_UNKNOWN_MODE) 10538c2ecf20Sopenharmony_ci return -1; /* Unknown PCI mode */ 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci config->bus_speed = bus_speed[mode]; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci if (s2io_on_nec_bridge(nic->pdev)) { 10588c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Device is on PCI-E bus\n", 10598c2ecf20Sopenharmony_ci nic->dev->name); 10608c2ecf20Sopenharmony_ci return mode; 10618c2ecf20Sopenharmony_ci } 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci switch (mode) { 10648c2ecf20Sopenharmony_ci case PCI_MODE_PCI_33: 10658c2ecf20Sopenharmony_ci pcimode = "33MHz PCI bus"; 10668c2ecf20Sopenharmony_ci break; 10678c2ecf20Sopenharmony_ci case PCI_MODE_PCI_66: 10688c2ecf20Sopenharmony_ci pcimode = "66MHz PCI bus"; 10698c2ecf20Sopenharmony_ci break; 10708c2ecf20Sopenharmony_ci case PCI_MODE_PCIX_M1_66: 10718c2ecf20Sopenharmony_ci pcimode = "66MHz PCIX(M1) bus"; 10728c2ecf20Sopenharmony_ci break; 10738c2ecf20Sopenharmony_ci case PCI_MODE_PCIX_M1_100: 10748c2ecf20Sopenharmony_ci pcimode = "100MHz PCIX(M1) bus"; 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci case PCI_MODE_PCIX_M1_133: 10778c2ecf20Sopenharmony_ci pcimode = "133MHz PCIX(M1) bus"; 10788c2ecf20Sopenharmony_ci break; 10798c2ecf20Sopenharmony_ci case PCI_MODE_PCIX_M2_66: 10808c2ecf20Sopenharmony_ci pcimode = "133MHz PCIX(M2) bus"; 10818c2ecf20Sopenharmony_ci break; 10828c2ecf20Sopenharmony_ci case PCI_MODE_PCIX_M2_100: 10838c2ecf20Sopenharmony_ci pcimode = "200MHz PCIX(M2) bus"; 10848c2ecf20Sopenharmony_ci break; 10858c2ecf20Sopenharmony_ci case PCI_MODE_PCIX_M2_133: 10868c2ecf20Sopenharmony_ci pcimode = "266MHz PCIX(M2) bus"; 10878c2ecf20Sopenharmony_ci break; 10888c2ecf20Sopenharmony_ci default: 10898c2ecf20Sopenharmony_ci pcimode = "unsupported bus!"; 10908c2ecf20Sopenharmony_ci mode = -1; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Device is on %d bit %s\n", 10948c2ecf20Sopenharmony_ci nic->dev->name, val64 & PCI_MODE_32_BITS ? 32 : 64, pcimode); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci return mode; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci/** 11008c2ecf20Sopenharmony_ci * init_tti - Initialization transmit traffic interrupt scheme 11018c2ecf20Sopenharmony_ci * @nic: device private variable 11028c2ecf20Sopenharmony_ci * @link: link status (UP/DOWN) used to enable/disable continuous 11038c2ecf20Sopenharmony_ci * transmit interrupts 11048c2ecf20Sopenharmony_ci * Description: The function configures transmit traffic interrupts 11058c2ecf20Sopenharmony_ci * Return Value: SUCCESS on success and 11068c2ecf20Sopenharmony_ci * '-1' on failure 11078c2ecf20Sopenharmony_ci */ 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic int init_tti(struct s2io_nic *nic, int link) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 11128c2ecf20Sopenharmony_ci register u64 val64 = 0; 11138c2ecf20Sopenharmony_ci int i; 11148c2ecf20Sopenharmony_ci struct config_param *config = &nic->config; 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) { 11178c2ecf20Sopenharmony_ci /* 11188c2ecf20Sopenharmony_ci * TTI Initialization. Default Tx timer gets us about 11198c2ecf20Sopenharmony_ci * 250 interrupts per sec. Continuous interrupts are enabled 11208c2ecf20Sopenharmony_ci * by default. 11218c2ecf20Sopenharmony_ci */ 11228c2ecf20Sopenharmony_ci if (nic->device_type == XFRAME_II_DEVICE) { 11238c2ecf20Sopenharmony_ci int count = (nic->config.bus_speed * 125)/2; 11248c2ecf20Sopenharmony_ci val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count); 11258c2ecf20Sopenharmony_ci } else 11268c2ecf20Sopenharmony_ci val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) | 11298c2ecf20Sopenharmony_ci TTI_DATA1_MEM_TX_URNG_B(0x10) | 11308c2ecf20Sopenharmony_ci TTI_DATA1_MEM_TX_URNG_C(0x30) | 11318c2ecf20Sopenharmony_ci TTI_DATA1_MEM_TX_TIMER_AC_EN; 11328c2ecf20Sopenharmony_ci if (i == 0) 11338c2ecf20Sopenharmony_ci if (use_continuous_tx_intrs && (link == LINK_UP)) 11348c2ecf20Sopenharmony_ci val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN; 11358c2ecf20Sopenharmony_ci writeq(val64, &bar0->tti_data1_mem); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci if (nic->config.intr_type == MSI_X) { 11388c2ecf20Sopenharmony_ci val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) | 11398c2ecf20Sopenharmony_ci TTI_DATA2_MEM_TX_UFC_B(0x100) | 11408c2ecf20Sopenharmony_ci TTI_DATA2_MEM_TX_UFC_C(0x200) | 11418c2ecf20Sopenharmony_ci TTI_DATA2_MEM_TX_UFC_D(0x300); 11428c2ecf20Sopenharmony_ci } else { 11438c2ecf20Sopenharmony_ci if ((nic->config.tx_steering_type == 11448c2ecf20Sopenharmony_ci TX_DEFAULT_STEERING) && 11458c2ecf20Sopenharmony_ci (config->tx_fifo_num > 1) && 11468c2ecf20Sopenharmony_ci (i >= nic->udp_fifo_idx) && 11478c2ecf20Sopenharmony_ci (i < (nic->udp_fifo_idx + 11488c2ecf20Sopenharmony_ci nic->total_udp_fifos))) 11498c2ecf20Sopenharmony_ci val64 = TTI_DATA2_MEM_TX_UFC_A(0x50) | 11508c2ecf20Sopenharmony_ci TTI_DATA2_MEM_TX_UFC_B(0x80) | 11518c2ecf20Sopenharmony_ci TTI_DATA2_MEM_TX_UFC_C(0x100) | 11528c2ecf20Sopenharmony_ci TTI_DATA2_MEM_TX_UFC_D(0x120); 11538c2ecf20Sopenharmony_ci else 11548c2ecf20Sopenharmony_ci val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) | 11558c2ecf20Sopenharmony_ci TTI_DATA2_MEM_TX_UFC_B(0x20) | 11568c2ecf20Sopenharmony_ci TTI_DATA2_MEM_TX_UFC_C(0x40) | 11578c2ecf20Sopenharmony_ci TTI_DATA2_MEM_TX_UFC_D(0x80); 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci writeq(val64, &bar0->tti_data2_mem); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci val64 = TTI_CMD_MEM_WE | 11638c2ecf20Sopenharmony_ci TTI_CMD_MEM_STROBE_NEW_CMD | 11648c2ecf20Sopenharmony_ci TTI_CMD_MEM_OFFSET(i); 11658c2ecf20Sopenharmony_ci writeq(val64, &bar0->tti_command_mem); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci if (wait_for_cmd_complete(&bar0->tti_command_mem, 11688c2ecf20Sopenharmony_ci TTI_CMD_MEM_STROBE_NEW_CMD, 11698c2ecf20Sopenharmony_ci S2IO_BIT_RESET) != SUCCESS) 11708c2ecf20Sopenharmony_ci return FAILURE; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci return SUCCESS; 11748c2ecf20Sopenharmony_ci} 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci/** 11778c2ecf20Sopenharmony_ci * init_nic - Initialization of hardware 11788c2ecf20Sopenharmony_ci * @nic: device private variable 11798c2ecf20Sopenharmony_ci * Description: The function sequentially configures every block 11808c2ecf20Sopenharmony_ci * of the H/W from their reset values. 11818c2ecf20Sopenharmony_ci * Return Value: SUCCESS on success and 11828c2ecf20Sopenharmony_ci * '-1' on failure (endian settings incorrect). 11838c2ecf20Sopenharmony_ci */ 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_cistatic int init_nic(struct s2io_nic *nic) 11868c2ecf20Sopenharmony_ci{ 11878c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 11888c2ecf20Sopenharmony_ci struct net_device *dev = nic->dev; 11898c2ecf20Sopenharmony_ci register u64 val64 = 0; 11908c2ecf20Sopenharmony_ci void __iomem *add; 11918c2ecf20Sopenharmony_ci u32 time; 11928c2ecf20Sopenharmony_ci int i, j; 11938c2ecf20Sopenharmony_ci int dtx_cnt = 0; 11948c2ecf20Sopenharmony_ci unsigned long long mem_share; 11958c2ecf20Sopenharmony_ci int mem_size; 11968c2ecf20Sopenharmony_ci struct config_param *config = &nic->config; 11978c2ecf20Sopenharmony_ci struct mac_info *mac_control = &nic->mac_control; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* to set the swapper controle on the card */ 12008c2ecf20Sopenharmony_ci if (s2io_set_swapper(nic)) { 12018c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "ERROR: Setting Swapper failed\n"); 12028c2ecf20Sopenharmony_ci return -EIO; 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci /* 12068c2ecf20Sopenharmony_ci * Herc requires EOI to be removed from reset before XGXS, so.. 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_ci if (nic->device_type & XFRAME_II_DEVICE) { 12098c2ecf20Sopenharmony_ci val64 = 0xA500000000ULL; 12108c2ecf20Sopenharmony_ci writeq(val64, &bar0->sw_reset); 12118c2ecf20Sopenharmony_ci msleep(500); 12128c2ecf20Sopenharmony_ci val64 = readq(&bar0->sw_reset); 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci /* Remove XGXS from reset state */ 12168c2ecf20Sopenharmony_ci val64 = 0; 12178c2ecf20Sopenharmony_ci writeq(val64, &bar0->sw_reset); 12188c2ecf20Sopenharmony_ci msleep(500); 12198c2ecf20Sopenharmony_ci val64 = readq(&bar0->sw_reset); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci /* Ensure that it's safe to access registers by checking 12228c2ecf20Sopenharmony_ci * RIC_RUNNING bit is reset. Check is valid only for XframeII. 12238c2ecf20Sopenharmony_ci */ 12248c2ecf20Sopenharmony_ci if (nic->device_type == XFRAME_II_DEVICE) { 12258c2ecf20Sopenharmony_ci for (i = 0; i < 50; i++) { 12268c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_status); 12278c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_RIC_RUNNING)) 12288c2ecf20Sopenharmony_ci break; 12298c2ecf20Sopenharmony_ci msleep(10); 12308c2ecf20Sopenharmony_ci } 12318c2ecf20Sopenharmony_ci if (i == 50) 12328c2ecf20Sopenharmony_ci return -ENODEV; 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci /* Enable Receiving broadcasts */ 12368c2ecf20Sopenharmony_ci add = &bar0->mac_cfg; 12378c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_cfg); 12388c2ecf20Sopenharmony_ci val64 |= MAC_RMAC_BCAST_ENABLE; 12398c2ecf20Sopenharmony_ci writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); 12408c2ecf20Sopenharmony_ci writel((u32)val64, add); 12418c2ecf20Sopenharmony_ci writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); 12428c2ecf20Sopenharmony_ci writel((u32) (val64 >> 32), (add + 4)); 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci /* Read registers in all blocks */ 12458c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_int_mask); 12468c2ecf20Sopenharmony_ci val64 = readq(&bar0->mc_int_mask); 12478c2ecf20Sopenharmony_ci val64 = readq(&bar0->xgxs_int_mask); 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci /* Set MTU */ 12508c2ecf20Sopenharmony_ci val64 = dev->mtu; 12518c2ecf20Sopenharmony_ci writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len); 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci if (nic->device_type & XFRAME_II_DEVICE) { 12548c2ecf20Sopenharmony_ci while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) { 12558c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt], 12568c2ecf20Sopenharmony_ci &bar0->dtx_control, UF); 12578c2ecf20Sopenharmony_ci if (dtx_cnt & 0x1) 12588c2ecf20Sopenharmony_ci msleep(1); /* Necessary!! */ 12598c2ecf20Sopenharmony_ci dtx_cnt++; 12608c2ecf20Sopenharmony_ci } 12618c2ecf20Sopenharmony_ci } else { 12628c2ecf20Sopenharmony_ci while (xena_dtx_cfg[dtx_cnt] != END_SIGN) { 12638c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt], 12648c2ecf20Sopenharmony_ci &bar0->dtx_control, UF); 12658c2ecf20Sopenharmony_ci val64 = readq(&bar0->dtx_control); 12668c2ecf20Sopenharmony_ci dtx_cnt++; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci /* Tx DMA Initialization */ 12718c2ecf20Sopenharmony_ci val64 = 0; 12728c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_fifo_partition_0); 12738c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_fifo_partition_1); 12748c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_fifo_partition_2); 12758c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_fifo_partition_3); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < config->tx_fifo_num; i++) { 12788c2ecf20Sopenharmony_ci struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci val64 |= vBIT(tx_cfg->fifo_len - 1, ((j * 32) + 19), 13) | 12818c2ecf20Sopenharmony_ci vBIT(tx_cfg->fifo_priority, ((j * 32) + 5), 3); 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci if (i == (config->tx_fifo_num - 1)) { 12848c2ecf20Sopenharmony_ci if (i % 2 == 0) 12858c2ecf20Sopenharmony_ci i++; 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci switch (i) { 12898c2ecf20Sopenharmony_ci case 1: 12908c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_fifo_partition_0); 12918c2ecf20Sopenharmony_ci val64 = 0; 12928c2ecf20Sopenharmony_ci j = 0; 12938c2ecf20Sopenharmony_ci break; 12948c2ecf20Sopenharmony_ci case 3: 12958c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_fifo_partition_1); 12968c2ecf20Sopenharmony_ci val64 = 0; 12978c2ecf20Sopenharmony_ci j = 0; 12988c2ecf20Sopenharmony_ci break; 12998c2ecf20Sopenharmony_ci case 5: 13008c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_fifo_partition_2); 13018c2ecf20Sopenharmony_ci val64 = 0; 13028c2ecf20Sopenharmony_ci j = 0; 13038c2ecf20Sopenharmony_ci break; 13048c2ecf20Sopenharmony_ci case 7: 13058c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_fifo_partition_3); 13068c2ecf20Sopenharmony_ci val64 = 0; 13078c2ecf20Sopenharmony_ci j = 0; 13088c2ecf20Sopenharmony_ci break; 13098c2ecf20Sopenharmony_ci default: 13108c2ecf20Sopenharmony_ci j++; 13118c2ecf20Sopenharmony_ci break; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* 13168c2ecf20Sopenharmony_ci * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug 13178c2ecf20Sopenharmony_ci * SXE-008 TRANSMIT DMA ARBITRATION ISSUE. 13188c2ecf20Sopenharmony_ci */ 13198c2ecf20Sopenharmony_ci if ((nic->device_type == XFRAME_I_DEVICE) && (nic->pdev->revision < 4)) 13208c2ecf20Sopenharmony_ci writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci val64 = readq(&bar0->tx_fifo_partition_0); 13238c2ecf20Sopenharmony_ci DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n", 13248c2ecf20Sopenharmony_ci &bar0->tx_fifo_partition_0, (unsigned long long)val64); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci /* 13278c2ecf20Sopenharmony_ci * Initialization of Tx_PA_CONFIG register to ignore packet 13288c2ecf20Sopenharmony_ci * integrity checking. 13298c2ecf20Sopenharmony_ci */ 13308c2ecf20Sopenharmony_ci val64 = readq(&bar0->tx_pa_cfg); 13318c2ecf20Sopenharmony_ci val64 |= TX_PA_CFG_IGNORE_FRM_ERR | 13328c2ecf20Sopenharmony_ci TX_PA_CFG_IGNORE_SNAP_OUI | 13338c2ecf20Sopenharmony_ci TX_PA_CFG_IGNORE_LLC_CTRL | 13348c2ecf20Sopenharmony_ci TX_PA_CFG_IGNORE_L2_ERR; 13358c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_pa_cfg); 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci /* Rx DMA initialization. */ 13388c2ecf20Sopenharmony_ci val64 = 0; 13398c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 13408c2ecf20Sopenharmony_ci struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci val64 |= vBIT(rx_cfg->ring_priority, (5 + (i * 8)), 3); 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_queue_priority); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci /* 13478c2ecf20Sopenharmony_ci * Allocating equal share of memory to all the 13488c2ecf20Sopenharmony_ci * configured Rings. 13498c2ecf20Sopenharmony_ci */ 13508c2ecf20Sopenharmony_ci val64 = 0; 13518c2ecf20Sopenharmony_ci if (nic->device_type & XFRAME_II_DEVICE) 13528c2ecf20Sopenharmony_ci mem_size = 32; 13538c2ecf20Sopenharmony_ci else 13548c2ecf20Sopenharmony_ci mem_size = 64; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 13578c2ecf20Sopenharmony_ci switch (i) { 13588c2ecf20Sopenharmony_ci case 0: 13598c2ecf20Sopenharmony_ci mem_share = (mem_size / config->rx_ring_num + 13608c2ecf20Sopenharmony_ci mem_size % config->rx_ring_num); 13618c2ecf20Sopenharmony_ci val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share); 13628c2ecf20Sopenharmony_ci continue; 13638c2ecf20Sopenharmony_ci case 1: 13648c2ecf20Sopenharmony_ci mem_share = (mem_size / config->rx_ring_num); 13658c2ecf20Sopenharmony_ci val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share); 13668c2ecf20Sopenharmony_ci continue; 13678c2ecf20Sopenharmony_ci case 2: 13688c2ecf20Sopenharmony_ci mem_share = (mem_size / config->rx_ring_num); 13698c2ecf20Sopenharmony_ci val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share); 13708c2ecf20Sopenharmony_ci continue; 13718c2ecf20Sopenharmony_ci case 3: 13728c2ecf20Sopenharmony_ci mem_share = (mem_size / config->rx_ring_num); 13738c2ecf20Sopenharmony_ci val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share); 13748c2ecf20Sopenharmony_ci continue; 13758c2ecf20Sopenharmony_ci case 4: 13768c2ecf20Sopenharmony_ci mem_share = (mem_size / config->rx_ring_num); 13778c2ecf20Sopenharmony_ci val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share); 13788c2ecf20Sopenharmony_ci continue; 13798c2ecf20Sopenharmony_ci case 5: 13808c2ecf20Sopenharmony_ci mem_share = (mem_size / config->rx_ring_num); 13818c2ecf20Sopenharmony_ci val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share); 13828c2ecf20Sopenharmony_ci continue; 13838c2ecf20Sopenharmony_ci case 6: 13848c2ecf20Sopenharmony_ci mem_share = (mem_size / config->rx_ring_num); 13858c2ecf20Sopenharmony_ci val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share); 13868c2ecf20Sopenharmony_ci continue; 13878c2ecf20Sopenharmony_ci case 7: 13888c2ecf20Sopenharmony_ci mem_share = (mem_size / config->rx_ring_num); 13898c2ecf20Sopenharmony_ci val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share); 13908c2ecf20Sopenharmony_ci continue; 13918c2ecf20Sopenharmony_ci } 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_queue_cfg); 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci /* 13968c2ecf20Sopenharmony_ci * Filling Tx round robin registers 13978c2ecf20Sopenharmony_ci * as per the number of FIFOs for equal scheduling priority 13988c2ecf20Sopenharmony_ci */ 13998c2ecf20Sopenharmony_ci switch (config->tx_fifo_num) { 14008c2ecf20Sopenharmony_ci case 1: 14018c2ecf20Sopenharmony_ci val64 = 0x0; 14028c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_0); 14038c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_1); 14048c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_2); 14058c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_3); 14068c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_4); 14078c2ecf20Sopenharmony_ci break; 14088c2ecf20Sopenharmony_ci case 2: 14098c2ecf20Sopenharmony_ci val64 = 0x0001000100010001ULL; 14108c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_0); 14118c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_1); 14128c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_2); 14138c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_3); 14148c2ecf20Sopenharmony_ci val64 = 0x0001000100000000ULL; 14158c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_4); 14168c2ecf20Sopenharmony_ci break; 14178c2ecf20Sopenharmony_ci case 3: 14188c2ecf20Sopenharmony_ci val64 = 0x0001020001020001ULL; 14198c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_0); 14208c2ecf20Sopenharmony_ci val64 = 0x0200010200010200ULL; 14218c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_1); 14228c2ecf20Sopenharmony_ci val64 = 0x0102000102000102ULL; 14238c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_2); 14248c2ecf20Sopenharmony_ci val64 = 0x0001020001020001ULL; 14258c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_3); 14268c2ecf20Sopenharmony_ci val64 = 0x0200010200000000ULL; 14278c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_4); 14288c2ecf20Sopenharmony_ci break; 14298c2ecf20Sopenharmony_ci case 4: 14308c2ecf20Sopenharmony_ci val64 = 0x0001020300010203ULL; 14318c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_0); 14328c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_1); 14338c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_2); 14348c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_3); 14358c2ecf20Sopenharmony_ci val64 = 0x0001020300000000ULL; 14368c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_4); 14378c2ecf20Sopenharmony_ci break; 14388c2ecf20Sopenharmony_ci case 5: 14398c2ecf20Sopenharmony_ci val64 = 0x0001020304000102ULL; 14408c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_0); 14418c2ecf20Sopenharmony_ci val64 = 0x0304000102030400ULL; 14428c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_1); 14438c2ecf20Sopenharmony_ci val64 = 0x0102030400010203ULL; 14448c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_2); 14458c2ecf20Sopenharmony_ci val64 = 0x0400010203040001ULL; 14468c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_3); 14478c2ecf20Sopenharmony_ci val64 = 0x0203040000000000ULL; 14488c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_4); 14498c2ecf20Sopenharmony_ci break; 14508c2ecf20Sopenharmony_ci case 6: 14518c2ecf20Sopenharmony_ci val64 = 0x0001020304050001ULL; 14528c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_0); 14538c2ecf20Sopenharmony_ci val64 = 0x0203040500010203ULL; 14548c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_1); 14558c2ecf20Sopenharmony_ci val64 = 0x0405000102030405ULL; 14568c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_2); 14578c2ecf20Sopenharmony_ci val64 = 0x0001020304050001ULL; 14588c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_3); 14598c2ecf20Sopenharmony_ci val64 = 0x0203040500000000ULL; 14608c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_4); 14618c2ecf20Sopenharmony_ci break; 14628c2ecf20Sopenharmony_ci case 7: 14638c2ecf20Sopenharmony_ci val64 = 0x0001020304050600ULL; 14648c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_0); 14658c2ecf20Sopenharmony_ci val64 = 0x0102030405060001ULL; 14668c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_1); 14678c2ecf20Sopenharmony_ci val64 = 0x0203040506000102ULL; 14688c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_2); 14698c2ecf20Sopenharmony_ci val64 = 0x0304050600010203ULL; 14708c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_3); 14718c2ecf20Sopenharmony_ci val64 = 0x0405060000000000ULL; 14728c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_4); 14738c2ecf20Sopenharmony_ci break; 14748c2ecf20Sopenharmony_ci case 8: 14758c2ecf20Sopenharmony_ci val64 = 0x0001020304050607ULL; 14768c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_0); 14778c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_1); 14788c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_2); 14798c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_3); 14808c2ecf20Sopenharmony_ci val64 = 0x0001020300000000ULL; 14818c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_w_round_robin_4); 14828c2ecf20Sopenharmony_ci break; 14838c2ecf20Sopenharmony_ci } 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_ci /* Enable all configured Tx FIFO partitions */ 14868c2ecf20Sopenharmony_ci val64 = readq(&bar0->tx_fifo_partition_0); 14878c2ecf20Sopenharmony_ci val64 |= (TX_FIFO_PARTITION_EN); 14888c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_fifo_partition_0); 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci /* Filling the Rx round robin registers as per the 14918c2ecf20Sopenharmony_ci * number of Rings and steering based on QoS with 14928c2ecf20Sopenharmony_ci * equal priority. 14938c2ecf20Sopenharmony_ci */ 14948c2ecf20Sopenharmony_ci switch (config->rx_ring_num) { 14958c2ecf20Sopenharmony_ci case 1: 14968c2ecf20Sopenharmony_ci val64 = 0x0; 14978c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_0); 14988c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_1); 14998c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_2); 15008c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_3); 15018c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_4); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci val64 = 0x8080808080808080ULL; 15048c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_qos_steering); 15058c2ecf20Sopenharmony_ci break; 15068c2ecf20Sopenharmony_ci case 2: 15078c2ecf20Sopenharmony_ci val64 = 0x0001000100010001ULL; 15088c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_0); 15098c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_1); 15108c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_2); 15118c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_3); 15128c2ecf20Sopenharmony_ci val64 = 0x0001000100000000ULL; 15138c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_4); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci val64 = 0x8080808040404040ULL; 15168c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_qos_steering); 15178c2ecf20Sopenharmony_ci break; 15188c2ecf20Sopenharmony_ci case 3: 15198c2ecf20Sopenharmony_ci val64 = 0x0001020001020001ULL; 15208c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_0); 15218c2ecf20Sopenharmony_ci val64 = 0x0200010200010200ULL; 15228c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_1); 15238c2ecf20Sopenharmony_ci val64 = 0x0102000102000102ULL; 15248c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_2); 15258c2ecf20Sopenharmony_ci val64 = 0x0001020001020001ULL; 15268c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_3); 15278c2ecf20Sopenharmony_ci val64 = 0x0200010200000000ULL; 15288c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_4); 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci val64 = 0x8080804040402020ULL; 15318c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_qos_steering); 15328c2ecf20Sopenharmony_ci break; 15338c2ecf20Sopenharmony_ci case 4: 15348c2ecf20Sopenharmony_ci val64 = 0x0001020300010203ULL; 15358c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_0); 15368c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_1); 15378c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_2); 15388c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_3); 15398c2ecf20Sopenharmony_ci val64 = 0x0001020300000000ULL; 15408c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_4); 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci val64 = 0x8080404020201010ULL; 15438c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_qos_steering); 15448c2ecf20Sopenharmony_ci break; 15458c2ecf20Sopenharmony_ci case 5: 15468c2ecf20Sopenharmony_ci val64 = 0x0001020304000102ULL; 15478c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_0); 15488c2ecf20Sopenharmony_ci val64 = 0x0304000102030400ULL; 15498c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_1); 15508c2ecf20Sopenharmony_ci val64 = 0x0102030400010203ULL; 15518c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_2); 15528c2ecf20Sopenharmony_ci val64 = 0x0400010203040001ULL; 15538c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_3); 15548c2ecf20Sopenharmony_ci val64 = 0x0203040000000000ULL; 15558c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_4); 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci val64 = 0x8080404020201008ULL; 15588c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_qos_steering); 15598c2ecf20Sopenharmony_ci break; 15608c2ecf20Sopenharmony_ci case 6: 15618c2ecf20Sopenharmony_ci val64 = 0x0001020304050001ULL; 15628c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_0); 15638c2ecf20Sopenharmony_ci val64 = 0x0203040500010203ULL; 15648c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_1); 15658c2ecf20Sopenharmony_ci val64 = 0x0405000102030405ULL; 15668c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_2); 15678c2ecf20Sopenharmony_ci val64 = 0x0001020304050001ULL; 15688c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_3); 15698c2ecf20Sopenharmony_ci val64 = 0x0203040500000000ULL; 15708c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_4); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci val64 = 0x8080404020100804ULL; 15738c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_qos_steering); 15748c2ecf20Sopenharmony_ci break; 15758c2ecf20Sopenharmony_ci case 7: 15768c2ecf20Sopenharmony_ci val64 = 0x0001020304050600ULL; 15778c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_0); 15788c2ecf20Sopenharmony_ci val64 = 0x0102030405060001ULL; 15798c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_1); 15808c2ecf20Sopenharmony_ci val64 = 0x0203040506000102ULL; 15818c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_2); 15828c2ecf20Sopenharmony_ci val64 = 0x0304050600010203ULL; 15838c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_3); 15848c2ecf20Sopenharmony_ci val64 = 0x0405060000000000ULL; 15858c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_4); 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_ci val64 = 0x8080402010080402ULL; 15888c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_qos_steering); 15898c2ecf20Sopenharmony_ci break; 15908c2ecf20Sopenharmony_ci case 8: 15918c2ecf20Sopenharmony_ci val64 = 0x0001020304050607ULL; 15928c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_0); 15938c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_1); 15948c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_2); 15958c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_3); 15968c2ecf20Sopenharmony_ci val64 = 0x0001020300000000ULL; 15978c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_w_round_robin_4); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci val64 = 0x8040201008040201ULL; 16008c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_qos_steering); 16018c2ecf20Sopenharmony_ci break; 16028c2ecf20Sopenharmony_ci } 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci /* UDP Fix */ 16058c2ecf20Sopenharmony_ci val64 = 0; 16068c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 16078c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_frm_len_n[i]); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci /* Set the default rts frame length for the rings configured */ 16108c2ecf20Sopenharmony_ci val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22); 16118c2ecf20Sopenharmony_ci for (i = 0 ; i < config->rx_ring_num ; i++) 16128c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_frm_len_n[i]); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci /* Set the frame length for the configured rings 16158c2ecf20Sopenharmony_ci * desired by the user 16168c2ecf20Sopenharmony_ci */ 16178c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 16188c2ecf20Sopenharmony_ci /* If rts_frm_len[i] == 0 then it is assumed that user not 16198c2ecf20Sopenharmony_ci * specified frame length steering. 16208c2ecf20Sopenharmony_ci * If the user provides the frame length then program 16218c2ecf20Sopenharmony_ci * the rts_frm_len register for those values or else 16228c2ecf20Sopenharmony_ci * leave it as it is. 16238c2ecf20Sopenharmony_ci */ 16248c2ecf20Sopenharmony_ci if (rts_frm_len[i] != 0) { 16258c2ecf20Sopenharmony_ci writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]), 16268c2ecf20Sopenharmony_ci &bar0->rts_frm_len_n[i]); 16278c2ecf20Sopenharmony_ci } 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci /* Disable differentiated services steering logic */ 16318c2ecf20Sopenharmony_ci for (i = 0; i < 64; i++) { 16328c2ecf20Sopenharmony_ci if (rts_ds_steer(nic, i, 0) == FAILURE) { 16338c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 16348c2ecf20Sopenharmony_ci "%s: rts_ds_steer failed on codepoint %d\n", 16358c2ecf20Sopenharmony_ci dev->name, i); 16368c2ecf20Sopenharmony_ci return -ENODEV; 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci /* Program statistics memory */ 16418c2ecf20Sopenharmony_ci writeq(mac_control->stats_mem_phy, &bar0->stat_addr); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci if (nic->device_type == XFRAME_II_DEVICE) { 16448c2ecf20Sopenharmony_ci val64 = STAT_BC(0x320); 16458c2ecf20Sopenharmony_ci writeq(val64, &bar0->stat_byte_cnt); 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci /* 16498c2ecf20Sopenharmony_ci * Initializing the sampling rate for the device to calculate the 16508c2ecf20Sopenharmony_ci * bandwidth utilization. 16518c2ecf20Sopenharmony_ci */ 16528c2ecf20Sopenharmony_ci val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) | 16538c2ecf20Sopenharmony_ci MAC_RX_LINK_UTIL_VAL(rmac_util_period); 16548c2ecf20Sopenharmony_ci writeq(val64, &bar0->mac_link_util); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci /* 16578c2ecf20Sopenharmony_ci * Initializing the Transmit and Receive Traffic Interrupt 16588c2ecf20Sopenharmony_ci * Scheme. 16598c2ecf20Sopenharmony_ci */ 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci /* Initialize TTI */ 16628c2ecf20Sopenharmony_ci if (SUCCESS != init_tti(nic, nic->last_link_state)) 16638c2ecf20Sopenharmony_ci return -ENODEV; 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci /* RTI Initialization */ 16668c2ecf20Sopenharmony_ci if (nic->device_type == XFRAME_II_DEVICE) { 16678c2ecf20Sopenharmony_ci /* 16688c2ecf20Sopenharmony_ci * Programmed to generate Apprx 500 Intrs per 16698c2ecf20Sopenharmony_ci * second 16708c2ecf20Sopenharmony_ci */ 16718c2ecf20Sopenharmony_ci int count = (nic->config.bus_speed * 125)/4; 16728c2ecf20Sopenharmony_ci val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count); 16738c2ecf20Sopenharmony_ci } else 16748c2ecf20Sopenharmony_ci val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF); 16758c2ecf20Sopenharmony_ci val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) | 16768c2ecf20Sopenharmony_ci RTI_DATA1_MEM_RX_URNG_B(0x10) | 16778c2ecf20Sopenharmony_ci RTI_DATA1_MEM_RX_URNG_C(0x30) | 16788c2ecf20Sopenharmony_ci RTI_DATA1_MEM_RX_TIMER_AC_EN; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci writeq(val64, &bar0->rti_data1_mem); 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) | 16838c2ecf20Sopenharmony_ci RTI_DATA2_MEM_RX_UFC_B(0x2) ; 16848c2ecf20Sopenharmony_ci if (nic->config.intr_type == MSI_X) 16858c2ecf20Sopenharmony_ci val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) | 16868c2ecf20Sopenharmony_ci RTI_DATA2_MEM_RX_UFC_D(0x40)); 16878c2ecf20Sopenharmony_ci else 16888c2ecf20Sopenharmony_ci val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) | 16898c2ecf20Sopenharmony_ci RTI_DATA2_MEM_RX_UFC_D(0x80)); 16908c2ecf20Sopenharmony_ci writeq(val64, &bar0->rti_data2_mem); 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 16938c2ecf20Sopenharmony_ci val64 = RTI_CMD_MEM_WE | 16948c2ecf20Sopenharmony_ci RTI_CMD_MEM_STROBE_NEW_CMD | 16958c2ecf20Sopenharmony_ci RTI_CMD_MEM_OFFSET(i); 16968c2ecf20Sopenharmony_ci writeq(val64, &bar0->rti_command_mem); 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci /* 16998c2ecf20Sopenharmony_ci * Once the operation completes, the Strobe bit of the 17008c2ecf20Sopenharmony_ci * command register will be reset. We poll for this 17018c2ecf20Sopenharmony_ci * particular condition. We wait for a maximum of 500ms 17028c2ecf20Sopenharmony_ci * for the operation to complete, if it's not complete 17038c2ecf20Sopenharmony_ci * by then we return error. 17048c2ecf20Sopenharmony_ci */ 17058c2ecf20Sopenharmony_ci time = 0; 17068c2ecf20Sopenharmony_ci while (true) { 17078c2ecf20Sopenharmony_ci val64 = readq(&bar0->rti_command_mem); 17088c2ecf20Sopenharmony_ci if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) 17098c2ecf20Sopenharmony_ci break; 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ci if (time > 10) { 17128c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: RTI init failed\n", 17138c2ecf20Sopenharmony_ci dev->name); 17148c2ecf20Sopenharmony_ci return -ENODEV; 17158c2ecf20Sopenharmony_ci } 17168c2ecf20Sopenharmony_ci time++; 17178c2ecf20Sopenharmony_ci msleep(50); 17188c2ecf20Sopenharmony_ci } 17198c2ecf20Sopenharmony_ci } 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci /* 17228c2ecf20Sopenharmony_ci * Initializing proper values as Pause threshold into all 17238c2ecf20Sopenharmony_ci * the 8 Queues on Rx side. 17248c2ecf20Sopenharmony_ci */ 17258c2ecf20Sopenharmony_ci writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3); 17268c2ecf20Sopenharmony_ci writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7); 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci /* Disable RMAC PAD STRIPPING */ 17298c2ecf20Sopenharmony_ci add = &bar0->mac_cfg; 17308c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_cfg); 17318c2ecf20Sopenharmony_ci val64 &= ~(MAC_CFG_RMAC_STRIP_PAD); 17328c2ecf20Sopenharmony_ci writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); 17338c2ecf20Sopenharmony_ci writel((u32) (val64), add); 17348c2ecf20Sopenharmony_ci writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); 17358c2ecf20Sopenharmony_ci writel((u32) (val64 >> 32), (add + 4)); 17368c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_cfg); 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci /* Enable FCS stripping by adapter */ 17398c2ecf20Sopenharmony_ci add = &bar0->mac_cfg; 17408c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_cfg); 17418c2ecf20Sopenharmony_ci val64 |= MAC_CFG_RMAC_STRIP_FCS; 17428c2ecf20Sopenharmony_ci if (nic->device_type == XFRAME_II_DEVICE) 17438c2ecf20Sopenharmony_ci writeq(val64, &bar0->mac_cfg); 17448c2ecf20Sopenharmony_ci else { 17458c2ecf20Sopenharmony_ci writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); 17468c2ecf20Sopenharmony_ci writel((u32) (val64), add); 17478c2ecf20Sopenharmony_ci writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); 17488c2ecf20Sopenharmony_ci writel((u32) (val64 >> 32), (add + 4)); 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci /* 17528c2ecf20Sopenharmony_ci * Set the time value to be inserted in the pause frame 17538c2ecf20Sopenharmony_ci * generated by xena. 17548c2ecf20Sopenharmony_ci */ 17558c2ecf20Sopenharmony_ci val64 = readq(&bar0->rmac_pause_cfg); 17568c2ecf20Sopenharmony_ci val64 &= ~(RMAC_PAUSE_HG_PTIME(0xffff)); 17578c2ecf20Sopenharmony_ci val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time); 17588c2ecf20Sopenharmony_ci writeq(val64, &bar0->rmac_pause_cfg); 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci /* 17618c2ecf20Sopenharmony_ci * Set the Threshold Limit for Generating the pause frame 17628c2ecf20Sopenharmony_ci * If the amount of data in any Queue exceeds ratio of 17638c2ecf20Sopenharmony_ci * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256 17648c2ecf20Sopenharmony_ci * pause frame is generated 17658c2ecf20Sopenharmony_ci */ 17668c2ecf20Sopenharmony_ci val64 = 0; 17678c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 17688c2ecf20Sopenharmony_ci val64 |= (((u64)0xFF00 | 17698c2ecf20Sopenharmony_ci nic->mac_control.mc_pause_threshold_q0q3) 17708c2ecf20Sopenharmony_ci << (i * 2 * 8)); 17718c2ecf20Sopenharmony_ci } 17728c2ecf20Sopenharmony_ci writeq(val64, &bar0->mc_pause_thresh_q0q3); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci val64 = 0; 17758c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 17768c2ecf20Sopenharmony_ci val64 |= (((u64)0xFF00 | 17778c2ecf20Sopenharmony_ci nic->mac_control.mc_pause_threshold_q4q7) 17788c2ecf20Sopenharmony_ci << (i * 2 * 8)); 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci writeq(val64, &bar0->mc_pause_thresh_q4q7); 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci /* 17838c2ecf20Sopenharmony_ci * TxDMA will stop Read request if the number of read split has 17848c2ecf20Sopenharmony_ci * exceeded the limit pointed by shared_splits 17858c2ecf20Sopenharmony_ci */ 17868c2ecf20Sopenharmony_ci val64 = readq(&bar0->pic_control); 17878c2ecf20Sopenharmony_ci val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits); 17888c2ecf20Sopenharmony_ci writeq(val64, &bar0->pic_control); 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci if (nic->config.bus_speed == 266) { 17918c2ecf20Sopenharmony_ci writeq(TXREQTO_VAL(0x7f) | TXREQTO_EN, &bar0->txreqtimeout); 17928c2ecf20Sopenharmony_ci writeq(0x0, &bar0->read_retry_delay); 17938c2ecf20Sopenharmony_ci writeq(0x0, &bar0->write_retry_delay); 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci /* 17978c2ecf20Sopenharmony_ci * Programming the Herc to split every write transaction 17988c2ecf20Sopenharmony_ci * that does not start on an ADB to reduce disconnects. 17998c2ecf20Sopenharmony_ci */ 18008c2ecf20Sopenharmony_ci if (nic->device_type == XFRAME_II_DEVICE) { 18018c2ecf20Sopenharmony_ci val64 = FAULT_BEHAVIOUR | EXT_REQ_EN | 18028c2ecf20Sopenharmony_ci MISC_LINK_STABILITY_PRD(3); 18038c2ecf20Sopenharmony_ci writeq(val64, &bar0->misc_control); 18048c2ecf20Sopenharmony_ci val64 = readq(&bar0->pic_control2); 18058c2ecf20Sopenharmony_ci val64 &= ~(s2BIT(13)|s2BIT(14)|s2BIT(15)); 18068c2ecf20Sopenharmony_ci writeq(val64, &bar0->pic_control2); 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci if (strstr(nic->product_name, "CX4")) { 18098c2ecf20Sopenharmony_ci val64 = TMAC_AVG_IPG(0x17); 18108c2ecf20Sopenharmony_ci writeq(val64, &bar0->tmac_avg_ipg); 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci return SUCCESS; 18148c2ecf20Sopenharmony_ci} 18158c2ecf20Sopenharmony_ci#define LINK_UP_DOWN_INTERRUPT 1 18168c2ecf20Sopenharmony_ci#define MAC_RMAC_ERR_TIMER 2 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_cistatic int s2io_link_fault_indication(struct s2io_nic *nic) 18198c2ecf20Sopenharmony_ci{ 18208c2ecf20Sopenharmony_ci if (nic->device_type == XFRAME_II_DEVICE) 18218c2ecf20Sopenharmony_ci return LINK_UP_DOWN_INTERRUPT; 18228c2ecf20Sopenharmony_ci else 18238c2ecf20Sopenharmony_ci return MAC_RMAC_ERR_TIMER; 18248c2ecf20Sopenharmony_ci} 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci/** 18278c2ecf20Sopenharmony_ci * do_s2io_write_bits - update alarm bits in alarm register 18288c2ecf20Sopenharmony_ci * @value: alarm bits 18298c2ecf20Sopenharmony_ci * @flag: interrupt status 18308c2ecf20Sopenharmony_ci * @addr: address value 18318c2ecf20Sopenharmony_ci * Description: update alarm bits in alarm register 18328c2ecf20Sopenharmony_ci * Return Value: 18338c2ecf20Sopenharmony_ci * NONE. 18348c2ecf20Sopenharmony_ci */ 18358c2ecf20Sopenharmony_cistatic void do_s2io_write_bits(u64 value, int flag, void __iomem *addr) 18368c2ecf20Sopenharmony_ci{ 18378c2ecf20Sopenharmony_ci u64 temp64; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci temp64 = readq(addr); 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (flag == ENABLE_INTRS) 18428c2ecf20Sopenharmony_ci temp64 &= ~((u64)value); 18438c2ecf20Sopenharmony_ci else 18448c2ecf20Sopenharmony_ci temp64 |= ((u64)value); 18458c2ecf20Sopenharmony_ci writeq(temp64, addr); 18468c2ecf20Sopenharmony_ci} 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_cistatic void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag) 18498c2ecf20Sopenharmony_ci{ 18508c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 18518c2ecf20Sopenharmony_ci register u64 gen_int_mask = 0; 18528c2ecf20Sopenharmony_ci u64 interruptible; 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci writeq(DISABLE_ALL_INTRS, &bar0->general_int_mask); 18558c2ecf20Sopenharmony_ci if (mask & TX_DMA_INTR) { 18568c2ecf20Sopenharmony_ci gen_int_mask |= TXDMA_INT_M; 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci do_s2io_write_bits(TXDMA_TDA_INT | TXDMA_PFC_INT | 18598c2ecf20Sopenharmony_ci TXDMA_PCC_INT | TXDMA_TTI_INT | 18608c2ecf20Sopenharmony_ci TXDMA_LSO_INT | TXDMA_TPA_INT | 18618c2ecf20Sopenharmony_ci TXDMA_SM_INT, flag, &bar0->txdma_int_mask); 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci do_s2io_write_bits(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM | 18648c2ecf20Sopenharmony_ci PFC_MISC_0_ERR | PFC_MISC_1_ERR | 18658c2ecf20Sopenharmony_ci PFC_PCIX_ERR | PFC_ECC_SG_ERR, flag, 18668c2ecf20Sopenharmony_ci &bar0->pfc_err_mask); 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci do_s2io_write_bits(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM | 18698c2ecf20Sopenharmony_ci TDA_SM1_ERR_ALARM | TDA_Fn_ECC_SG_ERR | 18708c2ecf20Sopenharmony_ci TDA_PCIX_ERR, flag, &bar0->tda_err_mask); 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci do_s2io_write_bits(PCC_FB_ECC_DB_ERR | PCC_TXB_ECC_DB_ERR | 18738c2ecf20Sopenharmony_ci PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM | 18748c2ecf20Sopenharmony_ci PCC_N_SERR | PCC_6_COF_OV_ERR | 18758c2ecf20Sopenharmony_ci PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR | 18768c2ecf20Sopenharmony_ci PCC_7_LSO_OV_ERR | PCC_FB_ECC_SG_ERR | 18778c2ecf20Sopenharmony_ci PCC_TXB_ECC_SG_ERR, 18788c2ecf20Sopenharmony_ci flag, &bar0->pcc_err_mask); 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_ci do_s2io_write_bits(TTI_SM_ERR_ALARM | TTI_ECC_SG_ERR | 18818c2ecf20Sopenharmony_ci TTI_ECC_DB_ERR, flag, &bar0->tti_err_mask); 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_ci do_s2io_write_bits(LSO6_ABORT | LSO7_ABORT | 18848c2ecf20Sopenharmony_ci LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM | 18858c2ecf20Sopenharmony_ci LSO6_SEND_OFLOW | LSO7_SEND_OFLOW, 18868c2ecf20Sopenharmony_ci flag, &bar0->lso_err_mask); 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci do_s2io_write_bits(TPA_SM_ERR_ALARM | TPA_TX_FRM_DROP, 18898c2ecf20Sopenharmony_ci flag, &bar0->tpa_err_mask); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci do_s2io_write_bits(SM_SM_ERR_ALARM, flag, &bar0->sm_err_mask); 18928c2ecf20Sopenharmony_ci } 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci if (mask & TX_MAC_INTR) { 18958c2ecf20Sopenharmony_ci gen_int_mask |= TXMAC_INT_M; 18968c2ecf20Sopenharmony_ci do_s2io_write_bits(MAC_INT_STATUS_TMAC_INT, flag, 18978c2ecf20Sopenharmony_ci &bar0->mac_int_mask); 18988c2ecf20Sopenharmony_ci do_s2io_write_bits(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR | 18998c2ecf20Sopenharmony_ci TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR | 19008c2ecf20Sopenharmony_ci TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR, 19018c2ecf20Sopenharmony_ci flag, &bar0->mac_tmac_err_mask); 19028c2ecf20Sopenharmony_ci } 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci if (mask & TX_XGXS_INTR) { 19058c2ecf20Sopenharmony_ci gen_int_mask |= TXXGXS_INT_M; 19068c2ecf20Sopenharmony_ci do_s2io_write_bits(XGXS_INT_STATUS_TXGXS, flag, 19078c2ecf20Sopenharmony_ci &bar0->xgxs_int_mask); 19088c2ecf20Sopenharmony_ci do_s2io_write_bits(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR | 19098c2ecf20Sopenharmony_ci TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR, 19108c2ecf20Sopenharmony_ci flag, &bar0->xgxs_txgxs_err_mask); 19118c2ecf20Sopenharmony_ci } 19128c2ecf20Sopenharmony_ci 19138c2ecf20Sopenharmony_ci if (mask & RX_DMA_INTR) { 19148c2ecf20Sopenharmony_ci gen_int_mask |= RXDMA_INT_M; 19158c2ecf20Sopenharmony_ci do_s2io_write_bits(RXDMA_INT_RC_INT_M | RXDMA_INT_RPA_INT_M | 19168c2ecf20Sopenharmony_ci RXDMA_INT_RDA_INT_M | RXDMA_INT_RTI_INT_M, 19178c2ecf20Sopenharmony_ci flag, &bar0->rxdma_int_mask); 19188c2ecf20Sopenharmony_ci do_s2io_write_bits(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR | 19198c2ecf20Sopenharmony_ci RC_PRCn_SM_ERR_ALARM | RC_FTC_SM_ERR_ALARM | 19208c2ecf20Sopenharmony_ci RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR | 19218c2ecf20Sopenharmony_ci RC_RDA_FAIL_WR_Rn, flag, &bar0->rc_err_mask); 19228c2ecf20Sopenharmony_ci do_s2io_write_bits(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn | 19238c2ecf20Sopenharmony_ci PRC_PCI_AB_F_WR_Rn | PRC_PCI_DP_RD_Rn | 19248c2ecf20Sopenharmony_ci PRC_PCI_DP_WR_Rn | PRC_PCI_DP_F_WR_Rn, flag, 19258c2ecf20Sopenharmony_ci &bar0->prc_pcix_err_mask); 19268c2ecf20Sopenharmony_ci do_s2io_write_bits(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR | 19278c2ecf20Sopenharmony_ci RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, flag, 19288c2ecf20Sopenharmony_ci &bar0->rpa_err_mask); 19298c2ecf20Sopenharmony_ci do_s2io_write_bits(RDA_RXDn_ECC_DB_ERR | RDA_FRM_ECC_DB_N_AERR | 19308c2ecf20Sopenharmony_ci RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM | 19318c2ecf20Sopenharmony_ci RDA_RXD_ECC_DB_SERR | RDA_RXDn_ECC_SG_ERR | 19328c2ecf20Sopenharmony_ci RDA_FRM_ECC_SG_ERR | 19338c2ecf20Sopenharmony_ci RDA_MISC_ERR|RDA_PCIX_ERR, 19348c2ecf20Sopenharmony_ci flag, &bar0->rda_err_mask); 19358c2ecf20Sopenharmony_ci do_s2io_write_bits(RTI_SM_ERR_ALARM | 19368c2ecf20Sopenharmony_ci RTI_ECC_SG_ERR | RTI_ECC_DB_ERR, 19378c2ecf20Sopenharmony_ci flag, &bar0->rti_err_mask); 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci 19408c2ecf20Sopenharmony_ci if (mask & RX_MAC_INTR) { 19418c2ecf20Sopenharmony_ci gen_int_mask |= RXMAC_INT_M; 19428c2ecf20Sopenharmony_ci do_s2io_write_bits(MAC_INT_STATUS_RMAC_INT, flag, 19438c2ecf20Sopenharmony_ci &bar0->mac_int_mask); 19448c2ecf20Sopenharmony_ci interruptible = (RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR | 19458c2ecf20Sopenharmony_ci RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR | 19468c2ecf20Sopenharmony_ci RMAC_DOUBLE_ECC_ERR); 19478c2ecf20Sopenharmony_ci if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) 19488c2ecf20Sopenharmony_ci interruptible |= RMAC_LINK_STATE_CHANGE_INT; 19498c2ecf20Sopenharmony_ci do_s2io_write_bits(interruptible, 19508c2ecf20Sopenharmony_ci flag, &bar0->mac_rmac_err_mask); 19518c2ecf20Sopenharmony_ci } 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci if (mask & RX_XGXS_INTR) { 19548c2ecf20Sopenharmony_ci gen_int_mask |= RXXGXS_INT_M; 19558c2ecf20Sopenharmony_ci do_s2io_write_bits(XGXS_INT_STATUS_RXGXS, flag, 19568c2ecf20Sopenharmony_ci &bar0->xgxs_int_mask); 19578c2ecf20Sopenharmony_ci do_s2io_write_bits(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, flag, 19588c2ecf20Sopenharmony_ci &bar0->xgxs_rxgxs_err_mask); 19598c2ecf20Sopenharmony_ci } 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci if (mask & MC_INTR) { 19628c2ecf20Sopenharmony_ci gen_int_mask |= MC_INT_M; 19638c2ecf20Sopenharmony_ci do_s2io_write_bits(MC_INT_MASK_MC_INT, 19648c2ecf20Sopenharmony_ci flag, &bar0->mc_int_mask); 19658c2ecf20Sopenharmony_ci do_s2io_write_bits(MC_ERR_REG_SM_ERR | MC_ERR_REG_ECC_ALL_SNG | 19668c2ecf20Sopenharmony_ci MC_ERR_REG_ECC_ALL_DBL | PLL_LOCK_N, flag, 19678c2ecf20Sopenharmony_ci &bar0->mc_err_mask); 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci nic->general_int_mask = gen_int_mask; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci /* Remove this line when alarm interrupts are enabled */ 19728c2ecf20Sopenharmony_ci nic->general_int_mask = 0; 19738c2ecf20Sopenharmony_ci} 19748c2ecf20Sopenharmony_ci 19758c2ecf20Sopenharmony_ci/** 19768c2ecf20Sopenharmony_ci * en_dis_able_nic_intrs - Enable or Disable the interrupts 19778c2ecf20Sopenharmony_ci * @nic: device private variable, 19788c2ecf20Sopenharmony_ci * @mask: A mask indicating which Intr block must be modified and, 19798c2ecf20Sopenharmony_ci * @flag: A flag indicating whether to enable or disable the Intrs. 19808c2ecf20Sopenharmony_ci * Description: This function will either disable or enable the interrupts 19818c2ecf20Sopenharmony_ci * depending on the flag argument. The mask argument can be used to 19828c2ecf20Sopenharmony_ci * enable/disable any Intr block. 19838c2ecf20Sopenharmony_ci * Return Value: NONE. 19848c2ecf20Sopenharmony_ci */ 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_cistatic void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag) 19878c2ecf20Sopenharmony_ci{ 19888c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 19898c2ecf20Sopenharmony_ci register u64 temp64 = 0, intr_mask = 0; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci intr_mask = nic->general_int_mask; 19928c2ecf20Sopenharmony_ci 19938c2ecf20Sopenharmony_ci /* Top level interrupt classification */ 19948c2ecf20Sopenharmony_ci /* PIC Interrupts */ 19958c2ecf20Sopenharmony_ci if (mask & TX_PIC_INTR) { 19968c2ecf20Sopenharmony_ci /* Enable PIC Intrs in the general intr mask register */ 19978c2ecf20Sopenharmony_ci intr_mask |= TXPIC_INT_M; 19988c2ecf20Sopenharmony_ci if (flag == ENABLE_INTRS) { 19998c2ecf20Sopenharmony_ci /* 20008c2ecf20Sopenharmony_ci * If Hercules adapter enable GPIO otherwise 20018c2ecf20Sopenharmony_ci * disable all PCIX, Flash, MDIO, IIC and GPIO 20028c2ecf20Sopenharmony_ci * interrupts for now. 20038c2ecf20Sopenharmony_ci * TODO 20048c2ecf20Sopenharmony_ci */ 20058c2ecf20Sopenharmony_ci if (s2io_link_fault_indication(nic) == 20068c2ecf20Sopenharmony_ci LINK_UP_DOWN_INTERRUPT) { 20078c2ecf20Sopenharmony_ci do_s2io_write_bits(PIC_INT_GPIO, flag, 20088c2ecf20Sopenharmony_ci &bar0->pic_int_mask); 20098c2ecf20Sopenharmony_ci do_s2io_write_bits(GPIO_INT_MASK_LINK_UP, flag, 20108c2ecf20Sopenharmony_ci &bar0->gpio_int_mask); 20118c2ecf20Sopenharmony_ci } else 20128c2ecf20Sopenharmony_ci writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); 20138c2ecf20Sopenharmony_ci } else if (flag == DISABLE_INTRS) { 20148c2ecf20Sopenharmony_ci /* 20158c2ecf20Sopenharmony_ci * Disable PIC Intrs in the general 20168c2ecf20Sopenharmony_ci * intr mask register 20178c2ecf20Sopenharmony_ci */ 20188c2ecf20Sopenharmony_ci writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask); 20198c2ecf20Sopenharmony_ci } 20208c2ecf20Sopenharmony_ci } 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci /* Tx traffic interrupts */ 20238c2ecf20Sopenharmony_ci if (mask & TX_TRAFFIC_INTR) { 20248c2ecf20Sopenharmony_ci intr_mask |= TXTRAFFIC_INT_M; 20258c2ecf20Sopenharmony_ci if (flag == ENABLE_INTRS) { 20268c2ecf20Sopenharmony_ci /* 20278c2ecf20Sopenharmony_ci * Enable all the Tx side interrupts 20288c2ecf20Sopenharmony_ci * writing 0 Enables all 64 TX interrupt levels 20298c2ecf20Sopenharmony_ci */ 20308c2ecf20Sopenharmony_ci writeq(0x0, &bar0->tx_traffic_mask); 20318c2ecf20Sopenharmony_ci } else if (flag == DISABLE_INTRS) { 20328c2ecf20Sopenharmony_ci /* 20338c2ecf20Sopenharmony_ci * Disable Tx Traffic Intrs in the general intr mask 20348c2ecf20Sopenharmony_ci * register. 20358c2ecf20Sopenharmony_ci */ 20368c2ecf20Sopenharmony_ci writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask); 20378c2ecf20Sopenharmony_ci } 20388c2ecf20Sopenharmony_ci } 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci /* Rx traffic interrupts */ 20418c2ecf20Sopenharmony_ci if (mask & RX_TRAFFIC_INTR) { 20428c2ecf20Sopenharmony_ci intr_mask |= RXTRAFFIC_INT_M; 20438c2ecf20Sopenharmony_ci if (flag == ENABLE_INTRS) { 20448c2ecf20Sopenharmony_ci /* writing 0 Enables all 8 RX interrupt levels */ 20458c2ecf20Sopenharmony_ci writeq(0x0, &bar0->rx_traffic_mask); 20468c2ecf20Sopenharmony_ci } else if (flag == DISABLE_INTRS) { 20478c2ecf20Sopenharmony_ci /* 20488c2ecf20Sopenharmony_ci * Disable Rx Traffic Intrs in the general intr mask 20498c2ecf20Sopenharmony_ci * register. 20508c2ecf20Sopenharmony_ci */ 20518c2ecf20Sopenharmony_ci writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask); 20528c2ecf20Sopenharmony_ci } 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci temp64 = readq(&bar0->general_int_mask); 20568c2ecf20Sopenharmony_ci if (flag == ENABLE_INTRS) 20578c2ecf20Sopenharmony_ci temp64 &= ~((u64)intr_mask); 20588c2ecf20Sopenharmony_ci else 20598c2ecf20Sopenharmony_ci temp64 = DISABLE_ALL_INTRS; 20608c2ecf20Sopenharmony_ci writeq(temp64, &bar0->general_int_mask); 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci nic->general_int_mask = readq(&bar0->general_int_mask); 20638c2ecf20Sopenharmony_ci} 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci/** 20668c2ecf20Sopenharmony_ci * verify_pcc_quiescent- Checks for PCC quiescent state 20678c2ecf20Sopenharmony_ci * @sp : private member of the device structure, which is a pointer to the 20688c2ecf20Sopenharmony_ci * s2io_nic structure. 20698c2ecf20Sopenharmony_ci * @flag: boolean controlling function path 20708c2ecf20Sopenharmony_ci * Return: 1 If PCC is quiescence 20718c2ecf20Sopenharmony_ci * 0 If PCC is not quiescence 20728c2ecf20Sopenharmony_ci */ 20738c2ecf20Sopenharmony_cistatic int verify_pcc_quiescent(struct s2io_nic *sp, int flag) 20748c2ecf20Sopenharmony_ci{ 20758c2ecf20Sopenharmony_ci int ret = 0, herc; 20768c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 20778c2ecf20Sopenharmony_ci u64 val64 = readq(&bar0->adapter_status); 20788c2ecf20Sopenharmony_ci 20798c2ecf20Sopenharmony_ci herc = (sp->device_type == XFRAME_II_DEVICE); 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci if (flag == false) { 20828c2ecf20Sopenharmony_ci if ((!herc && (sp->pdev->revision >= 4)) || herc) { 20838c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE)) 20848c2ecf20Sopenharmony_ci ret = 1; 20858c2ecf20Sopenharmony_ci } else { 20868c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE)) 20878c2ecf20Sopenharmony_ci ret = 1; 20888c2ecf20Sopenharmony_ci } 20898c2ecf20Sopenharmony_ci } else { 20908c2ecf20Sopenharmony_ci if ((!herc && (sp->pdev->revision >= 4)) || herc) { 20918c2ecf20Sopenharmony_ci if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) == 20928c2ecf20Sopenharmony_ci ADAPTER_STATUS_RMAC_PCC_IDLE)) 20938c2ecf20Sopenharmony_ci ret = 1; 20948c2ecf20Sopenharmony_ci } else { 20958c2ecf20Sopenharmony_ci if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) == 20968c2ecf20Sopenharmony_ci ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE)) 20978c2ecf20Sopenharmony_ci ret = 1; 20988c2ecf20Sopenharmony_ci } 20998c2ecf20Sopenharmony_ci } 21008c2ecf20Sopenharmony_ci 21018c2ecf20Sopenharmony_ci return ret; 21028c2ecf20Sopenharmony_ci} 21038c2ecf20Sopenharmony_ci/** 21048c2ecf20Sopenharmony_ci * verify_xena_quiescence - Checks whether the H/W is ready 21058c2ecf20Sopenharmony_ci * @sp : private member of the device structure, which is a pointer to the 21068c2ecf20Sopenharmony_ci * s2io_nic structure. 21078c2ecf20Sopenharmony_ci * Description: Returns whether the H/W is ready to go or not. Depending 21088c2ecf20Sopenharmony_ci * on whether adapter enable bit was written or not the comparison 21098c2ecf20Sopenharmony_ci * differs and the calling function passes the input argument flag to 21108c2ecf20Sopenharmony_ci * indicate this. 21118c2ecf20Sopenharmony_ci * Return: 1 If xena is quiescence 21128c2ecf20Sopenharmony_ci * 0 If Xena is not quiescence 21138c2ecf20Sopenharmony_ci */ 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_cistatic int verify_xena_quiescence(struct s2io_nic *sp) 21168c2ecf20Sopenharmony_ci{ 21178c2ecf20Sopenharmony_ci int mode; 21188c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 21198c2ecf20Sopenharmony_ci u64 val64 = readq(&bar0->adapter_status); 21208c2ecf20Sopenharmony_ci mode = s2io_verify_pci_mode(sp); 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_TDMA_READY)) { 21238c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "TDMA is not ready!\n"); 21248c2ecf20Sopenharmony_ci return 0; 21258c2ecf20Sopenharmony_ci } 21268c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_RDMA_READY)) { 21278c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "RDMA is not ready!\n"); 21288c2ecf20Sopenharmony_ci return 0; 21298c2ecf20Sopenharmony_ci } 21308c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_PFC_READY)) { 21318c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "PFC is not ready!\n"); 21328c2ecf20Sopenharmony_ci return 0; 21338c2ecf20Sopenharmony_ci } 21348c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) { 21358c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "TMAC BUF is not empty!\n"); 21368c2ecf20Sopenharmony_ci return 0; 21378c2ecf20Sopenharmony_ci } 21388c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) { 21398c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "PIC is not QUIESCENT!\n"); 21408c2ecf20Sopenharmony_ci return 0; 21418c2ecf20Sopenharmony_ci } 21428c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) { 21438c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "MC_DRAM is not ready!\n"); 21448c2ecf20Sopenharmony_ci return 0; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) { 21478c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "MC_QUEUES is not ready!\n"); 21488c2ecf20Sopenharmony_ci return 0; 21498c2ecf20Sopenharmony_ci } 21508c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) { 21518c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "M_PLL is not locked!\n"); 21528c2ecf20Sopenharmony_ci return 0; 21538c2ecf20Sopenharmony_ci } 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci /* 21568c2ecf20Sopenharmony_ci * In PCI 33 mode, the P_PLL is not used, and therefore, 21578c2ecf20Sopenharmony_ci * the the P_PLL_LOCK bit in the adapter_status register will 21588c2ecf20Sopenharmony_ci * not be asserted. 21598c2ecf20Sopenharmony_ci */ 21608c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) && 21618c2ecf20Sopenharmony_ci sp->device_type == XFRAME_II_DEVICE && 21628c2ecf20Sopenharmony_ci mode != PCI_MODE_PCI_33) { 21638c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "P_PLL is not locked!\n"); 21648c2ecf20Sopenharmony_ci return 0; 21658c2ecf20Sopenharmony_ci } 21668c2ecf20Sopenharmony_ci if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) == 21678c2ecf20Sopenharmony_ci ADAPTER_STATUS_RC_PRC_QUIESCENT)) { 21688c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "RC_PRC is not QUIESCENT!\n"); 21698c2ecf20Sopenharmony_ci return 0; 21708c2ecf20Sopenharmony_ci } 21718c2ecf20Sopenharmony_ci return 1; 21728c2ecf20Sopenharmony_ci} 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci/** 21758c2ecf20Sopenharmony_ci * fix_mac_address - Fix for Mac addr problem on Alpha platforms 21768c2ecf20Sopenharmony_ci * @sp: Pointer to device specifc structure 21778c2ecf20Sopenharmony_ci * Description : 21788c2ecf20Sopenharmony_ci * New procedure to clear mac address reading problems on Alpha platforms 21798c2ecf20Sopenharmony_ci * 21808c2ecf20Sopenharmony_ci */ 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_cistatic void fix_mac_address(struct s2io_nic *sp) 21838c2ecf20Sopenharmony_ci{ 21848c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 21858c2ecf20Sopenharmony_ci int i = 0; 21868c2ecf20Sopenharmony_ci 21878c2ecf20Sopenharmony_ci while (fix_mac[i] != END_SIGN) { 21888c2ecf20Sopenharmony_ci writeq(fix_mac[i++], &bar0->gpio_control); 21898c2ecf20Sopenharmony_ci udelay(10); 21908c2ecf20Sopenharmony_ci (void) readq(&bar0->gpio_control); 21918c2ecf20Sopenharmony_ci } 21928c2ecf20Sopenharmony_ci} 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci/** 21958c2ecf20Sopenharmony_ci * start_nic - Turns the device on 21968c2ecf20Sopenharmony_ci * @nic : device private variable. 21978c2ecf20Sopenharmony_ci * Description: 21988c2ecf20Sopenharmony_ci * This function actually turns the device on. Before this function is 21998c2ecf20Sopenharmony_ci * called,all Registers are configured from their reset states 22008c2ecf20Sopenharmony_ci * and shared memory is allocated but the NIC is still quiescent. On 22018c2ecf20Sopenharmony_ci * calling this function, the device interrupts are cleared and the NIC is 22028c2ecf20Sopenharmony_ci * literally switched on by writing into the adapter control register. 22038c2ecf20Sopenharmony_ci * Return Value: 22048c2ecf20Sopenharmony_ci * SUCCESS on success and -1 on failure. 22058c2ecf20Sopenharmony_ci */ 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_cistatic int start_nic(struct s2io_nic *nic) 22088c2ecf20Sopenharmony_ci{ 22098c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 22108c2ecf20Sopenharmony_ci struct net_device *dev = nic->dev; 22118c2ecf20Sopenharmony_ci register u64 val64 = 0; 22128c2ecf20Sopenharmony_ci u16 subid, i; 22138c2ecf20Sopenharmony_ci struct config_param *config = &nic->config; 22148c2ecf20Sopenharmony_ci struct mac_info *mac_control = &nic->mac_control; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci /* PRC Initialization and configuration */ 22178c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 22188c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci writeq((u64)ring->rx_blocks[0].block_dma_addr, 22218c2ecf20Sopenharmony_ci &bar0->prc_rxd0_n[i]); 22228c2ecf20Sopenharmony_ci 22238c2ecf20Sopenharmony_ci val64 = readq(&bar0->prc_ctrl_n[i]); 22248c2ecf20Sopenharmony_ci if (nic->rxd_mode == RXD_MODE_1) 22258c2ecf20Sopenharmony_ci val64 |= PRC_CTRL_RC_ENABLED; 22268c2ecf20Sopenharmony_ci else 22278c2ecf20Sopenharmony_ci val64 |= PRC_CTRL_RC_ENABLED | PRC_CTRL_RING_MODE_3; 22288c2ecf20Sopenharmony_ci if (nic->device_type == XFRAME_II_DEVICE) 22298c2ecf20Sopenharmony_ci val64 |= PRC_CTRL_GROUP_READS; 22308c2ecf20Sopenharmony_ci val64 &= ~PRC_CTRL_RXD_BACKOFF_INTERVAL(0xFFFFFF); 22318c2ecf20Sopenharmony_ci val64 |= PRC_CTRL_RXD_BACKOFF_INTERVAL(0x1000); 22328c2ecf20Sopenharmony_ci writeq(val64, &bar0->prc_ctrl_n[i]); 22338c2ecf20Sopenharmony_ci } 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci if (nic->rxd_mode == RXD_MODE_3B) { 22368c2ecf20Sopenharmony_ci /* Enabling 2 buffer mode by writing into Rx_pa_cfg reg. */ 22378c2ecf20Sopenharmony_ci val64 = readq(&bar0->rx_pa_cfg); 22388c2ecf20Sopenharmony_ci val64 |= RX_PA_CFG_IGNORE_L2_ERR; 22398c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_pa_cfg); 22408c2ecf20Sopenharmony_ci } 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci if (vlan_tag_strip == 0) { 22438c2ecf20Sopenharmony_ci val64 = readq(&bar0->rx_pa_cfg); 22448c2ecf20Sopenharmony_ci val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG; 22458c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_pa_cfg); 22468c2ecf20Sopenharmony_ci nic->vlan_strip_flag = 0; 22478c2ecf20Sopenharmony_ci } 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci /* 22508c2ecf20Sopenharmony_ci * Enabling MC-RLDRAM. After enabling the device, we timeout 22518c2ecf20Sopenharmony_ci * for around 100ms, which is approximately the time required 22528c2ecf20Sopenharmony_ci * for the device to be ready for operation. 22538c2ecf20Sopenharmony_ci */ 22548c2ecf20Sopenharmony_ci val64 = readq(&bar0->mc_rldram_mrs); 22558c2ecf20Sopenharmony_ci val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE | MC_RLDRAM_MRS_ENABLE; 22568c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF); 22578c2ecf20Sopenharmony_ci val64 = readq(&bar0->mc_rldram_mrs); 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci msleep(100); /* Delay by around 100 ms. */ 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci /* Enabling ECC Protection. */ 22628c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_control); 22638c2ecf20Sopenharmony_ci val64 &= ~ADAPTER_ECC_EN; 22648c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 22658c2ecf20Sopenharmony_ci 22668c2ecf20Sopenharmony_ci /* 22678c2ecf20Sopenharmony_ci * Verify if the device is ready to be enabled, if so enable 22688c2ecf20Sopenharmony_ci * it. 22698c2ecf20Sopenharmony_ci */ 22708c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_status); 22718c2ecf20Sopenharmony_ci if (!verify_xena_quiescence(nic)) { 22728c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: device is not ready, " 22738c2ecf20Sopenharmony_ci "Adapter status reads: 0x%llx\n", 22748c2ecf20Sopenharmony_ci dev->name, (unsigned long long)val64); 22758c2ecf20Sopenharmony_ci return FAILURE; 22768c2ecf20Sopenharmony_ci } 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci /* 22798c2ecf20Sopenharmony_ci * With some switches, link might be already up at this point. 22808c2ecf20Sopenharmony_ci * Because of this weird behavior, when we enable laser, 22818c2ecf20Sopenharmony_ci * we may not get link. We need to handle this. We cannot 22828c2ecf20Sopenharmony_ci * figure out which switch is misbehaving. So we are forced to 22838c2ecf20Sopenharmony_ci * make a global change. 22848c2ecf20Sopenharmony_ci */ 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci /* Enabling Laser. */ 22878c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_control); 22888c2ecf20Sopenharmony_ci val64 |= ADAPTER_EOI_TX_ON; 22898c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { 22928c2ecf20Sopenharmony_ci /* 22938c2ecf20Sopenharmony_ci * Dont see link state interrupts initially on some switches, 22948c2ecf20Sopenharmony_ci * so directly scheduling the link state task here. 22958c2ecf20Sopenharmony_ci */ 22968c2ecf20Sopenharmony_ci schedule_work(&nic->set_link_task); 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci /* SXE-002: Initialize link and activity LED */ 22998c2ecf20Sopenharmony_ci subid = nic->pdev->subsystem_device; 23008c2ecf20Sopenharmony_ci if (((subid & 0xFF) >= 0x07) && 23018c2ecf20Sopenharmony_ci (nic->device_type == XFRAME_I_DEVICE)) { 23028c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_control); 23038c2ecf20Sopenharmony_ci val64 |= 0x0000800000000000ULL; 23048c2ecf20Sopenharmony_ci writeq(val64, &bar0->gpio_control); 23058c2ecf20Sopenharmony_ci val64 = 0x0411040400000000ULL; 23068c2ecf20Sopenharmony_ci writeq(val64, (void __iomem *)bar0 + 0x2700); 23078c2ecf20Sopenharmony_ci } 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci return SUCCESS; 23108c2ecf20Sopenharmony_ci} 23118c2ecf20Sopenharmony_ci/** 23128c2ecf20Sopenharmony_ci * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb 23138c2ecf20Sopenharmony_ci * @fifo_data: fifo data pointer 23148c2ecf20Sopenharmony_ci * @txdlp: descriptor 23158c2ecf20Sopenharmony_ci * @get_off: unused 23168c2ecf20Sopenharmony_ci */ 23178c2ecf20Sopenharmony_cistatic struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, 23188c2ecf20Sopenharmony_ci struct TxD *txdlp, int get_off) 23198c2ecf20Sopenharmony_ci{ 23208c2ecf20Sopenharmony_ci struct s2io_nic *nic = fifo_data->nic; 23218c2ecf20Sopenharmony_ci struct sk_buff *skb; 23228c2ecf20Sopenharmony_ci struct TxD *txds; 23238c2ecf20Sopenharmony_ci u16 j, frg_cnt; 23248c2ecf20Sopenharmony_ci 23258c2ecf20Sopenharmony_ci txds = txdlp; 23268c2ecf20Sopenharmony_ci if (txds->Host_Control == (u64)(long)fifo_data->ufo_in_band_v) { 23278c2ecf20Sopenharmony_ci dma_unmap_single(&nic->pdev->dev, 23288c2ecf20Sopenharmony_ci (dma_addr_t)txds->Buffer_Pointer, 23298c2ecf20Sopenharmony_ci sizeof(u64), DMA_TO_DEVICE); 23308c2ecf20Sopenharmony_ci txds++; 23318c2ecf20Sopenharmony_ci } 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci skb = (struct sk_buff *)((unsigned long)txds->Host_Control); 23348c2ecf20Sopenharmony_ci if (!skb) { 23358c2ecf20Sopenharmony_ci memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds)); 23368c2ecf20Sopenharmony_ci return NULL; 23378c2ecf20Sopenharmony_ci } 23388c2ecf20Sopenharmony_ci dma_unmap_single(&nic->pdev->dev, (dma_addr_t)txds->Buffer_Pointer, 23398c2ecf20Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 23408c2ecf20Sopenharmony_ci frg_cnt = skb_shinfo(skb)->nr_frags; 23418c2ecf20Sopenharmony_ci if (frg_cnt) { 23428c2ecf20Sopenharmony_ci txds++; 23438c2ecf20Sopenharmony_ci for (j = 0; j < frg_cnt; j++, txds++) { 23448c2ecf20Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[j]; 23458c2ecf20Sopenharmony_ci if (!txds->Buffer_Pointer) 23468c2ecf20Sopenharmony_ci break; 23478c2ecf20Sopenharmony_ci dma_unmap_page(&nic->pdev->dev, 23488c2ecf20Sopenharmony_ci (dma_addr_t)txds->Buffer_Pointer, 23498c2ecf20Sopenharmony_ci skb_frag_size(frag), DMA_TO_DEVICE); 23508c2ecf20Sopenharmony_ci } 23518c2ecf20Sopenharmony_ci } 23528c2ecf20Sopenharmony_ci memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds)); 23538c2ecf20Sopenharmony_ci return skb; 23548c2ecf20Sopenharmony_ci} 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci/** 23578c2ecf20Sopenharmony_ci * free_tx_buffers - Free all queued Tx buffers 23588c2ecf20Sopenharmony_ci * @nic : device private variable. 23598c2ecf20Sopenharmony_ci * Description: 23608c2ecf20Sopenharmony_ci * Free all queued Tx buffers. 23618c2ecf20Sopenharmony_ci * Return Value: void 23628c2ecf20Sopenharmony_ci */ 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_cistatic void free_tx_buffers(struct s2io_nic *nic) 23658c2ecf20Sopenharmony_ci{ 23668c2ecf20Sopenharmony_ci struct net_device *dev = nic->dev; 23678c2ecf20Sopenharmony_ci struct sk_buff *skb; 23688c2ecf20Sopenharmony_ci struct TxD *txdp; 23698c2ecf20Sopenharmony_ci int i, j; 23708c2ecf20Sopenharmony_ci int cnt = 0; 23718c2ecf20Sopenharmony_ci struct config_param *config = &nic->config; 23728c2ecf20Sopenharmony_ci struct mac_info *mac_control = &nic->mac_control; 23738c2ecf20Sopenharmony_ci struct stat_block *stats = mac_control->stats_info; 23748c2ecf20Sopenharmony_ci struct swStat *swstats = &stats->sw_stat; 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) { 23778c2ecf20Sopenharmony_ci struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; 23788c2ecf20Sopenharmony_ci struct fifo_info *fifo = &mac_control->fifos[i]; 23798c2ecf20Sopenharmony_ci unsigned long flags; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci spin_lock_irqsave(&fifo->tx_lock, flags); 23828c2ecf20Sopenharmony_ci for (j = 0; j < tx_cfg->fifo_len; j++) { 23838c2ecf20Sopenharmony_ci txdp = fifo->list_info[j].list_virt_addr; 23848c2ecf20Sopenharmony_ci skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j); 23858c2ecf20Sopenharmony_ci if (skb) { 23868c2ecf20Sopenharmony_ci swstats->mem_freed += skb->truesize; 23878c2ecf20Sopenharmony_ci dev_kfree_skb_irq(skb); 23888c2ecf20Sopenharmony_ci cnt++; 23898c2ecf20Sopenharmony_ci } 23908c2ecf20Sopenharmony_ci } 23918c2ecf20Sopenharmony_ci DBG_PRINT(INTR_DBG, 23928c2ecf20Sopenharmony_ci "%s: forcibly freeing %d skbs on FIFO%d\n", 23938c2ecf20Sopenharmony_ci dev->name, cnt, i); 23948c2ecf20Sopenharmony_ci fifo->tx_curr_get_info.offset = 0; 23958c2ecf20Sopenharmony_ci fifo->tx_curr_put_info.offset = 0; 23968c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fifo->tx_lock, flags); 23978c2ecf20Sopenharmony_ci } 23988c2ecf20Sopenharmony_ci} 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci/** 24018c2ecf20Sopenharmony_ci * stop_nic - To stop the nic 24028c2ecf20Sopenharmony_ci * @nic : device private variable. 24038c2ecf20Sopenharmony_ci * Description: 24048c2ecf20Sopenharmony_ci * This function does exactly the opposite of what the start_nic() 24058c2ecf20Sopenharmony_ci * function does. This function is called to stop the device. 24068c2ecf20Sopenharmony_ci * Return Value: 24078c2ecf20Sopenharmony_ci * void. 24088c2ecf20Sopenharmony_ci */ 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_cistatic void stop_nic(struct s2io_nic *nic) 24118c2ecf20Sopenharmony_ci{ 24128c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 24138c2ecf20Sopenharmony_ci register u64 val64 = 0; 24148c2ecf20Sopenharmony_ci u16 interruptible; 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_ci /* Disable all interrupts */ 24178c2ecf20Sopenharmony_ci en_dis_err_alarms(nic, ENA_ALL_INTRS, DISABLE_INTRS); 24188c2ecf20Sopenharmony_ci interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; 24198c2ecf20Sopenharmony_ci interruptible |= TX_PIC_INTR; 24208c2ecf20Sopenharmony_ci en_dis_able_nic_intrs(nic, interruptible, DISABLE_INTRS); 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_ci /* Clearing Adapter_En bit of ADAPTER_CONTROL Register */ 24238c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_control); 24248c2ecf20Sopenharmony_ci val64 &= ~(ADAPTER_CNTL_EN); 24258c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 24268c2ecf20Sopenharmony_ci} 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci/** 24298c2ecf20Sopenharmony_ci * fill_rx_buffers - Allocates the Rx side skbs 24308c2ecf20Sopenharmony_ci * @nic : device private variable. 24318c2ecf20Sopenharmony_ci * @ring: per ring structure 24328c2ecf20Sopenharmony_ci * @from_card_up: If this is true, we will map the buffer to get 24338c2ecf20Sopenharmony_ci * the dma address for buf0 and buf1 to give it to the card. 24348c2ecf20Sopenharmony_ci * Else we will sync the already mapped buffer to give it to the card. 24358c2ecf20Sopenharmony_ci * Description: 24368c2ecf20Sopenharmony_ci * The function allocates Rx side skbs and puts the physical 24378c2ecf20Sopenharmony_ci * address of these buffers into the RxD buffer pointers, so that the NIC 24388c2ecf20Sopenharmony_ci * can DMA the received frame into these locations. 24398c2ecf20Sopenharmony_ci * The NIC supports 3 receive modes, viz 24408c2ecf20Sopenharmony_ci * 1. single buffer, 24418c2ecf20Sopenharmony_ci * 2. three buffer and 24428c2ecf20Sopenharmony_ci * 3. Five buffer modes. 24438c2ecf20Sopenharmony_ci * Each mode defines how many fragments the received frame will be split 24448c2ecf20Sopenharmony_ci * up into by the NIC. The frame is split into L3 header, L4 Header, 24458c2ecf20Sopenharmony_ci * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself 24468c2ecf20Sopenharmony_ci * is split into 3 fragments. As of now only single buffer mode is 24478c2ecf20Sopenharmony_ci * supported. 24488c2ecf20Sopenharmony_ci * Return Value: 24498c2ecf20Sopenharmony_ci * SUCCESS on success or an appropriate -ve value on failure. 24508c2ecf20Sopenharmony_ci */ 24518c2ecf20Sopenharmony_cistatic int fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, 24528c2ecf20Sopenharmony_ci int from_card_up) 24538c2ecf20Sopenharmony_ci{ 24548c2ecf20Sopenharmony_ci struct sk_buff *skb; 24558c2ecf20Sopenharmony_ci struct RxD_t *rxdp; 24568c2ecf20Sopenharmony_ci int off, size, block_no, block_no1; 24578c2ecf20Sopenharmony_ci u32 alloc_tab = 0; 24588c2ecf20Sopenharmony_ci u32 alloc_cnt; 24598c2ecf20Sopenharmony_ci u64 tmp; 24608c2ecf20Sopenharmony_ci struct buffAdd *ba; 24618c2ecf20Sopenharmony_ci struct RxD_t *first_rxdp = NULL; 24628c2ecf20Sopenharmony_ci u64 Buffer0_ptr = 0, Buffer1_ptr = 0; 24638c2ecf20Sopenharmony_ci struct RxD1 *rxdp1; 24648c2ecf20Sopenharmony_ci struct RxD3 *rxdp3; 24658c2ecf20Sopenharmony_ci struct swStat *swstats = &ring->nic->mac_control.stats_info->sw_stat; 24668c2ecf20Sopenharmony_ci 24678c2ecf20Sopenharmony_ci alloc_cnt = ring->pkt_cnt - ring->rx_bufs_left; 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci block_no1 = ring->rx_curr_get_info.block_index; 24708c2ecf20Sopenharmony_ci while (alloc_tab < alloc_cnt) { 24718c2ecf20Sopenharmony_ci block_no = ring->rx_curr_put_info.block_index; 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci off = ring->rx_curr_put_info.offset; 24748c2ecf20Sopenharmony_ci 24758c2ecf20Sopenharmony_ci rxdp = ring->rx_blocks[block_no].rxds[off].virt_addr; 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci if ((block_no == block_no1) && 24788c2ecf20Sopenharmony_ci (off == ring->rx_curr_get_info.offset) && 24798c2ecf20Sopenharmony_ci (rxdp->Host_Control)) { 24808c2ecf20Sopenharmony_ci DBG_PRINT(INTR_DBG, "%s: Get and Put info equated\n", 24818c2ecf20Sopenharmony_ci ring->dev->name); 24828c2ecf20Sopenharmony_ci goto end; 24838c2ecf20Sopenharmony_ci } 24848c2ecf20Sopenharmony_ci if (off && (off == ring->rxd_count)) { 24858c2ecf20Sopenharmony_ci ring->rx_curr_put_info.block_index++; 24868c2ecf20Sopenharmony_ci if (ring->rx_curr_put_info.block_index == 24878c2ecf20Sopenharmony_ci ring->block_count) 24888c2ecf20Sopenharmony_ci ring->rx_curr_put_info.block_index = 0; 24898c2ecf20Sopenharmony_ci block_no = ring->rx_curr_put_info.block_index; 24908c2ecf20Sopenharmony_ci off = 0; 24918c2ecf20Sopenharmony_ci ring->rx_curr_put_info.offset = off; 24928c2ecf20Sopenharmony_ci rxdp = ring->rx_blocks[block_no].block_virt_addr; 24938c2ecf20Sopenharmony_ci DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n", 24948c2ecf20Sopenharmony_ci ring->dev->name, rxdp); 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci } 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_ci if ((rxdp->Control_1 & RXD_OWN_XENA) && 24998c2ecf20Sopenharmony_ci ((ring->rxd_mode == RXD_MODE_3B) && 25008c2ecf20Sopenharmony_ci (rxdp->Control_2 & s2BIT(0)))) { 25018c2ecf20Sopenharmony_ci ring->rx_curr_put_info.offset = off; 25028c2ecf20Sopenharmony_ci goto end; 25038c2ecf20Sopenharmony_ci } 25048c2ecf20Sopenharmony_ci /* calculate size of skb based on ring mode */ 25058c2ecf20Sopenharmony_ci size = ring->mtu + 25068c2ecf20Sopenharmony_ci HEADER_ETHERNET_II_802_3_SIZE + 25078c2ecf20Sopenharmony_ci HEADER_802_2_SIZE + HEADER_SNAP_SIZE; 25088c2ecf20Sopenharmony_ci if (ring->rxd_mode == RXD_MODE_1) 25098c2ecf20Sopenharmony_ci size += NET_IP_ALIGN; 25108c2ecf20Sopenharmony_ci else 25118c2ecf20Sopenharmony_ci size = ring->mtu + ALIGN_SIZE + BUF0_LEN + 4; 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci /* allocate skb */ 25148c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(nic->dev, size); 25158c2ecf20Sopenharmony_ci if (!skb) { 25168c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: Could not allocate skb\n", 25178c2ecf20Sopenharmony_ci ring->dev->name); 25188c2ecf20Sopenharmony_ci if (first_rxdp) { 25198c2ecf20Sopenharmony_ci dma_wmb(); 25208c2ecf20Sopenharmony_ci first_rxdp->Control_1 |= RXD_OWN_XENA; 25218c2ecf20Sopenharmony_ci } 25228c2ecf20Sopenharmony_ci swstats->mem_alloc_fail_cnt++; 25238c2ecf20Sopenharmony_ci 25248c2ecf20Sopenharmony_ci return -ENOMEM ; 25258c2ecf20Sopenharmony_ci } 25268c2ecf20Sopenharmony_ci swstats->mem_allocated += skb->truesize; 25278c2ecf20Sopenharmony_ci 25288c2ecf20Sopenharmony_ci if (ring->rxd_mode == RXD_MODE_1) { 25298c2ecf20Sopenharmony_ci /* 1 buffer mode - normal operation mode */ 25308c2ecf20Sopenharmony_ci rxdp1 = (struct RxD1 *)rxdp; 25318c2ecf20Sopenharmony_ci memset(rxdp, 0, sizeof(struct RxD1)); 25328c2ecf20Sopenharmony_ci skb_reserve(skb, NET_IP_ALIGN); 25338c2ecf20Sopenharmony_ci rxdp1->Buffer0_ptr = 25348c2ecf20Sopenharmony_ci dma_map_single(&ring->pdev->dev, skb->data, 25358c2ecf20Sopenharmony_ci size - NET_IP_ALIGN, 25368c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 25378c2ecf20Sopenharmony_ci if (dma_mapping_error(&nic->pdev->dev, rxdp1->Buffer0_ptr)) 25388c2ecf20Sopenharmony_ci goto pci_map_failed; 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci rxdp->Control_2 = 25418c2ecf20Sopenharmony_ci SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN); 25428c2ecf20Sopenharmony_ci rxdp->Host_Control = (unsigned long)skb; 25438c2ecf20Sopenharmony_ci } else if (ring->rxd_mode == RXD_MODE_3B) { 25448c2ecf20Sopenharmony_ci /* 25458c2ecf20Sopenharmony_ci * 2 buffer mode - 25468c2ecf20Sopenharmony_ci * 2 buffer mode provides 128 25478c2ecf20Sopenharmony_ci * byte aligned receive buffers. 25488c2ecf20Sopenharmony_ci */ 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci rxdp3 = (struct RxD3 *)rxdp; 25518c2ecf20Sopenharmony_ci /* save buffer pointers to avoid frequent dma mapping */ 25528c2ecf20Sopenharmony_ci Buffer0_ptr = rxdp3->Buffer0_ptr; 25538c2ecf20Sopenharmony_ci Buffer1_ptr = rxdp3->Buffer1_ptr; 25548c2ecf20Sopenharmony_ci memset(rxdp, 0, sizeof(struct RxD3)); 25558c2ecf20Sopenharmony_ci /* restore the buffer pointers for dma sync*/ 25568c2ecf20Sopenharmony_ci rxdp3->Buffer0_ptr = Buffer0_ptr; 25578c2ecf20Sopenharmony_ci rxdp3->Buffer1_ptr = Buffer1_ptr; 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci ba = &ring->ba[block_no][off]; 25608c2ecf20Sopenharmony_ci skb_reserve(skb, BUF0_LEN); 25618c2ecf20Sopenharmony_ci tmp = (u64)(unsigned long)skb->data; 25628c2ecf20Sopenharmony_ci tmp += ALIGN_SIZE; 25638c2ecf20Sopenharmony_ci tmp &= ~ALIGN_SIZE; 25648c2ecf20Sopenharmony_ci skb->data = (void *) (unsigned long)tmp; 25658c2ecf20Sopenharmony_ci skb_reset_tail_pointer(skb); 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci if (from_card_up) { 25688c2ecf20Sopenharmony_ci rxdp3->Buffer0_ptr = 25698c2ecf20Sopenharmony_ci dma_map_single(&ring->pdev->dev, 25708c2ecf20Sopenharmony_ci ba->ba_0, BUF0_LEN, 25718c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 25728c2ecf20Sopenharmony_ci if (dma_mapping_error(&nic->pdev->dev, rxdp3->Buffer0_ptr)) 25738c2ecf20Sopenharmony_ci goto pci_map_failed; 25748c2ecf20Sopenharmony_ci } else 25758c2ecf20Sopenharmony_ci dma_sync_single_for_device(&ring->pdev->dev, 25768c2ecf20Sopenharmony_ci (dma_addr_t)rxdp3->Buffer0_ptr, 25778c2ecf20Sopenharmony_ci BUF0_LEN, 25788c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN); 25818c2ecf20Sopenharmony_ci if (ring->rxd_mode == RXD_MODE_3B) { 25828c2ecf20Sopenharmony_ci /* Two buffer mode */ 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci /* 25858c2ecf20Sopenharmony_ci * Buffer2 will have L3/L4 header plus 25868c2ecf20Sopenharmony_ci * L4 payload 25878c2ecf20Sopenharmony_ci */ 25888c2ecf20Sopenharmony_ci rxdp3->Buffer2_ptr = dma_map_single(&ring->pdev->dev, 25898c2ecf20Sopenharmony_ci skb->data, 25908c2ecf20Sopenharmony_ci ring->mtu + 4, 25918c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci if (dma_mapping_error(&nic->pdev->dev, rxdp3->Buffer2_ptr)) 25948c2ecf20Sopenharmony_ci goto pci_map_failed; 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci if (from_card_up) { 25978c2ecf20Sopenharmony_ci rxdp3->Buffer1_ptr = 25988c2ecf20Sopenharmony_ci dma_map_single(&ring->pdev->dev, 25998c2ecf20Sopenharmony_ci ba->ba_1, 26008c2ecf20Sopenharmony_ci BUF1_LEN, 26018c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci if (dma_mapping_error(&nic->pdev->dev, 26048c2ecf20Sopenharmony_ci rxdp3->Buffer1_ptr)) { 26058c2ecf20Sopenharmony_ci dma_unmap_single(&ring->pdev->dev, 26068c2ecf20Sopenharmony_ci (dma_addr_t)(unsigned long) 26078c2ecf20Sopenharmony_ci skb->data, 26088c2ecf20Sopenharmony_ci ring->mtu + 4, 26098c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 26108c2ecf20Sopenharmony_ci goto pci_map_failed; 26118c2ecf20Sopenharmony_ci } 26128c2ecf20Sopenharmony_ci } 26138c2ecf20Sopenharmony_ci rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1); 26148c2ecf20Sopenharmony_ci rxdp->Control_2 |= SET_BUFFER2_SIZE_3 26158c2ecf20Sopenharmony_ci (ring->mtu + 4); 26168c2ecf20Sopenharmony_ci } 26178c2ecf20Sopenharmony_ci rxdp->Control_2 |= s2BIT(0); 26188c2ecf20Sopenharmony_ci rxdp->Host_Control = (unsigned long) (skb); 26198c2ecf20Sopenharmony_ci } 26208c2ecf20Sopenharmony_ci if (alloc_tab & ((1 << rxsync_frequency) - 1)) 26218c2ecf20Sopenharmony_ci rxdp->Control_1 |= RXD_OWN_XENA; 26228c2ecf20Sopenharmony_ci off++; 26238c2ecf20Sopenharmony_ci if (off == (ring->rxd_count + 1)) 26248c2ecf20Sopenharmony_ci off = 0; 26258c2ecf20Sopenharmony_ci ring->rx_curr_put_info.offset = off; 26268c2ecf20Sopenharmony_ci 26278c2ecf20Sopenharmony_ci rxdp->Control_2 |= SET_RXD_MARKER; 26288c2ecf20Sopenharmony_ci if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) { 26298c2ecf20Sopenharmony_ci if (first_rxdp) { 26308c2ecf20Sopenharmony_ci dma_wmb(); 26318c2ecf20Sopenharmony_ci first_rxdp->Control_1 |= RXD_OWN_XENA; 26328c2ecf20Sopenharmony_ci } 26338c2ecf20Sopenharmony_ci first_rxdp = rxdp; 26348c2ecf20Sopenharmony_ci } 26358c2ecf20Sopenharmony_ci ring->rx_bufs_left += 1; 26368c2ecf20Sopenharmony_ci alloc_tab++; 26378c2ecf20Sopenharmony_ci } 26388c2ecf20Sopenharmony_ci 26398c2ecf20Sopenharmony_ciend: 26408c2ecf20Sopenharmony_ci /* Transfer ownership of first descriptor to adapter just before 26418c2ecf20Sopenharmony_ci * exiting. Before that, use memory barrier so that ownership 26428c2ecf20Sopenharmony_ci * and other fields are seen by adapter correctly. 26438c2ecf20Sopenharmony_ci */ 26448c2ecf20Sopenharmony_ci if (first_rxdp) { 26458c2ecf20Sopenharmony_ci dma_wmb(); 26468c2ecf20Sopenharmony_ci first_rxdp->Control_1 |= RXD_OWN_XENA; 26478c2ecf20Sopenharmony_ci } 26488c2ecf20Sopenharmony_ci 26498c2ecf20Sopenharmony_ci return SUCCESS; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_cipci_map_failed: 26528c2ecf20Sopenharmony_ci swstats->pci_map_fail_cnt++; 26538c2ecf20Sopenharmony_ci swstats->mem_freed += skb->truesize; 26548c2ecf20Sopenharmony_ci dev_kfree_skb_irq(skb); 26558c2ecf20Sopenharmony_ci return -ENOMEM; 26568c2ecf20Sopenharmony_ci} 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_cistatic void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk) 26598c2ecf20Sopenharmony_ci{ 26608c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 26618c2ecf20Sopenharmony_ci int j; 26628c2ecf20Sopenharmony_ci struct sk_buff *skb; 26638c2ecf20Sopenharmony_ci struct RxD_t *rxdp; 26648c2ecf20Sopenharmony_ci struct RxD1 *rxdp1; 26658c2ecf20Sopenharmony_ci struct RxD3 *rxdp3; 26668c2ecf20Sopenharmony_ci struct mac_info *mac_control = &sp->mac_control; 26678c2ecf20Sopenharmony_ci struct stat_block *stats = mac_control->stats_info; 26688c2ecf20Sopenharmony_ci struct swStat *swstats = &stats->sw_stat; 26698c2ecf20Sopenharmony_ci 26708c2ecf20Sopenharmony_ci for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) { 26718c2ecf20Sopenharmony_ci rxdp = mac_control->rings[ring_no]. 26728c2ecf20Sopenharmony_ci rx_blocks[blk].rxds[j].virt_addr; 26738c2ecf20Sopenharmony_ci skb = (struct sk_buff *)((unsigned long)rxdp->Host_Control); 26748c2ecf20Sopenharmony_ci if (!skb) 26758c2ecf20Sopenharmony_ci continue; 26768c2ecf20Sopenharmony_ci if (sp->rxd_mode == RXD_MODE_1) { 26778c2ecf20Sopenharmony_ci rxdp1 = (struct RxD1 *)rxdp; 26788c2ecf20Sopenharmony_ci dma_unmap_single(&sp->pdev->dev, 26798c2ecf20Sopenharmony_ci (dma_addr_t)rxdp1->Buffer0_ptr, 26808c2ecf20Sopenharmony_ci dev->mtu + 26818c2ecf20Sopenharmony_ci HEADER_ETHERNET_II_802_3_SIZE + 26828c2ecf20Sopenharmony_ci HEADER_802_2_SIZE + HEADER_SNAP_SIZE, 26838c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 26848c2ecf20Sopenharmony_ci memset(rxdp, 0, sizeof(struct RxD1)); 26858c2ecf20Sopenharmony_ci } else if (sp->rxd_mode == RXD_MODE_3B) { 26868c2ecf20Sopenharmony_ci rxdp3 = (struct RxD3 *)rxdp; 26878c2ecf20Sopenharmony_ci dma_unmap_single(&sp->pdev->dev, 26888c2ecf20Sopenharmony_ci (dma_addr_t)rxdp3->Buffer0_ptr, 26898c2ecf20Sopenharmony_ci BUF0_LEN, DMA_FROM_DEVICE); 26908c2ecf20Sopenharmony_ci dma_unmap_single(&sp->pdev->dev, 26918c2ecf20Sopenharmony_ci (dma_addr_t)rxdp3->Buffer1_ptr, 26928c2ecf20Sopenharmony_ci BUF1_LEN, DMA_FROM_DEVICE); 26938c2ecf20Sopenharmony_ci dma_unmap_single(&sp->pdev->dev, 26948c2ecf20Sopenharmony_ci (dma_addr_t)rxdp3->Buffer2_ptr, 26958c2ecf20Sopenharmony_ci dev->mtu + 4, DMA_FROM_DEVICE); 26968c2ecf20Sopenharmony_ci memset(rxdp, 0, sizeof(struct RxD3)); 26978c2ecf20Sopenharmony_ci } 26988c2ecf20Sopenharmony_ci swstats->mem_freed += skb->truesize; 26998c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 27008c2ecf20Sopenharmony_ci mac_control->rings[ring_no].rx_bufs_left -= 1; 27018c2ecf20Sopenharmony_ci } 27028c2ecf20Sopenharmony_ci} 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_ci/** 27058c2ecf20Sopenharmony_ci * free_rx_buffers - Frees all Rx buffers 27068c2ecf20Sopenharmony_ci * @sp: device private variable. 27078c2ecf20Sopenharmony_ci * Description: 27088c2ecf20Sopenharmony_ci * This function will free all Rx buffers allocated by host. 27098c2ecf20Sopenharmony_ci * Return Value: 27108c2ecf20Sopenharmony_ci * NONE. 27118c2ecf20Sopenharmony_ci */ 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_cistatic void free_rx_buffers(struct s2io_nic *sp) 27148c2ecf20Sopenharmony_ci{ 27158c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 27168c2ecf20Sopenharmony_ci int i, blk = 0, buf_cnt = 0; 27178c2ecf20Sopenharmony_ci struct config_param *config = &sp->config; 27188c2ecf20Sopenharmony_ci struct mac_info *mac_control = &sp->mac_control; 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 27218c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci for (blk = 0; blk < rx_ring_sz[i]; blk++) 27248c2ecf20Sopenharmony_ci free_rxd_blk(sp, i, blk); 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci ring->rx_curr_put_info.block_index = 0; 27278c2ecf20Sopenharmony_ci ring->rx_curr_get_info.block_index = 0; 27288c2ecf20Sopenharmony_ci ring->rx_curr_put_info.offset = 0; 27298c2ecf20Sopenharmony_ci ring->rx_curr_get_info.offset = 0; 27308c2ecf20Sopenharmony_ci ring->rx_bufs_left = 0; 27318c2ecf20Sopenharmony_ci DBG_PRINT(INIT_DBG, "%s: Freed 0x%x Rx Buffers on ring%d\n", 27328c2ecf20Sopenharmony_ci dev->name, buf_cnt, i); 27338c2ecf20Sopenharmony_ci } 27348c2ecf20Sopenharmony_ci} 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_cistatic int s2io_chk_rx_buffers(struct s2io_nic *nic, struct ring_info *ring) 27378c2ecf20Sopenharmony_ci{ 27388c2ecf20Sopenharmony_ci if (fill_rx_buffers(nic, ring, 0) == -ENOMEM) { 27398c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: Out of memory in Rx Intr!!\n", 27408c2ecf20Sopenharmony_ci ring->dev->name); 27418c2ecf20Sopenharmony_ci } 27428c2ecf20Sopenharmony_ci return 0; 27438c2ecf20Sopenharmony_ci} 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci/** 27468c2ecf20Sopenharmony_ci * s2io_poll - Rx interrupt handler for NAPI support 27478c2ecf20Sopenharmony_ci * @napi : pointer to the napi structure. 27488c2ecf20Sopenharmony_ci * @budget : The number of packets that were budgeted to be processed 27498c2ecf20Sopenharmony_ci * during one pass through the 'Poll" function. 27508c2ecf20Sopenharmony_ci * Description: 27518c2ecf20Sopenharmony_ci * Comes into picture only if NAPI support has been incorporated. It does 27528c2ecf20Sopenharmony_ci * the same thing that rx_intr_handler does, but not in a interrupt context 27538c2ecf20Sopenharmony_ci * also It will process only a given number of packets. 27548c2ecf20Sopenharmony_ci * Return value: 27558c2ecf20Sopenharmony_ci * 0 on success and 1 if there are No Rx packets to be processed. 27568c2ecf20Sopenharmony_ci */ 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_cistatic int s2io_poll_msix(struct napi_struct *napi, int budget) 27598c2ecf20Sopenharmony_ci{ 27608c2ecf20Sopenharmony_ci struct ring_info *ring = container_of(napi, struct ring_info, napi); 27618c2ecf20Sopenharmony_ci struct net_device *dev = ring->dev; 27628c2ecf20Sopenharmony_ci int pkts_processed = 0; 27638c2ecf20Sopenharmony_ci u8 __iomem *addr = NULL; 27648c2ecf20Sopenharmony_ci u8 val8 = 0; 27658c2ecf20Sopenharmony_ci struct s2io_nic *nic = netdev_priv(dev); 27668c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 27678c2ecf20Sopenharmony_ci int budget_org = budget; 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci if (unlikely(!is_s2io_card_up(nic))) 27708c2ecf20Sopenharmony_ci return 0; 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci pkts_processed = rx_intr_handler(ring, budget); 27738c2ecf20Sopenharmony_ci s2io_chk_rx_buffers(nic, ring); 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci if (pkts_processed < budget_org) { 27768c2ecf20Sopenharmony_ci napi_complete_done(napi, pkts_processed); 27778c2ecf20Sopenharmony_ci /*Re Enable MSI-Rx Vector*/ 27788c2ecf20Sopenharmony_ci addr = (u8 __iomem *)&bar0->xmsi_mask_reg; 27798c2ecf20Sopenharmony_ci addr += 7 - ring->ring_no; 27808c2ecf20Sopenharmony_ci val8 = (ring->ring_no == 0) ? 0x3f : 0xbf; 27818c2ecf20Sopenharmony_ci writeb(val8, addr); 27828c2ecf20Sopenharmony_ci val8 = readb(addr); 27838c2ecf20Sopenharmony_ci } 27848c2ecf20Sopenharmony_ci return pkts_processed; 27858c2ecf20Sopenharmony_ci} 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_cistatic int s2io_poll_inta(struct napi_struct *napi, int budget) 27888c2ecf20Sopenharmony_ci{ 27898c2ecf20Sopenharmony_ci struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); 27908c2ecf20Sopenharmony_ci int pkts_processed = 0; 27918c2ecf20Sopenharmony_ci int ring_pkts_processed, i; 27928c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 27938c2ecf20Sopenharmony_ci int budget_org = budget; 27948c2ecf20Sopenharmony_ci struct config_param *config = &nic->config; 27958c2ecf20Sopenharmony_ci struct mac_info *mac_control = &nic->mac_control; 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci if (unlikely(!is_s2io_card_up(nic))) 27988c2ecf20Sopenharmony_ci return 0; 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 28018c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 28028c2ecf20Sopenharmony_ci ring_pkts_processed = rx_intr_handler(ring, budget); 28038c2ecf20Sopenharmony_ci s2io_chk_rx_buffers(nic, ring); 28048c2ecf20Sopenharmony_ci pkts_processed += ring_pkts_processed; 28058c2ecf20Sopenharmony_ci budget -= ring_pkts_processed; 28068c2ecf20Sopenharmony_ci if (budget <= 0) 28078c2ecf20Sopenharmony_ci break; 28088c2ecf20Sopenharmony_ci } 28098c2ecf20Sopenharmony_ci if (pkts_processed < budget_org) { 28108c2ecf20Sopenharmony_ci napi_complete_done(napi, pkts_processed); 28118c2ecf20Sopenharmony_ci /* Re enable the Rx interrupts for the ring */ 28128c2ecf20Sopenharmony_ci writeq(0, &bar0->rx_traffic_mask); 28138c2ecf20Sopenharmony_ci readl(&bar0->rx_traffic_mask); 28148c2ecf20Sopenharmony_ci } 28158c2ecf20Sopenharmony_ci return pkts_processed; 28168c2ecf20Sopenharmony_ci} 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 28198c2ecf20Sopenharmony_ci/** 28208c2ecf20Sopenharmony_ci * s2io_netpoll - netpoll event handler entry point 28218c2ecf20Sopenharmony_ci * @dev : pointer to the device structure. 28228c2ecf20Sopenharmony_ci * Description: 28238c2ecf20Sopenharmony_ci * This function will be called by upper layer to check for events on the 28248c2ecf20Sopenharmony_ci * interface in situations where interrupts are disabled. It is used for 28258c2ecf20Sopenharmony_ci * specific in-kernel networking tasks, such as remote consoles and kernel 28268c2ecf20Sopenharmony_ci * debugging over the network (example netdump in RedHat). 28278c2ecf20Sopenharmony_ci */ 28288c2ecf20Sopenharmony_cistatic void s2io_netpoll(struct net_device *dev) 28298c2ecf20Sopenharmony_ci{ 28308c2ecf20Sopenharmony_ci struct s2io_nic *nic = netdev_priv(dev); 28318c2ecf20Sopenharmony_ci const int irq = nic->pdev->irq; 28328c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 28338c2ecf20Sopenharmony_ci u64 val64 = 0xFFFFFFFFFFFFFFFFULL; 28348c2ecf20Sopenharmony_ci int i; 28358c2ecf20Sopenharmony_ci struct config_param *config = &nic->config; 28368c2ecf20Sopenharmony_ci struct mac_info *mac_control = &nic->mac_control; 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci if (pci_channel_offline(nic->pdev)) 28398c2ecf20Sopenharmony_ci return; 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci disable_irq(irq); 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_traffic_int); 28448c2ecf20Sopenharmony_ci writeq(val64, &bar0->tx_traffic_int); 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci /* we need to free up the transmitted skbufs or else netpoll will 28478c2ecf20Sopenharmony_ci * run out of skbs and will fail and eventually netpoll application such 28488c2ecf20Sopenharmony_ci * as netdump will fail. 28498c2ecf20Sopenharmony_ci */ 28508c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) 28518c2ecf20Sopenharmony_ci tx_intr_handler(&mac_control->fifos[i]); 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci /* check for received packet and indicate up to network */ 28548c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 28558c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_ci rx_intr_handler(ring, 0); 28588c2ecf20Sopenharmony_ci } 28598c2ecf20Sopenharmony_ci 28608c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 28618c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci if (fill_rx_buffers(nic, ring, 0) == -ENOMEM) { 28648c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, 28658c2ecf20Sopenharmony_ci "%s: Out of memory in Rx Netpoll!!\n", 28668c2ecf20Sopenharmony_ci dev->name); 28678c2ecf20Sopenharmony_ci break; 28688c2ecf20Sopenharmony_ci } 28698c2ecf20Sopenharmony_ci } 28708c2ecf20Sopenharmony_ci enable_irq(irq); 28718c2ecf20Sopenharmony_ci} 28728c2ecf20Sopenharmony_ci#endif 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci/** 28758c2ecf20Sopenharmony_ci * rx_intr_handler - Rx interrupt handler 28768c2ecf20Sopenharmony_ci * @ring_data: per ring structure. 28778c2ecf20Sopenharmony_ci * @budget: budget for napi processing. 28788c2ecf20Sopenharmony_ci * Description: 28798c2ecf20Sopenharmony_ci * If the interrupt is because of a received frame or if the 28808c2ecf20Sopenharmony_ci * receive ring contains fresh as yet un-processed frames,this function is 28818c2ecf20Sopenharmony_ci * called. It picks out the RxD at which place the last Rx processing had 28828c2ecf20Sopenharmony_ci * stopped and sends the skb to the OSM's Rx handler and then increments 28838c2ecf20Sopenharmony_ci * the offset. 28848c2ecf20Sopenharmony_ci * Return Value: 28858c2ecf20Sopenharmony_ci * No. of napi packets processed. 28868c2ecf20Sopenharmony_ci */ 28878c2ecf20Sopenharmony_cistatic int rx_intr_handler(struct ring_info *ring_data, int budget) 28888c2ecf20Sopenharmony_ci{ 28898c2ecf20Sopenharmony_ci int get_block, put_block; 28908c2ecf20Sopenharmony_ci struct rx_curr_get_info get_info, put_info; 28918c2ecf20Sopenharmony_ci struct RxD_t *rxdp; 28928c2ecf20Sopenharmony_ci struct sk_buff *skb; 28938c2ecf20Sopenharmony_ci int pkt_cnt = 0, napi_pkts = 0; 28948c2ecf20Sopenharmony_ci int i; 28958c2ecf20Sopenharmony_ci struct RxD1 *rxdp1; 28968c2ecf20Sopenharmony_ci struct RxD3 *rxdp3; 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ci if (budget <= 0) 28998c2ecf20Sopenharmony_ci return napi_pkts; 29008c2ecf20Sopenharmony_ci 29018c2ecf20Sopenharmony_ci get_info = ring_data->rx_curr_get_info; 29028c2ecf20Sopenharmony_ci get_block = get_info.block_index; 29038c2ecf20Sopenharmony_ci memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info)); 29048c2ecf20Sopenharmony_ci put_block = put_info.block_index; 29058c2ecf20Sopenharmony_ci rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr; 29068c2ecf20Sopenharmony_ci 29078c2ecf20Sopenharmony_ci while (RXD_IS_UP2DT(rxdp)) { 29088c2ecf20Sopenharmony_ci /* 29098c2ecf20Sopenharmony_ci * If your are next to put index then it's 29108c2ecf20Sopenharmony_ci * FIFO full condition 29118c2ecf20Sopenharmony_ci */ 29128c2ecf20Sopenharmony_ci if ((get_block == put_block) && 29138c2ecf20Sopenharmony_ci (get_info.offset + 1) == put_info.offset) { 29148c2ecf20Sopenharmony_ci DBG_PRINT(INTR_DBG, "%s: Ring Full\n", 29158c2ecf20Sopenharmony_ci ring_data->dev->name); 29168c2ecf20Sopenharmony_ci break; 29178c2ecf20Sopenharmony_ci } 29188c2ecf20Sopenharmony_ci skb = (struct sk_buff *)((unsigned long)rxdp->Host_Control); 29198c2ecf20Sopenharmony_ci if (skb == NULL) { 29208c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: NULL skb in Rx Intr\n", 29218c2ecf20Sopenharmony_ci ring_data->dev->name); 29228c2ecf20Sopenharmony_ci return 0; 29238c2ecf20Sopenharmony_ci } 29248c2ecf20Sopenharmony_ci if (ring_data->rxd_mode == RXD_MODE_1) { 29258c2ecf20Sopenharmony_ci rxdp1 = (struct RxD1 *)rxdp; 29268c2ecf20Sopenharmony_ci dma_unmap_single(&ring_data->pdev->dev, 29278c2ecf20Sopenharmony_ci (dma_addr_t)rxdp1->Buffer0_ptr, 29288c2ecf20Sopenharmony_ci ring_data->mtu + 29298c2ecf20Sopenharmony_ci HEADER_ETHERNET_II_802_3_SIZE + 29308c2ecf20Sopenharmony_ci HEADER_802_2_SIZE + 29318c2ecf20Sopenharmony_ci HEADER_SNAP_SIZE, 29328c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 29338c2ecf20Sopenharmony_ci } else if (ring_data->rxd_mode == RXD_MODE_3B) { 29348c2ecf20Sopenharmony_ci rxdp3 = (struct RxD3 *)rxdp; 29358c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&ring_data->pdev->dev, 29368c2ecf20Sopenharmony_ci (dma_addr_t)rxdp3->Buffer0_ptr, 29378c2ecf20Sopenharmony_ci BUF0_LEN, DMA_FROM_DEVICE); 29388c2ecf20Sopenharmony_ci dma_unmap_single(&ring_data->pdev->dev, 29398c2ecf20Sopenharmony_ci (dma_addr_t)rxdp3->Buffer2_ptr, 29408c2ecf20Sopenharmony_ci ring_data->mtu + 4, DMA_FROM_DEVICE); 29418c2ecf20Sopenharmony_ci } 29428c2ecf20Sopenharmony_ci prefetch(skb->data); 29438c2ecf20Sopenharmony_ci rx_osm_handler(ring_data, rxdp); 29448c2ecf20Sopenharmony_ci get_info.offset++; 29458c2ecf20Sopenharmony_ci ring_data->rx_curr_get_info.offset = get_info.offset; 29468c2ecf20Sopenharmony_ci rxdp = ring_data->rx_blocks[get_block]. 29478c2ecf20Sopenharmony_ci rxds[get_info.offset].virt_addr; 29488c2ecf20Sopenharmony_ci if (get_info.offset == rxd_count[ring_data->rxd_mode]) { 29498c2ecf20Sopenharmony_ci get_info.offset = 0; 29508c2ecf20Sopenharmony_ci ring_data->rx_curr_get_info.offset = get_info.offset; 29518c2ecf20Sopenharmony_ci get_block++; 29528c2ecf20Sopenharmony_ci if (get_block == ring_data->block_count) 29538c2ecf20Sopenharmony_ci get_block = 0; 29548c2ecf20Sopenharmony_ci ring_data->rx_curr_get_info.block_index = get_block; 29558c2ecf20Sopenharmony_ci rxdp = ring_data->rx_blocks[get_block].block_virt_addr; 29568c2ecf20Sopenharmony_ci } 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci if (ring_data->nic->config.napi) { 29598c2ecf20Sopenharmony_ci budget--; 29608c2ecf20Sopenharmony_ci napi_pkts++; 29618c2ecf20Sopenharmony_ci if (!budget) 29628c2ecf20Sopenharmony_ci break; 29638c2ecf20Sopenharmony_ci } 29648c2ecf20Sopenharmony_ci pkt_cnt++; 29658c2ecf20Sopenharmony_ci if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts)) 29668c2ecf20Sopenharmony_ci break; 29678c2ecf20Sopenharmony_ci } 29688c2ecf20Sopenharmony_ci if (ring_data->lro) { 29698c2ecf20Sopenharmony_ci /* Clear all LRO sessions before exiting */ 29708c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LRO_SESSIONS; i++) { 29718c2ecf20Sopenharmony_ci struct lro *lro = &ring_data->lro0_n[i]; 29728c2ecf20Sopenharmony_ci if (lro->in_use) { 29738c2ecf20Sopenharmony_ci update_L3L4_header(ring_data->nic, lro); 29748c2ecf20Sopenharmony_ci queue_rx_frame(lro->parent, lro->vlan_tag); 29758c2ecf20Sopenharmony_ci clear_lro_session(lro); 29768c2ecf20Sopenharmony_ci } 29778c2ecf20Sopenharmony_ci } 29788c2ecf20Sopenharmony_ci } 29798c2ecf20Sopenharmony_ci return napi_pkts; 29808c2ecf20Sopenharmony_ci} 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_ci/** 29838c2ecf20Sopenharmony_ci * tx_intr_handler - Transmit interrupt handler 29848c2ecf20Sopenharmony_ci * @fifo_data : fifo data pointer 29858c2ecf20Sopenharmony_ci * Description: 29868c2ecf20Sopenharmony_ci * If an interrupt was raised to indicate DMA complete of the 29878c2ecf20Sopenharmony_ci * Tx packet, this function is called. It identifies the last TxD 29888c2ecf20Sopenharmony_ci * whose buffer was freed and frees all skbs whose data have already 29898c2ecf20Sopenharmony_ci * DMA'ed into the NICs internal memory. 29908c2ecf20Sopenharmony_ci * Return Value: 29918c2ecf20Sopenharmony_ci * NONE 29928c2ecf20Sopenharmony_ci */ 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_cistatic void tx_intr_handler(struct fifo_info *fifo_data) 29958c2ecf20Sopenharmony_ci{ 29968c2ecf20Sopenharmony_ci struct s2io_nic *nic = fifo_data->nic; 29978c2ecf20Sopenharmony_ci struct tx_curr_get_info get_info, put_info; 29988c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 29998c2ecf20Sopenharmony_ci struct TxD *txdlp; 30008c2ecf20Sopenharmony_ci int pkt_cnt = 0; 30018c2ecf20Sopenharmony_ci unsigned long flags = 0; 30028c2ecf20Sopenharmony_ci u8 err_mask; 30038c2ecf20Sopenharmony_ci struct stat_block *stats = nic->mac_control.stats_info; 30048c2ecf20Sopenharmony_ci struct swStat *swstats = &stats->sw_stat; 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci if (!spin_trylock_irqsave(&fifo_data->tx_lock, flags)) 30078c2ecf20Sopenharmony_ci return; 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci get_info = fifo_data->tx_curr_get_info; 30108c2ecf20Sopenharmony_ci memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info)); 30118c2ecf20Sopenharmony_ci txdlp = fifo_data->list_info[get_info.offset].list_virt_addr; 30128c2ecf20Sopenharmony_ci while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) && 30138c2ecf20Sopenharmony_ci (get_info.offset != put_info.offset) && 30148c2ecf20Sopenharmony_ci (txdlp->Host_Control)) { 30158c2ecf20Sopenharmony_ci /* Check for TxD errors */ 30168c2ecf20Sopenharmony_ci if (txdlp->Control_1 & TXD_T_CODE) { 30178c2ecf20Sopenharmony_ci unsigned long long err; 30188c2ecf20Sopenharmony_ci err = txdlp->Control_1 & TXD_T_CODE; 30198c2ecf20Sopenharmony_ci if (err & 0x1) { 30208c2ecf20Sopenharmony_ci swstats->parity_err_cnt++; 30218c2ecf20Sopenharmony_ci } 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci /* update t_code statistics */ 30248c2ecf20Sopenharmony_ci err_mask = err >> 48; 30258c2ecf20Sopenharmony_ci switch (err_mask) { 30268c2ecf20Sopenharmony_ci case 2: 30278c2ecf20Sopenharmony_ci swstats->tx_buf_abort_cnt++; 30288c2ecf20Sopenharmony_ci break; 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci case 3: 30318c2ecf20Sopenharmony_ci swstats->tx_desc_abort_cnt++; 30328c2ecf20Sopenharmony_ci break; 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ci case 7: 30358c2ecf20Sopenharmony_ci swstats->tx_parity_err_cnt++; 30368c2ecf20Sopenharmony_ci break; 30378c2ecf20Sopenharmony_ci 30388c2ecf20Sopenharmony_ci case 10: 30398c2ecf20Sopenharmony_ci swstats->tx_link_loss_cnt++; 30408c2ecf20Sopenharmony_ci break; 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci case 15: 30438c2ecf20Sopenharmony_ci swstats->tx_list_proc_err_cnt++; 30448c2ecf20Sopenharmony_ci break; 30458c2ecf20Sopenharmony_ci } 30468c2ecf20Sopenharmony_ci } 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci skb = s2io_txdl_getskb(fifo_data, txdlp, get_info.offset); 30498c2ecf20Sopenharmony_ci if (skb == NULL) { 30508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fifo_data->tx_lock, flags); 30518c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: NULL skb in Tx Free Intr\n", 30528c2ecf20Sopenharmony_ci __func__); 30538c2ecf20Sopenharmony_ci return; 30548c2ecf20Sopenharmony_ci } 30558c2ecf20Sopenharmony_ci pkt_cnt++; 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_ci /* Updating the statistics block */ 30588c2ecf20Sopenharmony_ci swstats->mem_freed += skb->truesize; 30598c2ecf20Sopenharmony_ci dev_consume_skb_irq(skb); 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci get_info.offset++; 30628c2ecf20Sopenharmony_ci if (get_info.offset == get_info.fifo_len + 1) 30638c2ecf20Sopenharmony_ci get_info.offset = 0; 30648c2ecf20Sopenharmony_ci txdlp = fifo_data->list_info[get_info.offset].list_virt_addr; 30658c2ecf20Sopenharmony_ci fifo_data->tx_curr_get_info.offset = get_info.offset; 30668c2ecf20Sopenharmony_ci } 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_ci s2io_wake_tx_queue(fifo_data, pkt_cnt, nic->config.multiq); 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fifo_data->tx_lock, flags); 30718c2ecf20Sopenharmony_ci} 30728c2ecf20Sopenharmony_ci 30738c2ecf20Sopenharmony_ci/** 30748c2ecf20Sopenharmony_ci * s2io_mdio_write - Function to write in to MDIO registers 30758c2ecf20Sopenharmony_ci * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS) 30768c2ecf20Sopenharmony_ci * @addr : address value 30778c2ecf20Sopenharmony_ci * @value : data value 30788c2ecf20Sopenharmony_ci * @dev : pointer to net_device structure 30798c2ecf20Sopenharmony_ci * Description: 30808c2ecf20Sopenharmony_ci * This function is used to write values to the MDIO registers 30818c2ecf20Sopenharmony_ci * NONE 30828c2ecf20Sopenharmony_ci */ 30838c2ecf20Sopenharmony_cistatic void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, 30848c2ecf20Sopenharmony_ci struct net_device *dev) 30858c2ecf20Sopenharmony_ci{ 30868c2ecf20Sopenharmony_ci u64 val64; 30878c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 30888c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci /* address transaction */ 30918c2ecf20Sopenharmony_ci val64 = MDIO_MMD_INDX_ADDR(addr) | 30928c2ecf20Sopenharmony_ci MDIO_MMD_DEV_ADDR(mmd_type) | 30938c2ecf20Sopenharmony_ci MDIO_MMS_PRT_ADDR(0x0); 30948c2ecf20Sopenharmony_ci writeq(val64, &bar0->mdio_control); 30958c2ecf20Sopenharmony_ci val64 = val64 | MDIO_CTRL_START_TRANS(0xE); 30968c2ecf20Sopenharmony_ci writeq(val64, &bar0->mdio_control); 30978c2ecf20Sopenharmony_ci udelay(100); 30988c2ecf20Sopenharmony_ci 30998c2ecf20Sopenharmony_ci /* Data transaction */ 31008c2ecf20Sopenharmony_ci val64 = MDIO_MMD_INDX_ADDR(addr) | 31018c2ecf20Sopenharmony_ci MDIO_MMD_DEV_ADDR(mmd_type) | 31028c2ecf20Sopenharmony_ci MDIO_MMS_PRT_ADDR(0x0) | 31038c2ecf20Sopenharmony_ci MDIO_MDIO_DATA(value) | 31048c2ecf20Sopenharmony_ci MDIO_OP(MDIO_OP_WRITE_TRANS); 31058c2ecf20Sopenharmony_ci writeq(val64, &bar0->mdio_control); 31068c2ecf20Sopenharmony_ci val64 = val64 | MDIO_CTRL_START_TRANS(0xE); 31078c2ecf20Sopenharmony_ci writeq(val64, &bar0->mdio_control); 31088c2ecf20Sopenharmony_ci udelay(100); 31098c2ecf20Sopenharmony_ci 31108c2ecf20Sopenharmony_ci val64 = MDIO_MMD_INDX_ADDR(addr) | 31118c2ecf20Sopenharmony_ci MDIO_MMD_DEV_ADDR(mmd_type) | 31128c2ecf20Sopenharmony_ci MDIO_MMS_PRT_ADDR(0x0) | 31138c2ecf20Sopenharmony_ci MDIO_OP(MDIO_OP_READ_TRANS); 31148c2ecf20Sopenharmony_ci writeq(val64, &bar0->mdio_control); 31158c2ecf20Sopenharmony_ci val64 = val64 | MDIO_CTRL_START_TRANS(0xE); 31168c2ecf20Sopenharmony_ci writeq(val64, &bar0->mdio_control); 31178c2ecf20Sopenharmony_ci udelay(100); 31188c2ecf20Sopenharmony_ci} 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci/** 31218c2ecf20Sopenharmony_ci * s2io_mdio_read - Function to write in to MDIO registers 31228c2ecf20Sopenharmony_ci * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS) 31238c2ecf20Sopenharmony_ci * @addr : address value 31248c2ecf20Sopenharmony_ci * @dev : pointer to net_device structure 31258c2ecf20Sopenharmony_ci * Description: 31268c2ecf20Sopenharmony_ci * This function is used to read values to the MDIO registers 31278c2ecf20Sopenharmony_ci * NONE 31288c2ecf20Sopenharmony_ci */ 31298c2ecf20Sopenharmony_cistatic u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev) 31308c2ecf20Sopenharmony_ci{ 31318c2ecf20Sopenharmony_ci u64 val64 = 0x0; 31328c2ecf20Sopenharmony_ci u64 rval64 = 0x0; 31338c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 31348c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci /* address transaction */ 31378c2ecf20Sopenharmony_ci val64 = val64 | (MDIO_MMD_INDX_ADDR(addr) 31388c2ecf20Sopenharmony_ci | MDIO_MMD_DEV_ADDR(mmd_type) 31398c2ecf20Sopenharmony_ci | MDIO_MMS_PRT_ADDR(0x0)); 31408c2ecf20Sopenharmony_ci writeq(val64, &bar0->mdio_control); 31418c2ecf20Sopenharmony_ci val64 = val64 | MDIO_CTRL_START_TRANS(0xE); 31428c2ecf20Sopenharmony_ci writeq(val64, &bar0->mdio_control); 31438c2ecf20Sopenharmony_ci udelay(100); 31448c2ecf20Sopenharmony_ci 31458c2ecf20Sopenharmony_ci /* Data transaction */ 31468c2ecf20Sopenharmony_ci val64 = MDIO_MMD_INDX_ADDR(addr) | 31478c2ecf20Sopenharmony_ci MDIO_MMD_DEV_ADDR(mmd_type) | 31488c2ecf20Sopenharmony_ci MDIO_MMS_PRT_ADDR(0x0) | 31498c2ecf20Sopenharmony_ci MDIO_OP(MDIO_OP_READ_TRANS); 31508c2ecf20Sopenharmony_ci writeq(val64, &bar0->mdio_control); 31518c2ecf20Sopenharmony_ci val64 = val64 | MDIO_CTRL_START_TRANS(0xE); 31528c2ecf20Sopenharmony_ci writeq(val64, &bar0->mdio_control); 31538c2ecf20Sopenharmony_ci udelay(100); 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci /* Read the value from regs */ 31568c2ecf20Sopenharmony_ci rval64 = readq(&bar0->mdio_control); 31578c2ecf20Sopenharmony_ci rval64 = rval64 & 0xFFFF0000; 31588c2ecf20Sopenharmony_ci rval64 = rval64 >> 16; 31598c2ecf20Sopenharmony_ci return rval64; 31608c2ecf20Sopenharmony_ci} 31618c2ecf20Sopenharmony_ci 31628c2ecf20Sopenharmony_ci/** 31638c2ecf20Sopenharmony_ci * s2io_chk_xpak_counter - Function to check the status of the xpak counters 31648c2ecf20Sopenharmony_ci * @counter : counter value to be updated 31658c2ecf20Sopenharmony_ci * @regs_stat : registers status 31668c2ecf20Sopenharmony_ci * @index : index 31678c2ecf20Sopenharmony_ci * @flag : flag to indicate the status 31688c2ecf20Sopenharmony_ci * @type : counter type 31698c2ecf20Sopenharmony_ci * Description: 31708c2ecf20Sopenharmony_ci * This function is to check the status of the xpak counters value 31718c2ecf20Sopenharmony_ci * NONE 31728c2ecf20Sopenharmony_ci */ 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_cistatic void s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index, 31758c2ecf20Sopenharmony_ci u16 flag, u16 type) 31768c2ecf20Sopenharmony_ci{ 31778c2ecf20Sopenharmony_ci u64 mask = 0x3; 31788c2ecf20Sopenharmony_ci u64 val64; 31798c2ecf20Sopenharmony_ci int i; 31808c2ecf20Sopenharmony_ci for (i = 0; i < index; i++) 31818c2ecf20Sopenharmony_ci mask = mask << 0x2; 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci if (flag > 0) { 31848c2ecf20Sopenharmony_ci *counter = *counter + 1; 31858c2ecf20Sopenharmony_ci val64 = *regs_stat & mask; 31868c2ecf20Sopenharmony_ci val64 = val64 >> (index * 0x2); 31878c2ecf20Sopenharmony_ci val64 = val64 + 1; 31888c2ecf20Sopenharmony_ci if (val64 == 3) { 31898c2ecf20Sopenharmony_ci switch (type) { 31908c2ecf20Sopenharmony_ci case 1: 31918c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 31928c2ecf20Sopenharmony_ci "Take Xframe NIC out of service.\n"); 31938c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 31948c2ecf20Sopenharmony_ci"Excessive temperatures may result in premature transceiver failure.\n"); 31958c2ecf20Sopenharmony_ci break; 31968c2ecf20Sopenharmony_ci case 2: 31978c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 31988c2ecf20Sopenharmony_ci "Take Xframe NIC out of service.\n"); 31998c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 32008c2ecf20Sopenharmony_ci"Excessive bias currents may indicate imminent laser diode failure.\n"); 32018c2ecf20Sopenharmony_ci break; 32028c2ecf20Sopenharmony_ci case 3: 32038c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 32048c2ecf20Sopenharmony_ci "Take Xframe NIC out of service.\n"); 32058c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 32068c2ecf20Sopenharmony_ci"Excessive laser output power may saturate far-end receiver.\n"); 32078c2ecf20Sopenharmony_ci break; 32088c2ecf20Sopenharmony_ci default: 32098c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 32108c2ecf20Sopenharmony_ci "Incorrect XPAK Alarm type\n"); 32118c2ecf20Sopenharmony_ci } 32128c2ecf20Sopenharmony_ci val64 = 0x0; 32138c2ecf20Sopenharmony_ci } 32148c2ecf20Sopenharmony_ci val64 = val64 << (index * 0x2); 32158c2ecf20Sopenharmony_ci *regs_stat = (*regs_stat & (~mask)) | (val64); 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci } else { 32188c2ecf20Sopenharmony_ci *regs_stat = *regs_stat & (~mask); 32198c2ecf20Sopenharmony_ci } 32208c2ecf20Sopenharmony_ci} 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci/** 32238c2ecf20Sopenharmony_ci * s2io_updt_xpak_counter - Function to update the xpak counters 32248c2ecf20Sopenharmony_ci * @dev : pointer to net_device struct 32258c2ecf20Sopenharmony_ci * Description: 32268c2ecf20Sopenharmony_ci * This function is to upate the status of the xpak counters value 32278c2ecf20Sopenharmony_ci * NONE 32288c2ecf20Sopenharmony_ci */ 32298c2ecf20Sopenharmony_cistatic void s2io_updt_xpak_counter(struct net_device *dev) 32308c2ecf20Sopenharmony_ci{ 32318c2ecf20Sopenharmony_ci u16 flag = 0x0; 32328c2ecf20Sopenharmony_ci u16 type = 0x0; 32338c2ecf20Sopenharmony_ci u16 val16 = 0x0; 32348c2ecf20Sopenharmony_ci u64 val64 = 0x0; 32358c2ecf20Sopenharmony_ci u64 addr = 0x0; 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 32388c2ecf20Sopenharmony_ci struct stat_block *stats = sp->mac_control.stats_info; 32398c2ecf20Sopenharmony_ci struct xpakStat *xstats = &stats->xpak_stat; 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci /* Check the communication with the MDIO slave */ 32428c2ecf20Sopenharmony_ci addr = MDIO_CTRL1; 32438c2ecf20Sopenharmony_ci val64 = 0x0; 32448c2ecf20Sopenharmony_ci val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); 32458c2ecf20Sopenharmony_ci if ((val64 == 0xFFFF) || (val64 == 0x0000)) { 32468c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 32478c2ecf20Sopenharmony_ci "ERR: MDIO slave access failed - Returned %llx\n", 32488c2ecf20Sopenharmony_ci (unsigned long long)val64); 32498c2ecf20Sopenharmony_ci return; 32508c2ecf20Sopenharmony_ci } 32518c2ecf20Sopenharmony_ci 32528c2ecf20Sopenharmony_ci /* Check for the expected value of control reg 1 */ 32538c2ecf20Sopenharmony_ci if (val64 != MDIO_CTRL1_SPEED10G) { 32548c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - " 32558c2ecf20Sopenharmony_ci "Returned: %llx- Expected: 0x%x\n", 32568c2ecf20Sopenharmony_ci (unsigned long long)val64, MDIO_CTRL1_SPEED10G); 32578c2ecf20Sopenharmony_ci return; 32588c2ecf20Sopenharmony_ci } 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_ci /* Loading the DOM register to MDIO register */ 32618c2ecf20Sopenharmony_ci addr = 0xA100; 32628c2ecf20Sopenharmony_ci s2io_mdio_write(MDIO_MMD_PMAPMD, addr, val16, dev); 32638c2ecf20Sopenharmony_ci val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci /* Reading the Alarm flags */ 32668c2ecf20Sopenharmony_ci addr = 0xA070; 32678c2ecf20Sopenharmony_ci val64 = 0x0; 32688c2ecf20Sopenharmony_ci val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); 32698c2ecf20Sopenharmony_ci 32708c2ecf20Sopenharmony_ci flag = CHECKBIT(val64, 0x7); 32718c2ecf20Sopenharmony_ci type = 1; 32728c2ecf20Sopenharmony_ci s2io_chk_xpak_counter(&xstats->alarm_transceiver_temp_high, 32738c2ecf20Sopenharmony_ci &xstats->xpak_regs_stat, 32748c2ecf20Sopenharmony_ci 0x0, flag, type); 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci if (CHECKBIT(val64, 0x6)) 32778c2ecf20Sopenharmony_ci xstats->alarm_transceiver_temp_low++; 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci flag = CHECKBIT(val64, 0x3); 32808c2ecf20Sopenharmony_ci type = 2; 32818c2ecf20Sopenharmony_ci s2io_chk_xpak_counter(&xstats->alarm_laser_bias_current_high, 32828c2ecf20Sopenharmony_ci &xstats->xpak_regs_stat, 32838c2ecf20Sopenharmony_ci 0x2, flag, type); 32848c2ecf20Sopenharmony_ci 32858c2ecf20Sopenharmony_ci if (CHECKBIT(val64, 0x2)) 32868c2ecf20Sopenharmony_ci xstats->alarm_laser_bias_current_low++; 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci flag = CHECKBIT(val64, 0x1); 32898c2ecf20Sopenharmony_ci type = 3; 32908c2ecf20Sopenharmony_ci s2io_chk_xpak_counter(&xstats->alarm_laser_output_power_high, 32918c2ecf20Sopenharmony_ci &xstats->xpak_regs_stat, 32928c2ecf20Sopenharmony_ci 0x4, flag, type); 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_ci if (CHECKBIT(val64, 0x0)) 32958c2ecf20Sopenharmony_ci xstats->alarm_laser_output_power_low++; 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci /* Reading the Warning flags */ 32988c2ecf20Sopenharmony_ci addr = 0xA074; 32998c2ecf20Sopenharmony_ci val64 = 0x0; 33008c2ecf20Sopenharmony_ci val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci if (CHECKBIT(val64, 0x7)) 33038c2ecf20Sopenharmony_ci xstats->warn_transceiver_temp_high++; 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci if (CHECKBIT(val64, 0x6)) 33068c2ecf20Sopenharmony_ci xstats->warn_transceiver_temp_low++; 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci if (CHECKBIT(val64, 0x3)) 33098c2ecf20Sopenharmony_ci xstats->warn_laser_bias_current_high++; 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci if (CHECKBIT(val64, 0x2)) 33128c2ecf20Sopenharmony_ci xstats->warn_laser_bias_current_low++; 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci if (CHECKBIT(val64, 0x1)) 33158c2ecf20Sopenharmony_ci xstats->warn_laser_output_power_high++; 33168c2ecf20Sopenharmony_ci 33178c2ecf20Sopenharmony_ci if (CHECKBIT(val64, 0x0)) 33188c2ecf20Sopenharmony_ci xstats->warn_laser_output_power_low++; 33198c2ecf20Sopenharmony_ci} 33208c2ecf20Sopenharmony_ci 33218c2ecf20Sopenharmony_ci/** 33228c2ecf20Sopenharmony_ci * wait_for_cmd_complete - waits for a command to complete. 33238c2ecf20Sopenharmony_ci * @addr: address 33248c2ecf20Sopenharmony_ci * @busy_bit: bit to check for busy 33258c2ecf20Sopenharmony_ci * @bit_state: state to check 33268c2ecf20Sopenharmony_ci * Description: Function that waits for a command to Write into RMAC 33278c2ecf20Sopenharmony_ci * ADDR DATA registers to be completed and returns either success or 33288c2ecf20Sopenharmony_ci * error depending on whether the command was complete or not. 33298c2ecf20Sopenharmony_ci * Return value: 33308c2ecf20Sopenharmony_ci * SUCCESS on success and FAILURE on failure. 33318c2ecf20Sopenharmony_ci */ 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_cistatic int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit, 33348c2ecf20Sopenharmony_ci int bit_state) 33358c2ecf20Sopenharmony_ci{ 33368c2ecf20Sopenharmony_ci int ret = FAILURE, cnt = 0, delay = 1; 33378c2ecf20Sopenharmony_ci u64 val64; 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_ci if ((bit_state != S2IO_BIT_RESET) && (bit_state != S2IO_BIT_SET)) 33408c2ecf20Sopenharmony_ci return FAILURE; 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci do { 33438c2ecf20Sopenharmony_ci val64 = readq(addr); 33448c2ecf20Sopenharmony_ci if (bit_state == S2IO_BIT_RESET) { 33458c2ecf20Sopenharmony_ci if (!(val64 & busy_bit)) { 33468c2ecf20Sopenharmony_ci ret = SUCCESS; 33478c2ecf20Sopenharmony_ci break; 33488c2ecf20Sopenharmony_ci } 33498c2ecf20Sopenharmony_ci } else { 33508c2ecf20Sopenharmony_ci if (val64 & busy_bit) { 33518c2ecf20Sopenharmony_ci ret = SUCCESS; 33528c2ecf20Sopenharmony_ci break; 33538c2ecf20Sopenharmony_ci } 33548c2ecf20Sopenharmony_ci } 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_ci if (in_interrupt()) 33578c2ecf20Sopenharmony_ci mdelay(delay); 33588c2ecf20Sopenharmony_ci else 33598c2ecf20Sopenharmony_ci msleep(delay); 33608c2ecf20Sopenharmony_ci 33618c2ecf20Sopenharmony_ci if (++cnt >= 10) 33628c2ecf20Sopenharmony_ci delay = 50; 33638c2ecf20Sopenharmony_ci } while (cnt < 20); 33648c2ecf20Sopenharmony_ci return ret; 33658c2ecf20Sopenharmony_ci} 33668c2ecf20Sopenharmony_ci/** 33678c2ecf20Sopenharmony_ci * check_pci_device_id - Checks if the device id is supported 33688c2ecf20Sopenharmony_ci * @id : device id 33698c2ecf20Sopenharmony_ci * Description: Function to check if the pci device id is supported by driver. 33708c2ecf20Sopenharmony_ci * Return value: Actual device id if supported else PCI_ANY_ID 33718c2ecf20Sopenharmony_ci */ 33728c2ecf20Sopenharmony_cistatic u16 check_pci_device_id(u16 id) 33738c2ecf20Sopenharmony_ci{ 33748c2ecf20Sopenharmony_ci switch (id) { 33758c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_HERC_WIN: 33768c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_HERC_UNI: 33778c2ecf20Sopenharmony_ci return XFRAME_II_DEVICE; 33788c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_S2IO_UNI: 33798c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_S2IO_WIN: 33808c2ecf20Sopenharmony_ci return XFRAME_I_DEVICE; 33818c2ecf20Sopenharmony_ci default: 33828c2ecf20Sopenharmony_ci return PCI_ANY_ID; 33838c2ecf20Sopenharmony_ci } 33848c2ecf20Sopenharmony_ci} 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_ci/** 33878c2ecf20Sopenharmony_ci * s2io_reset - Resets the card. 33888c2ecf20Sopenharmony_ci * @sp : private member of the device structure. 33898c2ecf20Sopenharmony_ci * Description: Function to Reset the card. This function then also 33908c2ecf20Sopenharmony_ci * restores the previously saved PCI configuration space registers as 33918c2ecf20Sopenharmony_ci * the card reset also resets the configuration space. 33928c2ecf20Sopenharmony_ci * Return value: 33938c2ecf20Sopenharmony_ci * void. 33948c2ecf20Sopenharmony_ci */ 33958c2ecf20Sopenharmony_ci 33968c2ecf20Sopenharmony_cistatic void s2io_reset(struct s2io_nic *sp) 33978c2ecf20Sopenharmony_ci{ 33988c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 33998c2ecf20Sopenharmony_ci u64 val64; 34008c2ecf20Sopenharmony_ci u16 subid, pci_cmd; 34018c2ecf20Sopenharmony_ci int i; 34028c2ecf20Sopenharmony_ci u16 val16; 34038c2ecf20Sopenharmony_ci unsigned long long up_cnt, down_cnt, up_time, down_time, reset_cnt; 34048c2ecf20Sopenharmony_ci unsigned long long mem_alloc_cnt, mem_free_cnt, watchdog_cnt; 34058c2ecf20Sopenharmony_ci struct stat_block *stats; 34068c2ecf20Sopenharmony_ci struct swStat *swstats; 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_ci DBG_PRINT(INIT_DBG, "%s: Resetting XFrame card %s\n", 34098c2ecf20Sopenharmony_ci __func__, pci_name(sp->pdev)); 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_ci /* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */ 34128c2ecf20Sopenharmony_ci pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd)); 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci val64 = SW_RESET_ALL; 34158c2ecf20Sopenharmony_ci writeq(val64, &bar0->sw_reset); 34168c2ecf20Sopenharmony_ci if (strstr(sp->product_name, "CX4")) 34178c2ecf20Sopenharmony_ci msleep(750); 34188c2ecf20Sopenharmony_ci msleep(250); 34198c2ecf20Sopenharmony_ci for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) { 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci /* Restore the PCI state saved during initialization. */ 34228c2ecf20Sopenharmony_ci pci_restore_state(sp->pdev); 34238c2ecf20Sopenharmony_ci pci_save_state(sp->pdev); 34248c2ecf20Sopenharmony_ci pci_read_config_word(sp->pdev, 0x2, &val16); 34258c2ecf20Sopenharmony_ci if (check_pci_device_id(val16) != (u16)PCI_ANY_ID) 34268c2ecf20Sopenharmony_ci break; 34278c2ecf20Sopenharmony_ci msleep(200); 34288c2ecf20Sopenharmony_ci } 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) 34318c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s SW_Reset failed!\n", __func__); 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd); 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci s2io_init_pci(sp); 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci /* Set swapper to enable I/O register access */ 34388c2ecf20Sopenharmony_ci s2io_set_swapper(sp); 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci /* restore mac_addr entries */ 34418c2ecf20Sopenharmony_ci do_s2io_restore_unicast_mc(sp); 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_ci /* Restore the MSIX table entries from local variables */ 34448c2ecf20Sopenharmony_ci restore_xmsi_data(sp); 34458c2ecf20Sopenharmony_ci 34468c2ecf20Sopenharmony_ci /* Clear certain PCI/PCI-X fields after reset */ 34478c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_II_DEVICE) { 34488c2ecf20Sopenharmony_ci /* Clear "detected parity error" bit */ 34498c2ecf20Sopenharmony_ci pci_write_config_word(sp->pdev, PCI_STATUS, 0x8000); 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci /* Clearing PCIX Ecc status register */ 34528c2ecf20Sopenharmony_ci pci_write_config_dword(sp->pdev, 0x68, 0x7C); 34538c2ecf20Sopenharmony_ci 34548c2ecf20Sopenharmony_ci /* Clearing PCI_STATUS error reflected here */ 34558c2ecf20Sopenharmony_ci writeq(s2BIT(62), &bar0->txpic_int_reg); 34568c2ecf20Sopenharmony_ci } 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci /* Reset device statistics maintained by OS */ 34598c2ecf20Sopenharmony_ci memset(&sp->stats, 0, sizeof(struct net_device_stats)); 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_ci stats = sp->mac_control.stats_info; 34628c2ecf20Sopenharmony_ci swstats = &stats->sw_stat; 34638c2ecf20Sopenharmony_ci 34648c2ecf20Sopenharmony_ci /* save link up/down time/cnt, reset/memory/watchdog cnt */ 34658c2ecf20Sopenharmony_ci up_cnt = swstats->link_up_cnt; 34668c2ecf20Sopenharmony_ci down_cnt = swstats->link_down_cnt; 34678c2ecf20Sopenharmony_ci up_time = swstats->link_up_time; 34688c2ecf20Sopenharmony_ci down_time = swstats->link_down_time; 34698c2ecf20Sopenharmony_ci reset_cnt = swstats->soft_reset_cnt; 34708c2ecf20Sopenharmony_ci mem_alloc_cnt = swstats->mem_allocated; 34718c2ecf20Sopenharmony_ci mem_free_cnt = swstats->mem_freed; 34728c2ecf20Sopenharmony_ci watchdog_cnt = swstats->watchdog_timer_cnt; 34738c2ecf20Sopenharmony_ci 34748c2ecf20Sopenharmony_ci memset(stats, 0, sizeof(struct stat_block)); 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci /* restore link up/down time/cnt, reset/memory/watchdog cnt */ 34778c2ecf20Sopenharmony_ci swstats->link_up_cnt = up_cnt; 34788c2ecf20Sopenharmony_ci swstats->link_down_cnt = down_cnt; 34798c2ecf20Sopenharmony_ci swstats->link_up_time = up_time; 34808c2ecf20Sopenharmony_ci swstats->link_down_time = down_time; 34818c2ecf20Sopenharmony_ci swstats->soft_reset_cnt = reset_cnt; 34828c2ecf20Sopenharmony_ci swstats->mem_allocated = mem_alloc_cnt; 34838c2ecf20Sopenharmony_ci swstats->mem_freed = mem_free_cnt; 34848c2ecf20Sopenharmony_ci swstats->watchdog_timer_cnt = watchdog_cnt; 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_ci /* SXE-002: Configure link and activity LED to turn it off */ 34878c2ecf20Sopenharmony_ci subid = sp->pdev->subsystem_device; 34888c2ecf20Sopenharmony_ci if (((subid & 0xFF) >= 0x07) && 34898c2ecf20Sopenharmony_ci (sp->device_type == XFRAME_I_DEVICE)) { 34908c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_control); 34918c2ecf20Sopenharmony_ci val64 |= 0x0000800000000000ULL; 34928c2ecf20Sopenharmony_ci writeq(val64, &bar0->gpio_control); 34938c2ecf20Sopenharmony_ci val64 = 0x0411040400000000ULL; 34948c2ecf20Sopenharmony_ci writeq(val64, (void __iomem *)bar0 + 0x2700); 34958c2ecf20Sopenharmony_ci } 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci /* 34988c2ecf20Sopenharmony_ci * Clear spurious ECC interrupts that would have occurred on 34998c2ecf20Sopenharmony_ci * XFRAME II cards after reset. 35008c2ecf20Sopenharmony_ci */ 35018c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_II_DEVICE) { 35028c2ecf20Sopenharmony_ci val64 = readq(&bar0->pcc_err_reg); 35038c2ecf20Sopenharmony_ci writeq(val64, &bar0->pcc_err_reg); 35048c2ecf20Sopenharmony_ci } 35058c2ecf20Sopenharmony_ci 35068c2ecf20Sopenharmony_ci sp->device_enabled_once = false; 35078c2ecf20Sopenharmony_ci} 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci/** 35108c2ecf20Sopenharmony_ci * s2io_set_swapper - to set the swapper controle on the card 35118c2ecf20Sopenharmony_ci * @sp : private member of the device structure, 35128c2ecf20Sopenharmony_ci * pointer to the s2io_nic structure. 35138c2ecf20Sopenharmony_ci * Description: Function to set the swapper control on the card 35148c2ecf20Sopenharmony_ci * correctly depending on the 'endianness' of the system. 35158c2ecf20Sopenharmony_ci * Return value: 35168c2ecf20Sopenharmony_ci * SUCCESS on success and FAILURE on failure. 35178c2ecf20Sopenharmony_ci */ 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_cistatic int s2io_set_swapper(struct s2io_nic *sp) 35208c2ecf20Sopenharmony_ci{ 35218c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 35228c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 35238c2ecf20Sopenharmony_ci u64 val64, valt, valr; 35248c2ecf20Sopenharmony_ci 35258c2ecf20Sopenharmony_ci /* 35268c2ecf20Sopenharmony_ci * Set proper endian settings and verify the same by reading 35278c2ecf20Sopenharmony_ci * the PIF Feed-back register. 35288c2ecf20Sopenharmony_ci */ 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_ci val64 = readq(&bar0->pif_rd_swapper_fb); 35318c2ecf20Sopenharmony_ci if (val64 != 0x0123456789ABCDEFULL) { 35328c2ecf20Sopenharmony_ci int i = 0; 35338c2ecf20Sopenharmony_ci static const u64 value[] = { 35348c2ecf20Sopenharmony_ci 0xC30000C3C30000C3ULL, /* FE=1, SE=1 */ 35358c2ecf20Sopenharmony_ci 0x8100008181000081ULL, /* FE=1, SE=0 */ 35368c2ecf20Sopenharmony_ci 0x4200004242000042ULL, /* FE=0, SE=1 */ 35378c2ecf20Sopenharmony_ci 0 /* FE=0, SE=0 */ 35388c2ecf20Sopenharmony_ci }; 35398c2ecf20Sopenharmony_ci 35408c2ecf20Sopenharmony_ci while (i < 4) { 35418c2ecf20Sopenharmony_ci writeq(value[i], &bar0->swapper_ctrl); 35428c2ecf20Sopenharmony_ci val64 = readq(&bar0->pif_rd_swapper_fb); 35438c2ecf20Sopenharmony_ci if (val64 == 0x0123456789ABCDEFULL) 35448c2ecf20Sopenharmony_ci break; 35458c2ecf20Sopenharmony_ci i++; 35468c2ecf20Sopenharmony_ci } 35478c2ecf20Sopenharmony_ci if (i == 4) { 35488c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, " 35498c2ecf20Sopenharmony_ci "feedback read %llx\n", 35508c2ecf20Sopenharmony_ci dev->name, (unsigned long long)val64); 35518c2ecf20Sopenharmony_ci return FAILURE; 35528c2ecf20Sopenharmony_ci } 35538c2ecf20Sopenharmony_ci valr = value[i]; 35548c2ecf20Sopenharmony_ci } else { 35558c2ecf20Sopenharmony_ci valr = readq(&bar0->swapper_ctrl); 35568c2ecf20Sopenharmony_ci } 35578c2ecf20Sopenharmony_ci 35588c2ecf20Sopenharmony_ci valt = 0x0123456789ABCDEFULL; 35598c2ecf20Sopenharmony_ci writeq(valt, &bar0->xmsi_address); 35608c2ecf20Sopenharmony_ci val64 = readq(&bar0->xmsi_address); 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ci if (val64 != valt) { 35638c2ecf20Sopenharmony_ci int i = 0; 35648c2ecf20Sopenharmony_ci static const u64 value[] = { 35658c2ecf20Sopenharmony_ci 0x00C3C30000C3C300ULL, /* FE=1, SE=1 */ 35668c2ecf20Sopenharmony_ci 0x0081810000818100ULL, /* FE=1, SE=0 */ 35678c2ecf20Sopenharmony_ci 0x0042420000424200ULL, /* FE=0, SE=1 */ 35688c2ecf20Sopenharmony_ci 0 /* FE=0, SE=0 */ 35698c2ecf20Sopenharmony_ci }; 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci while (i < 4) { 35728c2ecf20Sopenharmony_ci writeq((value[i] | valr), &bar0->swapper_ctrl); 35738c2ecf20Sopenharmony_ci writeq(valt, &bar0->xmsi_address); 35748c2ecf20Sopenharmony_ci val64 = readq(&bar0->xmsi_address); 35758c2ecf20Sopenharmony_ci if (val64 == valt) 35768c2ecf20Sopenharmony_ci break; 35778c2ecf20Sopenharmony_ci i++; 35788c2ecf20Sopenharmony_ci } 35798c2ecf20Sopenharmony_ci if (i == 4) { 35808c2ecf20Sopenharmony_ci unsigned long long x = val64; 35818c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 35828c2ecf20Sopenharmony_ci "Write failed, Xmsi_addr reads:0x%llx\n", x); 35838c2ecf20Sopenharmony_ci return FAILURE; 35848c2ecf20Sopenharmony_ci } 35858c2ecf20Sopenharmony_ci } 35868c2ecf20Sopenharmony_ci val64 = readq(&bar0->swapper_ctrl); 35878c2ecf20Sopenharmony_ci val64 &= 0xFFFF000000000000ULL; 35888c2ecf20Sopenharmony_ci 35898c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 35908c2ecf20Sopenharmony_ci /* 35918c2ecf20Sopenharmony_ci * The device by default set to a big endian format, so a 35928c2ecf20Sopenharmony_ci * big endian driver need not set anything. 35938c2ecf20Sopenharmony_ci */ 35948c2ecf20Sopenharmony_ci val64 |= (SWAPPER_CTRL_TXP_FE | 35958c2ecf20Sopenharmony_ci SWAPPER_CTRL_TXP_SE | 35968c2ecf20Sopenharmony_ci SWAPPER_CTRL_TXD_R_FE | 35978c2ecf20Sopenharmony_ci SWAPPER_CTRL_TXD_W_FE | 35988c2ecf20Sopenharmony_ci SWAPPER_CTRL_TXF_R_FE | 35998c2ecf20Sopenharmony_ci SWAPPER_CTRL_RXD_R_FE | 36008c2ecf20Sopenharmony_ci SWAPPER_CTRL_RXD_W_FE | 36018c2ecf20Sopenharmony_ci SWAPPER_CTRL_RXF_W_FE | 36028c2ecf20Sopenharmony_ci SWAPPER_CTRL_XMSI_FE | 36038c2ecf20Sopenharmony_ci SWAPPER_CTRL_STATS_FE | 36048c2ecf20Sopenharmony_ci SWAPPER_CTRL_STATS_SE); 36058c2ecf20Sopenharmony_ci if (sp->config.intr_type == INTA) 36068c2ecf20Sopenharmony_ci val64 |= SWAPPER_CTRL_XMSI_SE; 36078c2ecf20Sopenharmony_ci writeq(val64, &bar0->swapper_ctrl); 36088c2ecf20Sopenharmony_ci#else 36098c2ecf20Sopenharmony_ci /* 36108c2ecf20Sopenharmony_ci * Initially we enable all bits to make it accessible by the 36118c2ecf20Sopenharmony_ci * driver, then we selectively enable only those bits that 36128c2ecf20Sopenharmony_ci * we want to set. 36138c2ecf20Sopenharmony_ci */ 36148c2ecf20Sopenharmony_ci val64 |= (SWAPPER_CTRL_TXP_FE | 36158c2ecf20Sopenharmony_ci SWAPPER_CTRL_TXP_SE | 36168c2ecf20Sopenharmony_ci SWAPPER_CTRL_TXD_R_FE | 36178c2ecf20Sopenharmony_ci SWAPPER_CTRL_TXD_R_SE | 36188c2ecf20Sopenharmony_ci SWAPPER_CTRL_TXD_W_FE | 36198c2ecf20Sopenharmony_ci SWAPPER_CTRL_TXD_W_SE | 36208c2ecf20Sopenharmony_ci SWAPPER_CTRL_TXF_R_FE | 36218c2ecf20Sopenharmony_ci SWAPPER_CTRL_RXD_R_FE | 36228c2ecf20Sopenharmony_ci SWAPPER_CTRL_RXD_R_SE | 36238c2ecf20Sopenharmony_ci SWAPPER_CTRL_RXD_W_FE | 36248c2ecf20Sopenharmony_ci SWAPPER_CTRL_RXD_W_SE | 36258c2ecf20Sopenharmony_ci SWAPPER_CTRL_RXF_W_FE | 36268c2ecf20Sopenharmony_ci SWAPPER_CTRL_XMSI_FE | 36278c2ecf20Sopenharmony_ci SWAPPER_CTRL_STATS_FE | 36288c2ecf20Sopenharmony_ci SWAPPER_CTRL_STATS_SE); 36298c2ecf20Sopenharmony_ci if (sp->config.intr_type == INTA) 36308c2ecf20Sopenharmony_ci val64 |= SWAPPER_CTRL_XMSI_SE; 36318c2ecf20Sopenharmony_ci writeq(val64, &bar0->swapper_ctrl); 36328c2ecf20Sopenharmony_ci#endif 36338c2ecf20Sopenharmony_ci val64 = readq(&bar0->swapper_ctrl); 36348c2ecf20Sopenharmony_ci 36358c2ecf20Sopenharmony_ci /* 36368c2ecf20Sopenharmony_ci * Verifying if endian settings are accurate by reading a 36378c2ecf20Sopenharmony_ci * feedback register. 36388c2ecf20Sopenharmony_ci */ 36398c2ecf20Sopenharmony_ci val64 = readq(&bar0->pif_rd_swapper_fb); 36408c2ecf20Sopenharmony_ci if (val64 != 0x0123456789ABCDEFULL) { 36418c2ecf20Sopenharmony_ci /* Endian settings are incorrect, calls for another dekko. */ 36428c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 36438c2ecf20Sopenharmony_ci "%s: Endian settings are wrong, feedback read %llx\n", 36448c2ecf20Sopenharmony_ci dev->name, (unsigned long long)val64); 36458c2ecf20Sopenharmony_ci return FAILURE; 36468c2ecf20Sopenharmony_ci } 36478c2ecf20Sopenharmony_ci 36488c2ecf20Sopenharmony_ci return SUCCESS; 36498c2ecf20Sopenharmony_ci} 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_cistatic int wait_for_msix_trans(struct s2io_nic *nic, int i) 36528c2ecf20Sopenharmony_ci{ 36538c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 36548c2ecf20Sopenharmony_ci u64 val64; 36558c2ecf20Sopenharmony_ci int ret = 0, cnt = 0; 36568c2ecf20Sopenharmony_ci 36578c2ecf20Sopenharmony_ci do { 36588c2ecf20Sopenharmony_ci val64 = readq(&bar0->xmsi_access); 36598c2ecf20Sopenharmony_ci if (!(val64 & s2BIT(15))) 36608c2ecf20Sopenharmony_ci break; 36618c2ecf20Sopenharmony_ci mdelay(1); 36628c2ecf20Sopenharmony_ci cnt++; 36638c2ecf20Sopenharmony_ci } while (cnt < 5); 36648c2ecf20Sopenharmony_ci if (cnt == 5) { 36658c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i); 36668c2ecf20Sopenharmony_ci ret = 1; 36678c2ecf20Sopenharmony_ci } 36688c2ecf20Sopenharmony_ci 36698c2ecf20Sopenharmony_ci return ret; 36708c2ecf20Sopenharmony_ci} 36718c2ecf20Sopenharmony_ci 36728c2ecf20Sopenharmony_cistatic void restore_xmsi_data(struct s2io_nic *nic) 36738c2ecf20Sopenharmony_ci{ 36748c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 36758c2ecf20Sopenharmony_ci u64 val64; 36768c2ecf20Sopenharmony_ci int i, msix_index; 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci if (nic->device_type == XFRAME_I_DEVICE) 36798c2ecf20Sopenharmony_ci return; 36808c2ecf20Sopenharmony_ci 36818c2ecf20Sopenharmony_ci for (i = 0; i < MAX_REQUESTED_MSI_X; i++) { 36828c2ecf20Sopenharmony_ci msix_index = (i) ? ((i-1) * 8 + 1) : 0; 36838c2ecf20Sopenharmony_ci writeq(nic->msix_info[i].addr, &bar0->xmsi_address); 36848c2ecf20Sopenharmony_ci writeq(nic->msix_info[i].data, &bar0->xmsi_data); 36858c2ecf20Sopenharmony_ci val64 = (s2BIT(7) | s2BIT(15) | vBIT(msix_index, 26, 6)); 36868c2ecf20Sopenharmony_ci writeq(val64, &bar0->xmsi_access); 36878c2ecf20Sopenharmony_ci if (wait_for_msix_trans(nic, msix_index)) 36888c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: index: %d failed\n", 36898c2ecf20Sopenharmony_ci __func__, msix_index); 36908c2ecf20Sopenharmony_ci } 36918c2ecf20Sopenharmony_ci} 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_cistatic void store_xmsi_data(struct s2io_nic *nic) 36948c2ecf20Sopenharmony_ci{ 36958c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 36968c2ecf20Sopenharmony_ci u64 val64, addr, data; 36978c2ecf20Sopenharmony_ci int i, msix_index; 36988c2ecf20Sopenharmony_ci 36998c2ecf20Sopenharmony_ci if (nic->device_type == XFRAME_I_DEVICE) 37008c2ecf20Sopenharmony_ci return; 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci /* Store and display */ 37038c2ecf20Sopenharmony_ci for (i = 0; i < MAX_REQUESTED_MSI_X; i++) { 37048c2ecf20Sopenharmony_ci msix_index = (i) ? ((i-1) * 8 + 1) : 0; 37058c2ecf20Sopenharmony_ci val64 = (s2BIT(15) | vBIT(msix_index, 26, 6)); 37068c2ecf20Sopenharmony_ci writeq(val64, &bar0->xmsi_access); 37078c2ecf20Sopenharmony_ci if (wait_for_msix_trans(nic, msix_index)) { 37088c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: index: %d failed\n", 37098c2ecf20Sopenharmony_ci __func__, msix_index); 37108c2ecf20Sopenharmony_ci continue; 37118c2ecf20Sopenharmony_ci } 37128c2ecf20Sopenharmony_ci addr = readq(&bar0->xmsi_address); 37138c2ecf20Sopenharmony_ci data = readq(&bar0->xmsi_data); 37148c2ecf20Sopenharmony_ci if (addr && data) { 37158c2ecf20Sopenharmony_ci nic->msix_info[i].addr = addr; 37168c2ecf20Sopenharmony_ci nic->msix_info[i].data = data; 37178c2ecf20Sopenharmony_ci } 37188c2ecf20Sopenharmony_ci } 37198c2ecf20Sopenharmony_ci} 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_cistatic int s2io_enable_msi_x(struct s2io_nic *nic) 37228c2ecf20Sopenharmony_ci{ 37238c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 37248c2ecf20Sopenharmony_ci u64 rx_mat; 37258c2ecf20Sopenharmony_ci u16 msi_control; /* Temp variable */ 37268c2ecf20Sopenharmony_ci int ret, i, j, msix_indx = 1; 37278c2ecf20Sopenharmony_ci int size; 37288c2ecf20Sopenharmony_ci struct stat_block *stats = nic->mac_control.stats_info; 37298c2ecf20Sopenharmony_ci struct swStat *swstats = &stats->sw_stat; 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_ci size = nic->num_entries * sizeof(struct msix_entry); 37328c2ecf20Sopenharmony_ci nic->entries = kzalloc(size, GFP_KERNEL); 37338c2ecf20Sopenharmony_ci if (!nic->entries) { 37348c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", 37358c2ecf20Sopenharmony_ci __func__); 37368c2ecf20Sopenharmony_ci swstats->mem_alloc_fail_cnt++; 37378c2ecf20Sopenharmony_ci return -ENOMEM; 37388c2ecf20Sopenharmony_ci } 37398c2ecf20Sopenharmony_ci swstats->mem_allocated += size; 37408c2ecf20Sopenharmony_ci 37418c2ecf20Sopenharmony_ci size = nic->num_entries * sizeof(struct s2io_msix_entry); 37428c2ecf20Sopenharmony_ci nic->s2io_entries = kzalloc(size, GFP_KERNEL); 37438c2ecf20Sopenharmony_ci if (!nic->s2io_entries) { 37448c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", 37458c2ecf20Sopenharmony_ci __func__); 37468c2ecf20Sopenharmony_ci swstats->mem_alloc_fail_cnt++; 37478c2ecf20Sopenharmony_ci kfree(nic->entries); 37488c2ecf20Sopenharmony_ci swstats->mem_freed 37498c2ecf20Sopenharmony_ci += (nic->num_entries * sizeof(struct msix_entry)); 37508c2ecf20Sopenharmony_ci return -ENOMEM; 37518c2ecf20Sopenharmony_ci } 37528c2ecf20Sopenharmony_ci swstats->mem_allocated += size; 37538c2ecf20Sopenharmony_ci 37548c2ecf20Sopenharmony_ci nic->entries[0].entry = 0; 37558c2ecf20Sopenharmony_ci nic->s2io_entries[0].entry = 0; 37568c2ecf20Sopenharmony_ci nic->s2io_entries[0].in_use = MSIX_FLG; 37578c2ecf20Sopenharmony_ci nic->s2io_entries[0].type = MSIX_ALARM_TYPE; 37588c2ecf20Sopenharmony_ci nic->s2io_entries[0].arg = &nic->mac_control.fifos; 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ci for (i = 1; i < nic->num_entries; i++) { 37618c2ecf20Sopenharmony_ci nic->entries[i].entry = ((i - 1) * 8) + 1; 37628c2ecf20Sopenharmony_ci nic->s2io_entries[i].entry = ((i - 1) * 8) + 1; 37638c2ecf20Sopenharmony_ci nic->s2io_entries[i].arg = NULL; 37648c2ecf20Sopenharmony_ci nic->s2io_entries[i].in_use = 0; 37658c2ecf20Sopenharmony_ci } 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci rx_mat = readq(&bar0->rx_mat); 37688c2ecf20Sopenharmony_ci for (j = 0; j < nic->config.rx_ring_num; j++) { 37698c2ecf20Sopenharmony_ci rx_mat |= RX_MAT_SET(j, msix_indx); 37708c2ecf20Sopenharmony_ci nic->s2io_entries[j+1].arg = &nic->mac_control.rings[j]; 37718c2ecf20Sopenharmony_ci nic->s2io_entries[j+1].type = MSIX_RING_TYPE; 37728c2ecf20Sopenharmony_ci nic->s2io_entries[j+1].in_use = MSIX_FLG; 37738c2ecf20Sopenharmony_ci msix_indx += 8; 37748c2ecf20Sopenharmony_ci } 37758c2ecf20Sopenharmony_ci writeq(rx_mat, &bar0->rx_mat); 37768c2ecf20Sopenharmony_ci readq(&bar0->rx_mat); 37778c2ecf20Sopenharmony_ci 37788c2ecf20Sopenharmony_ci ret = pci_enable_msix_range(nic->pdev, nic->entries, 37798c2ecf20Sopenharmony_ci nic->num_entries, nic->num_entries); 37808c2ecf20Sopenharmony_ci /* We fail init if error or we get less vectors than min required */ 37818c2ecf20Sopenharmony_ci if (ret < 0) { 37828c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Enabling MSI-X failed\n"); 37838c2ecf20Sopenharmony_ci kfree(nic->entries); 37848c2ecf20Sopenharmony_ci swstats->mem_freed += nic->num_entries * 37858c2ecf20Sopenharmony_ci sizeof(struct msix_entry); 37868c2ecf20Sopenharmony_ci kfree(nic->s2io_entries); 37878c2ecf20Sopenharmony_ci swstats->mem_freed += nic->num_entries * 37888c2ecf20Sopenharmony_ci sizeof(struct s2io_msix_entry); 37898c2ecf20Sopenharmony_ci nic->entries = NULL; 37908c2ecf20Sopenharmony_ci nic->s2io_entries = NULL; 37918c2ecf20Sopenharmony_ci return -ENOMEM; 37928c2ecf20Sopenharmony_ci } 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_ci /* 37958c2ecf20Sopenharmony_ci * To enable MSI-X, MSI also needs to be enabled, due to a bug 37968c2ecf20Sopenharmony_ci * in the herc NIC. (Temp change, needs to be removed later) 37978c2ecf20Sopenharmony_ci */ 37988c2ecf20Sopenharmony_ci pci_read_config_word(nic->pdev, 0x42, &msi_control); 37998c2ecf20Sopenharmony_ci msi_control |= 0x1; /* Enable MSI */ 38008c2ecf20Sopenharmony_ci pci_write_config_word(nic->pdev, 0x42, msi_control); 38018c2ecf20Sopenharmony_ci 38028c2ecf20Sopenharmony_ci return 0; 38038c2ecf20Sopenharmony_ci} 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci/* Handle software interrupt used during MSI(X) test */ 38068c2ecf20Sopenharmony_cistatic irqreturn_t s2io_test_intr(int irq, void *dev_id) 38078c2ecf20Sopenharmony_ci{ 38088c2ecf20Sopenharmony_ci struct s2io_nic *sp = dev_id; 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci sp->msi_detected = 1; 38118c2ecf20Sopenharmony_ci wake_up(&sp->msi_wait); 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_ci return IRQ_HANDLED; 38148c2ecf20Sopenharmony_ci} 38158c2ecf20Sopenharmony_ci 38168c2ecf20Sopenharmony_ci/* Test interrupt path by forcing a a software IRQ */ 38178c2ecf20Sopenharmony_cistatic int s2io_test_msi(struct s2io_nic *sp) 38188c2ecf20Sopenharmony_ci{ 38198c2ecf20Sopenharmony_ci struct pci_dev *pdev = sp->pdev; 38208c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 38218c2ecf20Sopenharmony_ci int err; 38228c2ecf20Sopenharmony_ci u64 val64, saved64; 38238c2ecf20Sopenharmony_ci 38248c2ecf20Sopenharmony_ci err = request_irq(sp->entries[1].vector, s2io_test_intr, 0, 38258c2ecf20Sopenharmony_ci sp->name, sp); 38268c2ecf20Sopenharmony_ci if (err) { 38278c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: PCI %s: cannot assign irq %d\n", 38288c2ecf20Sopenharmony_ci sp->dev->name, pci_name(pdev), pdev->irq); 38298c2ecf20Sopenharmony_ci return err; 38308c2ecf20Sopenharmony_ci } 38318c2ecf20Sopenharmony_ci 38328c2ecf20Sopenharmony_ci init_waitqueue_head(&sp->msi_wait); 38338c2ecf20Sopenharmony_ci sp->msi_detected = 0; 38348c2ecf20Sopenharmony_ci 38358c2ecf20Sopenharmony_ci saved64 = val64 = readq(&bar0->scheduled_int_ctrl); 38368c2ecf20Sopenharmony_ci val64 |= SCHED_INT_CTRL_ONE_SHOT; 38378c2ecf20Sopenharmony_ci val64 |= SCHED_INT_CTRL_TIMER_EN; 38388c2ecf20Sopenharmony_ci val64 |= SCHED_INT_CTRL_INT2MSI(1); 38398c2ecf20Sopenharmony_ci writeq(val64, &bar0->scheduled_int_ctrl); 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci wait_event_timeout(sp->msi_wait, sp->msi_detected, HZ/10); 38428c2ecf20Sopenharmony_ci 38438c2ecf20Sopenharmony_ci if (!sp->msi_detected) { 38448c2ecf20Sopenharmony_ci /* MSI(X) test failed, go back to INTx mode */ 38458c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated " 38468c2ecf20Sopenharmony_ci "using MSI(X) during test\n", 38478c2ecf20Sopenharmony_ci sp->dev->name, pci_name(pdev)); 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci err = -EOPNOTSUPP; 38508c2ecf20Sopenharmony_ci } 38518c2ecf20Sopenharmony_ci 38528c2ecf20Sopenharmony_ci free_irq(sp->entries[1].vector, sp); 38538c2ecf20Sopenharmony_ci 38548c2ecf20Sopenharmony_ci writeq(saved64, &bar0->scheduled_int_ctrl); 38558c2ecf20Sopenharmony_ci 38568c2ecf20Sopenharmony_ci return err; 38578c2ecf20Sopenharmony_ci} 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_cistatic void remove_msix_isr(struct s2io_nic *sp) 38608c2ecf20Sopenharmony_ci{ 38618c2ecf20Sopenharmony_ci int i; 38628c2ecf20Sopenharmony_ci u16 msi_control; 38638c2ecf20Sopenharmony_ci 38648c2ecf20Sopenharmony_ci for (i = 0; i < sp->num_entries; i++) { 38658c2ecf20Sopenharmony_ci if (sp->s2io_entries[i].in_use == MSIX_REGISTERED_SUCCESS) { 38668c2ecf20Sopenharmony_ci int vector = sp->entries[i].vector; 38678c2ecf20Sopenharmony_ci void *arg = sp->s2io_entries[i].arg; 38688c2ecf20Sopenharmony_ci free_irq(vector, arg); 38698c2ecf20Sopenharmony_ci } 38708c2ecf20Sopenharmony_ci } 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ci kfree(sp->entries); 38738c2ecf20Sopenharmony_ci kfree(sp->s2io_entries); 38748c2ecf20Sopenharmony_ci sp->entries = NULL; 38758c2ecf20Sopenharmony_ci sp->s2io_entries = NULL; 38768c2ecf20Sopenharmony_ci 38778c2ecf20Sopenharmony_ci pci_read_config_word(sp->pdev, 0x42, &msi_control); 38788c2ecf20Sopenharmony_ci msi_control &= 0xFFFE; /* Disable MSI */ 38798c2ecf20Sopenharmony_ci pci_write_config_word(sp->pdev, 0x42, msi_control); 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ci pci_disable_msix(sp->pdev); 38828c2ecf20Sopenharmony_ci} 38838c2ecf20Sopenharmony_ci 38848c2ecf20Sopenharmony_cistatic void remove_inta_isr(struct s2io_nic *sp) 38858c2ecf20Sopenharmony_ci{ 38868c2ecf20Sopenharmony_ci free_irq(sp->pdev->irq, sp->dev); 38878c2ecf20Sopenharmony_ci} 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_ci/* ********************************************************* * 38908c2ecf20Sopenharmony_ci * Functions defined below concern the OS part of the driver * 38918c2ecf20Sopenharmony_ci * ********************************************************* */ 38928c2ecf20Sopenharmony_ci 38938c2ecf20Sopenharmony_ci/** 38948c2ecf20Sopenharmony_ci * s2io_open - open entry point of the driver 38958c2ecf20Sopenharmony_ci * @dev : pointer to the device structure. 38968c2ecf20Sopenharmony_ci * Description: 38978c2ecf20Sopenharmony_ci * This function is the open entry point of the driver. It mainly calls a 38988c2ecf20Sopenharmony_ci * function to allocate Rx buffers and inserts them into the buffer 38998c2ecf20Sopenharmony_ci * descriptors and then enables the Rx part of the NIC. 39008c2ecf20Sopenharmony_ci * Return value: 39018c2ecf20Sopenharmony_ci * 0 on success and an appropriate (-)ve integer as defined in errno.h 39028c2ecf20Sopenharmony_ci * file on failure. 39038c2ecf20Sopenharmony_ci */ 39048c2ecf20Sopenharmony_ci 39058c2ecf20Sopenharmony_cistatic int s2io_open(struct net_device *dev) 39068c2ecf20Sopenharmony_ci{ 39078c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 39088c2ecf20Sopenharmony_ci struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; 39098c2ecf20Sopenharmony_ci int err = 0; 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci /* 39128c2ecf20Sopenharmony_ci * Make sure you have link off by default every time 39138c2ecf20Sopenharmony_ci * Nic is initialized 39148c2ecf20Sopenharmony_ci */ 39158c2ecf20Sopenharmony_ci netif_carrier_off(dev); 39168c2ecf20Sopenharmony_ci sp->last_link_state = 0; 39178c2ecf20Sopenharmony_ci 39188c2ecf20Sopenharmony_ci /* Initialize H/W and enable interrupts */ 39198c2ecf20Sopenharmony_ci err = s2io_card_up(sp); 39208c2ecf20Sopenharmony_ci if (err) { 39218c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n", 39228c2ecf20Sopenharmony_ci dev->name); 39238c2ecf20Sopenharmony_ci goto hw_init_failed; 39248c2ecf20Sopenharmony_ci } 39258c2ecf20Sopenharmony_ci 39268c2ecf20Sopenharmony_ci if (do_s2io_prog_unicast(dev, dev->dev_addr) == FAILURE) { 39278c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n"); 39288c2ecf20Sopenharmony_ci s2io_card_down(sp); 39298c2ecf20Sopenharmony_ci err = -ENODEV; 39308c2ecf20Sopenharmony_ci goto hw_init_failed; 39318c2ecf20Sopenharmony_ci } 39328c2ecf20Sopenharmony_ci s2io_start_all_tx_queue(sp); 39338c2ecf20Sopenharmony_ci return 0; 39348c2ecf20Sopenharmony_ci 39358c2ecf20Sopenharmony_cihw_init_failed: 39368c2ecf20Sopenharmony_ci if (sp->config.intr_type == MSI_X) { 39378c2ecf20Sopenharmony_ci if (sp->entries) { 39388c2ecf20Sopenharmony_ci kfree(sp->entries); 39398c2ecf20Sopenharmony_ci swstats->mem_freed += sp->num_entries * 39408c2ecf20Sopenharmony_ci sizeof(struct msix_entry); 39418c2ecf20Sopenharmony_ci } 39428c2ecf20Sopenharmony_ci if (sp->s2io_entries) { 39438c2ecf20Sopenharmony_ci kfree(sp->s2io_entries); 39448c2ecf20Sopenharmony_ci swstats->mem_freed += sp->num_entries * 39458c2ecf20Sopenharmony_ci sizeof(struct s2io_msix_entry); 39468c2ecf20Sopenharmony_ci } 39478c2ecf20Sopenharmony_ci } 39488c2ecf20Sopenharmony_ci return err; 39498c2ecf20Sopenharmony_ci} 39508c2ecf20Sopenharmony_ci 39518c2ecf20Sopenharmony_ci/** 39528c2ecf20Sopenharmony_ci * s2io_close -close entry point of the driver 39538c2ecf20Sopenharmony_ci * @dev : device pointer. 39548c2ecf20Sopenharmony_ci * Description: 39558c2ecf20Sopenharmony_ci * This is the stop entry point of the driver. It needs to undo exactly 39568c2ecf20Sopenharmony_ci * whatever was done by the open entry point,thus it's usually referred to 39578c2ecf20Sopenharmony_ci * as the close function.Among other things this function mainly stops the 39588c2ecf20Sopenharmony_ci * Rx side of the NIC and frees all the Rx buffers in the Rx rings. 39598c2ecf20Sopenharmony_ci * Return value: 39608c2ecf20Sopenharmony_ci * 0 on success and an appropriate (-)ve integer as defined in errno.h 39618c2ecf20Sopenharmony_ci * file on failure. 39628c2ecf20Sopenharmony_ci */ 39638c2ecf20Sopenharmony_ci 39648c2ecf20Sopenharmony_cistatic int s2io_close(struct net_device *dev) 39658c2ecf20Sopenharmony_ci{ 39668c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 39678c2ecf20Sopenharmony_ci struct config_param *config = &sp->config; 39688c2ecf20Sopenharmony_ci u64 tmp64; 39698c2ecf20Sopenharmony_ci int offset; 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci /* Return if the device is already closed * 39728c2ecf20Sopenharmony_ci * Can happen when s2io_card_up failed in change_mtu * 39738c2ecf20Sopenharmony_ci */ 39748c2ecf20Sopenharmony_ci if (!is_s2io_card_up(sp)) 39758c2ecf20Sopenharmony_ci return 0; 39768c2ecf20Sopenharmony_ci 39778c2ecf20Sopenharmony_ci s2io_stop_all_tx_queue(sp); 39788c2ecf20Sopenharmony_ci /* delete all populated mac entries */ 39798c2ecf20Sopenharmony_ci for (offset = 1; offset < config->max_mc_addr; offset++) { 39808c2ecf20Sopenharmony_ci tmp64 = do_s2io_read_unicast_mc(sp, offset); 39818c2ecf20Sopenharmony_ci if (tmp64 != S2IO_DISABLE_MAC_ENTRY) 39828c2ecf20Sopenharmony_ci do_s2io_delete_unicast_mc(sp, tmp64); 39838c2ecf20Sopenharmony_ci } 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_ci s2io_card_down(sp); 39868c2ecf20Sopenharmony_ci 39878c2ecf20Sopenharmony_ci return 0; 39888c2ecf20Sopenharmony_ci} 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci/** 39918c2ecf20Sopenharmony_ci * s2io_xmit - Tx entry point of te driver 39928c2ecf20Sopenharmony_ci * @skb : the socket buffer containing the Tx data. 39938c2ecf20Sopenharmony_ci * @dev : device pointer. 39948c2ecf20Sopenharmony_ci * Description : 39958c2ecf20Sopenharmony_ci * This function is the Tx entry point of the driver. S2IO NIC supports 39968c2ecf20Sopenharmony_ci * certain protocol assist features on Tx side, namely CSO, S/G, LSO. 39978c2ecf20Sopenharmony_ci * NOTE: when device can't queue the pkt,just the trans_start variable will 39988c2ecf20Sopenharmony_ci * not be upadted. 39998c2ecf20Sopenharmony_ci * Return value: 40008c2ecf20Sopenharmony_ci * 0 on success & 1 on failure. 40018c2ecf20Sopenharmony_ci */ 40028c2ecf20Sopenharmony_ci 40038c2ecf20Sopenharmony_cistatic netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev) 40048c2ecf20Sopenharmony_ci{ 40058c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 40068c2ecf20Sopenharmony_ci u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off; 40078c2ecf20Sopenharmony_ci register u64 val64; 40088c2ecf20Sopenharmony_ci struct TxD *txdp; 40098c2ecf20Sopenharmony_ci struct TxFIFO_element __iomem *tx_fifo; 40108c2ecf20Sopenharmony_ci unsigned long flags = 0; 40118c2ecf20Sopenharmony_ci u16 vlan_tag = 0; 40128c2ecf20Sopenharmony_ci struct fifo_info *fifo = NULL; 40138c2ecf20Sopenharmony_ci int offload_type; 40148c2ecf20Sopenharmony_ci int enable_per_list_interrupt = 0; 40158c2ecf20Sopenharmony_ci struct config_param *config = &sp->config; 40168c2ecf20Sopenharmony_ci struct mac_info *mac_control = &sp->mac_control; 40178c2ecf20Sopenharmony_ci struct stat_block *stats = mac_control->stats_info; 40188c2ecf20Sopenharmony_ci struct swStat *swstats = &stats->sw_stat; 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ci DBG_PRINT(TX_DBG, "%s: In Neterion Tx routine\n", dev->name); 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci if (unlikely(skb->len <= 0)) { 40238c2ecf20Sopenharmony_ci DBG_PRINT(TX_DBG, "%s: Buffer has no data..\n", dev->name); 40248c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 40258c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 40268c2ecf20Sopenharmony_ci } 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci if (!is_s2io_card_up(sp)) { 40298c2ecf20Sopenharmony_ci DBG_PRINT(TX_DBG, "%s: Card going down for reset\n", 40308c2ecf20Sopenharmony_ci dev->name); 40318c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 40328c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 40338c2ecf20Sopenharmony_ci } 40348c2ecf20Sopenharmony_ci 40358c2ecf20Sopenharmony_ci queue = 0; 40368c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) 40378c2ecf20Sopenharmony_ci vlan_tag = skb_vlan_tag_get(skb); 40388c2ecf20Sopenharmony_ci if (sp->config.tx_steering_type == TX_DEFAULT_STEERING) { 40398c2ecf20Sopenharmony_ci if (skb->protocol == htons(ETH_P_IP)) { 40408c2ecf20Sopenharmony_ci struct iphdr *ip; 40418c2ecf20Sopenharmony_ci struct tcphdr *th; 40428c2ecf20Sopenharmony_ci ip = ip_hdr(skb); 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ci if (!ip_is_fragment(ip)) { 40458c2ecf20Sopenharmony_ci th = (struct tcphdr *)(((unsigned char *)ip) + 40468c2ecf20Sopenharmony_ci ip->ihl*4); 40478c2ecf20Sopenharmony_ci 40488c2ecf20Sopenharmony_ci if (ip->protocol == IPPROTO_TCP) { 40498c2ecf20Sopenharmony_ci queue_len = sp->total_tcp_fifos; 40508c2ecf20Sopenharmony_ci queue = (ntohs(th->source) + 40518c2ecf20Sopenharmony_ci ntohs(th->dest)) & 40528c2ecf20Sopenharmony_ci sp->fifo_selector[queue_len - 1]; 40538c2ecf20Sopenharmony_ci if (queue >= queue_len) 40548c2ecf20Sopenharmony_ci queue = queue_len - 1; 40558c2ecf20Sopenharmony_ci } else if (ip->protocol == IPPROTO_UDP) { 40568c2ecf20Sopenharmony_ci queue_len = sp->total_udp_fifos; 40578c2ecf20Sopenharmony_ci queue = (ntohs(th->source) + 40588c2ecf20Sopenharmony_ci ntohs(th->dest)) & 40598c2ecf20Sopenharmony_ci sp->fifo_selector[queue_len - 1]; 40608c2ecf20Sopenharmony_ci if (queue >= queue_len) 40618c2ecf20Sopenharmony_ci queue = queue_len - 1; 40628c2ecf20Sopenharmony_ci queue += sp->udp_fifo_idx; 40638c2ecf20Sopenharmony_ci if (skb->len > 1024) 40648c2ecf20Sopenharmony_ci enable_per_list_interrupt = 1; 40658c2ecf20Sopenharmony_ci } 40668c2ecf20Sopenharmony_ci } 40678c2ecf20Sopenharmony_ci } 40688c2ecf20Sopenharmony_ci } else if (sp->config.tx_steering_type == TX_PRIORITY_STEERING) 40698c2ecf20Sopenharmony_ci /* get fifo number based on skb->priority value */ 40708c2ecf20Sopenharmony_ci queue = config->fifo_mapping 40718c2ecf20Sopenharmony_ci [skb->priority & (MAX_TX_FIFOS - 1)]; 40728c2ecf20Sopenharmony_ci fifo = &mac_control->fifos[queue]; 40738c2ecf20Sopenharmony_ci 40748c2ecf20Sopenharmony_ci spin_lock_irqsave(&fifo->tx_lock, flags); 40758c2ecf20Sopenharmony_ci 40768c2ecf20Sopenharmony_ci if (sp->config.multiq) { 40778c2ecf20Sopenharmony_ci if (__netif_subqueue_stopped(dev, fifo->fifo_no)) { 40788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fifo->tx_lock, flags); 40798c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 40808c2ecf20Sopenharmony_ci } 40818c2ecf20Sopenharmony_ci } else if (unlikely(fifo->queue_state == FIFO_QUEUE_STOP)) { 40828c2ecf20Sopenharmony_ci if (netif_queue_stopped(dev)) { 40838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fifo->tx_lock, flags); 40848c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 40858c2ecf20Sopenharmony_ci } 40868c2ecf20Sopenharmony_ci } 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci put_off = (u16)fifo->tx_curr_put_info.offset; 40898c2ecf20Sopenharmony_ci get_off = (u16)fifo->tx_curr_get_info.offset; 40908c2ecf20Sopenharmony_ci txdp = fifo->list_info[put_off].list_virt_addr; 40918c2ecf20Sopenharmony_ci 40928c2ecf20Sopenharmony_ci queue_len = fifo->tx_curr_put_info.fifo_len + 1; 40938c2ecf20Sopenharmony_ci /* Avoid "put" pointer going beyond "get" pointer */ 40948c2ecf20Sopenharmony_ci if (txdp->Host_Control || 40958c2ecf20Sopenharmony_ci ((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) { 40968c2ecf20Sopenharmony_ci DBG_PRINT(TX_DBG, "Error in xmit, No free TXDs.\n"); 40978c2ecf20Sopenharmony_ci s2io_stop_tx_queue(sp, fifo->fifo_no); 40988c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 40998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fifo->tx_lock, flags); 41008c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 41018c2ecf20Sopenharmony_ci } 41028c2ecf20Sopenharmony_ci 41038c2ecf20Sopenharmony_ci offload_type = s2io_offload_type(skb); 41048c2ecf20Sopenharmony_ci if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) { 41058c2ecf20Sopenharmony_ci txdp->Control_1 |= TXD_TCP_LSO_EN; 41068c2ecf20Sopenharmony_ci txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb)); 41078c2ecf20Sopenharmony_ci } 41088c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) { 41098c2ecf20Sopenharmony_ci txdp->Control_2 |= (TXD_TX_CKO_IPV4_EN | 41108c2ecf20Sopenharmony_ci TXD_TX_CKO_TCP_EN | 41118c2ecf20Sopenharmony_ci TXD_TX_CKO_UDP_EN); 41128c2ecf20Sopenharmony_ci } 41138c2ecf20Sopenharmony_ci txdp->Control_1 |= TXD_GATHER_CODE_FIRST; 41148c2ecf20Sopenharmony_ci txdp->Control_1 |= TXD_LIST_OWN_XENA; 41158c2ecf20Sopenharmony_ci txdp->Control_2 |= TXD_INT_NUMBER(fifo->fifo_no); 41168c2ecf20Sopenharmony_ci if (enable_per_list_interrupt) 41178c2ecf20Sopenharmony_ci if (put_off & (queue_len >> 5)) 41188c2ecf20Sopenharmony_ci txdp->Control_2 |= TXD_INT_TYPE_PER_LIST; 41198c2ecf20Sopenharmony_ci if (vlan_tag) { 41208c2ecf20Sopenharmony_ci txdp->Control_2 |= TXD_VLAN_ENABLE; 41218c2ecf20Sopenharmony_ci txdp->Control_2 |= TXD_VLAN_TAG(vlan_tag); 41228c2ecf20Sopenharmony_ci } 41238c2ecf20Sopenharmony_ci 41248c2ecf20Sopenharmony_ci frg_len = skb_headlen(skb); 41258c2ecf20Sopenharmony_ci txdp->Buffer_Pointer = dma_map_single(&sp->pdev->dev, skb->data, 41268c2ecf20Sopenharmony_ci frg_len, DMA_TO_DEVICE); 41278c2ecf20Sopenharmony_ci if (dma_mapping_error(&sp->pdev->dev, txdp->Buffer_Pointer)) 41288c2ecf20Sopenharmony_ci goto pci_map_failed; 41298c2ecf20Sopenharmony_ci 41308c2ecf20Sopenharmony_ci txdp->Host_Control = (unsigned long)skb; 41318c2ecf20Sopenharmony_ci txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len); 41328c2ecf20Sopenharmony_ci 41338c2ecf20Sopenharmony_ci frg_cnt = skb_shinfo(skb)->nr_frags; 41348c2ecf20Sopenharmony_ci /* For fragmented SKB. */ 41358c2ecf20Sopenharmony_ci for (i = 0; i < frg_cnt; i++) { 41368c2ecf20Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 41378c2ecf20Sopenharmony_ci /* A '0' length fragment will be ignored */ 41388c2ecf20Sopenharmony_ci if (!skb_frag_size(frag)) 41398c2ecf20Sopenharmony_ci continue; 41408c2ecf20Sopenharmony_ci txdp++; 41418c2ecf20Sopenharmony_ci txdp->Buffer_Pointer = (u64)skb_frag_dma_map(&sp->pdev->dev, 41428c2ecf20Sopenharmony_ci frag, 0, 41438c2ecf20Sopenharmony_ci skb_frag_size(frag), 41448c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 41458c2ecf20Sopenharmony_ci txdp->Control_1 = TXD_BUFFER0_SIZE(skb_frag_size(frag)); 41468c2ecf20Sopenharmony_ci } 41478c2ecf20Sopenharmony_ci txdp->Control_1 |= TXD_GATHER_CODE_LAST; 41488c2ecf20Sopenharmony_ci 41498c2ecf20Sopenharmony_ci tx_fifo = mac_control->tx_FIFO_start[queue]; 41508c2ecf20Sopenharmony_ci val64 = fifo->list_info[put_off].list_phy_addr; 41518c2ecf20Sopenharmony_ci writeq(val64, &tx_fifo->TxDL_Pointer); 41528c2ecf20Sopenharmony_ci 41538c2ecf20Sopenharmony_ci val64 = (TX_FIFO_LAST_TXD_NUM(frg_cnt) | TX_FIFO_FIRST_LIST | 41548c2ecf20Sopenharmony_ci TX_FIFO_LAST_LIST); 41558c2ecf20Sopenharmony_ci if (offload_type) 41568c2ecf20Sopenharmony_ci val64 |= TX_FIFO_SPECIAL_FUNC; 41578c2ecf20Sopenharmony_ci 41588c2ecf20Sopenharmony_ci writeq(val64, &tx_fifo->List_Control); 41598c2ecf20Sopenharmony_ci 41608c2ecf20Sopenharmony_ci put_off++; 41618c2ecf20Sopenharmony_ci if (put_off == fifo->tx_curr_put_info.fifo_len + 1) 41628c2ecf20Sopenharmony_ci put_off = 0; 41638c2ecf20Sopenharmony_ci fifo->tx_curr_put_info.offset = put_off; 41648c2ecf20Sopenharmony_ci 41658c2ecf20Sopenharmony_ci /* Avoid "put" pointer going beyond "get" pointer */ 41668c2ecf20Sopenharmony_ci if (((put_off+1) == queue_len ? 0 : (put_off+1)) == get_off) { 41678c2ecf20Sopenharmony_ci swstats->fifo_full_cnt++; 41688c2ecf20Sopenharmony_ci DBG_PRINT(TX_DBG, 41698c2ecf20Sopenharmony_ci "No free TxDs for xmit, Put: 0x%x Get:0x%x\n", 41708c2ecf20Sopenharmony_ci put_off, get_off); 41718c2ecf20Sopenharmony_ci s2io_stop_tx_queue(sp, fifo->fifo_no); 41728c2ecf20Sopenharmony_ci } 41738c2ecf20Sopenharmony_ci swstats->mem_allocated += skb->truesize; 41748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fifo->tx_lock, flags); 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci if (sp->config.intr_type == MSI_X) 41778c2ecf20Sopenharmony_ci tx_intr_handler(fifo); 41788c2ecf20Sopenharmony_ci 41798c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 41808c2ecf20Sopenharmony_ci 41818c2ecf20Sopenharmony_cipci_map_failed: 41828c2ecf20Sopenharmony_ci swstats->pci_map_fail_cnt++; 41838c2ecf20Sopenharmony_ci s2io_stop_tx_queue(sp, fifo->fifo_no); 41848c2ecf20Sopenharmony_ci swstats->mem_freed += skb->truesize; 41858c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 41868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fifo->tx_lock, flags); 41878c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 41888c2ecf20Sopenharmony_ci} 41898c2ecf20Sopenharmony_ci 41908c2ecf20Sopenharmony_cistatic void 41918c2ecf20Sopenharmony_cis2io_alarm_handle(struct timer_list *t) 41928c2ecf20Sopenharmony_ci{ 41938c2ecf20Sopenharmony_ci struct s2io_nic *sp = from_timer(sp, t, alarm_timer); 41948c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 41958c2ecf20Sopenharmony_ci 41968c2ecf20Sopenharmony_ci s2io_handle_errors(dev); 41978c2ecf20Sopenharmony_ci mod_timer(&sp->alarm_timer, jiffies + HZ / 2); 41988c2ecf20Sopenharmony_ci} 41998c2ecf20Sopenharmony_ci 42008c2ecf20Sopenharmony_cistatic irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) 42018c2ecf20Sopenharmony_ci{ 42028c2ecf20Sopenharmony_ci struct ring_info *ring = (struct ring_info *)dev_id; 42038c2ecf20Sopenharmony_ci struct s2io_nic *sp = ring->nic; 42048c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 42058c2ecf20Sopenharmony_ci 42068c2ecf20Sopenharmony_ci if (unlikely(!is_s2io_card_up(sp))) 42078c2ecf20Sopenharmony_ci return IRQ_HANDLED; 42088c2ecf20Sopenharmony_ci 42098c2ecf20Sopenharmony_ci if (sp->config.napi) { 42108c2ecf20Sopenharmony_ci u8 __iomem *addr = NULL; 42118c2ecf20Sopenharmony_ci u8 val8 = 0; 42128c2ecf20Sopenharmony_ci 42138c2ecf20Sopenharmony_ci addr = (u8 __iomem *)&bar0->xmsi_mask_reg; 42148c2ecf20Sopenharmony_ci addr += (7 - ring->ring_no); 42158c2ecf20Sopenharmony_ci val8 = (ring->ring_no == 0) ? 0x7f : 0xff; 42168c2ecf20Sopenharmony_ci writeb(val8, addr); 42178c2ecf20Sopenharmony_ci val8 = readb(addr); 42188c2ecf20Sopenharmony_ci napi_schedule(&ring->napi); 42198c2ecf20Sopenharmony_ci } else { 42208c2ecf20Sopenharmony_ci rx_intr_handler(ring, 0); 42218c2ecf20Sopenharmony_ci s2io_chk_rx_buffers(sp, ring); 42228c2ecf20Sopenharmony_ci } 42238c2ecf20Sopenharmony_ci 42248c2ecf20Sopenharmony_ci return IRQ_HANDLED; 42258c2ecf20Sopenharmony_ci} 42268c2ecf20Sopenharmony_ci 42278c2ecf20Sopenharmony_cistatic irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id) 42288c2ecf20Sopenharmony_ci{ 42298c2ecf20Sopenharmony_ci int i; 42308c2ecf20Sopenharmony_ci struct fifo_info *fifos = (struct fifo_info *)dev_id; 42318c2ecf20Sopenharmony_ci struct s2io_nic *sp = fifos->nic; 42328c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 42338c2ecf20Sopenharmony_ci struct config_param *config = &sp->config; 42348c2ecf20Sopenharmony_ci u64 reason; 42358c2ecf20Sopenharmony_ci 42368c2ecf20Sopenharmony_ci if (unlikely(!is_s2io_card_up(sp))) 42378c2ecf20Sopenharmony_ci return IRQ_NONE; 42388c2ecf20Sopenharmony_ci 42398c2ecf20Sopenharmony_ci reason = readq(&bar0->general_int_status); 42408c2ecf20Sopenharmony_ci if (unlikely(reason == S2IO_MINUS_ONE)) 42418c2ecf20Sopenharmony_ci /* Nothing much can be done. Get out */ 42428c2ecf20Sopenharmony_ci return IRQ_HANDLED; 42438c2ecf20Sopenharmony_ci 42448c2ecf20Sopenharmony_ci if (reason & (GEN_INTR_TXPIC | GEN_INTR_TXTRAFFIC)) { 42458c2ecf20Sopenharmony_ci writeq(S2IO_MINUS_ONE, &bar0->general_int_mask); 42468c2ecf20Sopenharmony_ci 42478c2ecf20Sopenharmony_ci if (reason & GEN_INTR_TXPIC) 42488c2ecf20Sopenharmony_ci s2io_txpic_intr_handle(sp); 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_ci if (reason & GEN_INTR_TXTRAFFIC) 42518c2ecf20Sopenharmony_ci writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int); 42528c2ecf20Sopenharmony_ci 42538c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) 42548c2ecf20Sopenharmony_ci tx_intr_handler(&fifos[i]); 42558c2ecf20Sopenharmony_ci 42568c2ecf20Sopenharmony_ci writeq(sp->general_int_mask, &bar0->general_int_mask); 42578c2ecf20Sopenharmony_ci readl(&bar0->general_int_status); 42588c2ecf20Sopenharmony_ci return IRQ_HANDLED; 42598c2ecf20Sopenharmony_ci } 42608c2ecf20Sopenharmony_ci /* The interrupt was not raised by us */ 42618c2ecf20Sopenharmony_ci return IRQ_NONE; 42628c2ecf20Sopenharmony_ci} 42638c2ecf20Sopenharmony_ci 42648c2ecf20Sopenharmony_cistatic void s2io_txpic_intr_handle(struct s2io_nic *sp) 42658c2ecf20Sopenharmony_ci{ 42668c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 42678c2ecf20Sopenharmony_ci u64 val64; 42688c2ecf20Sopenharmony_ci 42698c2ecf20Sopenharmony_ci val64 = readq(&bar0->pic_int_status); 42708c2ecf20Sopenharmony_ci if (val64 & PIC_INT_GPIO) { 42718c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_int_reg); 42728c2ecf20Sopenharmony_ci if ((val64 & GPIO_INT_REG_LINK_DOWN) && 42738c2ecf20Sopenharmony_ci (val64 & GPIO_INT_REG_LINK_UP)) { 42748c2ecf20Sopenharmony_ci /* 42758c2ecf20Sopenharmony_ci * This is unstable state so clear both up/down 42768c2ecf20Sopenharmony_ci * interrupt and adapter to re-evaluate the link state. 42778c2ecf20Sopenharmony_ci */ 42788c2ecf20Sopenharmony_ci val64 |= GPIO_INT_REG_LINK_DOWN; 42798c2ecf20Sopenharmony_ci val64 |= GPIO_INT_REG_LINK_UP; 42808c2ecf20Sopenharmony_ci writeq(val64, &bar0->gpio_int_reg); 42818c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_int_mask); 42828c2ecf20Sopenharmony_ci val64 &= ~(GPIO_INT_MASK_LINK_UP | 42838c2ecf20Sopenharmony_ci GPIO_INT_MASK_LINK_DOWN); 42848c2ecf20Sopenharmony_ci writeq(val64, &bar0->gpio_int_mask); 42858c2ecf20Sopenharmony_ci } else if (val64 & GPIO_INT_REG_LINK_UP) { 42868c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_status); 42878c2ecf20Sopenharmony_ci /* Enable Adapter */ 42888c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_control); 42898c2ecf20Sopenharmony_ci val64 |= ADAPTER_CNTL_EN; 42908c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 42918c2ecf20Sopenharmony_ci val64 |= ADAPTER_LED_ON; 42928c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 42938c2ecf20Sopenharmony_ci if (!sp->device_enabled_once) 42948c2ecf20Sopenharmony_ci sp->device_enabled_once = 1; 42958c2ecf20Sopenharmony_ci 42968c2ecf20Sopenharmony_ci s2io_link(sp, LINK_UP); 42978c2ecf20Sopenharmony_ci /* 42988c2ecf20Sopenharmony_ci * unmask link down interrupt and mask link-up 42998c2ecf20Sopenharmony_ci * intr 43008c2ecf20Sopenharmony_ci */ 43018c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_int_mask); 43028c2ecf20Sopenharmony_ci val64 &= ~GPIO_INT_MASK_LINK_DOWN; 43038c2ecf20Sopenharmony_ci val64 |= GPIO_INT_MASK_LINK_UP; 43048c2ecf20Sopenharmony_ci writeq(val64, &bar0->gpio_int_mask); 43058c2ecf20Sopenharmony_ci 43068c2ecf20Sopenharmony_ci } else if (val64 & GPIO_INT_REG_LINK_DOWN) { 43078c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_status); 43088c2ecf20Sopenharmony_ci s2io_link(sp, LINK_DOWN); 43098c2ecf20Sopenharmony_ci /* Link is down so unmaks link up interrupt */ 43108c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_int_mask); 43118c2ecf20Sopenharmony_ci val64 &= ~GPIO_INT_MASK_LINK_UP; 43128c2ecf20Sopenharmony_ci val64 |= GPIO_INT_MASK_LINK_DOWN; 43138c2ecf20Sopenharmony_ci writeq(val64, &bar0->gpio_int_mask); 43148c2ecf20Sopenharmony_ci 43158c2ecf20Sopenharmony_ci /* turn off LED */ 43168c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_control); 43178c2ecf20Sopenharmony_ci val64 = val64 & (~ADAPTER_LED_ON); 43188c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 43198c2ecf20Sopenharmony_ci } 43208c2ecf20Sopenharmony_ci } 43218c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_int_mask); 43228c2ecf20Sopenharmony_ci} 43238c2ecf20Sopenharmony_ci 43248c2ecf20Sopenharmony_ci/** 43258c2ecf20Sopenharmony_ci * do_s2io_chk_alarm_bit - Check for alarm and incrment the counter 43268c2ecf20Sopenharmony_ci * @value: alarm bits 43278c2ecf20Sopenharmony_ci * @addr: address value 43288c2ecf20Sopenharmony_ci * @cnt: counter variable 43298c2ecf20Sopenharmony_ci * Description: Check for alarm and increment the counter 43308c2ecf20Sopenharmony_ci * Return Value: 43318c2ecf20Sopenharmony_ci * 1 - if alarm bit set 43328c2ecf20Sopenharmony_ci * 0 - if alarm bit is not set 43338c2ecf20Sopenharmony_ci */ 43348c2ecf20Sopenharmony_cistatic int do_s2io_chk_alarm_bit(u64 value, void __iomem *addr, 43358c2ecf20Sopenharmony_ci unsigned long long *cnt) 43368c2ecf20Sopenharmony_ci{ 43378c2ecf20Sopenharmony_ci u64 val64; 43388c2ecf20Sopenharmony_ci val64 = readq(addr); 43398c2ecf20Sopenharmony_ci if (val64 & value) { 43408c2ecf20Sopenharmony_ci writeq(val64, addr); 43418c2ecf20Sopenharmony_ci (*cnt)++; 43428c2ecf20Sopenharmony_ci return 1; 43438c2ecf20Sopenharmony_ci } 43448c2ecf20Sopenharmony_ci return 0; 43458c2ecf20Sopenharmony_ci 43468c2ecf20Sopenharmony_ci} 43478c2ecf20Sopenharmony_ci 43488c2ecf20Sopenharmony_ci/** 43498c2ecf20Sopenharmony_ci * s2io_handle_errors - Xframe error indication handler 43508c2ecf20Sopenharmony_ci * @dev_id: opaque handle to dev 43518c2ecf20Sopenharmony_ci * Description: Handle alarms such as loss of link, single or 43528c2ecf20Sopenharmony_ci * double ECC errors, critical and serious errors. 43538c2ecf20Sopenharmony_ci * Return Value: 43548c2ecf20Sopenharmony_ci * NONE 43558c2ecf20Sopenharmony_ci */ 43568c2ecf20Sopenharmony_cistatic void s2io_handle_errors(void *dev_id) 43578c2ecf20Sopenharmony_ci{ 43588c2ecf20Sopenharmony_ci struct net_device *dev = (struct net_device *)dev_id; 43598c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 43608c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 43618c2ecf20Sopenharmony_ci u64 temp64 = 0, val64 = 0; 43628c2ecf20Sopenharmony_ci int i = 0; 43638c2ecf20Sopenharmony_ci 43648c2ecf20Sopenharmony_ci struct swStat *sw_stat = &sp->mac_control.stats_info->sw_stat; 43658c2ecf20Sopenharmony_ci struct xpakStat *stats = &sp->mac_control.stats_info->xpak_stat; 43668c2ecf20Sopenharmony_ci 43678c2ecf20Sopenharmony_ci if (!is_s2io_card_up(sp)) 43688c2ecf20Sopenharmony_ci return; 43698c2ecf20Sopenharmony_ci 43708c2ecf20Sopenharmony_ci if (pci_channel_offline(sp->pdev)) 43718c2ecf20Sopenharmony_ci return; 43728c2ecf20Sopenharmony_ci 43738c2ecf20Sopenharmony_ci memset(&sw_stat->ring_full_cnt, 0, 43748c2ecf20Sopenharmony_ci sizeof(sw_stat->ring_full_cnt)); 43758c2ecf20Sopenharmony_ci 43768c2ecf20Sopenharmony_ci /* Handling the XPAK counters update */ 43778c2ecf20Sopenharmony_ci if (stats->xpak_timer_count < 72000) { 43788c2ecf20Sopenharmony_ci /* waiting for an hour */ 43798c2ecf20Sopenharmony_ci stats->xpak_timer_count++; 43808c2ecf20Sopenharmony_ci } else { 43818c2ecf20Sopenharmony_ci s2io_updt_xpak_counter(dev); 43828c2ecf20Sopenharmony_ci /* reset the count to zero */ 43838c2ecf20Sopenharmony_ci stats->xpak_timer_count = 0; 43848c2ecf20Sopenharmony_ci } 43858c2ecf20Sopenharmony_ci 43868c2ecf20Sopenharmony_ci /* Handling link status change error Intr */ 43878c2ecf20Sopenharmony_ci if (s2io_link_fault_indication(sp) == MAC_RMAC_ERR_TIMER) { 43888c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_rmac_err_reg); 43898c2ecf20Sopenharmony_ci writeq(val64, &bar0->mac_rmac_err_reg); 43908c2ecf20Sopenharmony_ci if (val64 & RMAC_LINK_STATE_CHANGE_INT) 43918c2ecf20Sopenharmony_ci schedule_work(&sp->set_link_task); 43928c2ecf20Sopenharmony_ci } 43938c2ecf20Sopenharmony_ci 43948c2ecf20Sopenharmony_ci /* In case of a serious error, the device will be Reset. */ 43958c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(SERR_SOURCE_ANY, &bar0->serr_source, 43968c2ecf20Sopenharmony_ci &sw_stat->serious_err_cnt)) 43978c2ecf20Sopenharmony_ci goto reset; 43988c2ecf20Sopenharmony_ci 43998c2ecf20Sopenharmony_ci /* Check for data parity error */ 44008c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(GPIO_INT_REG_DP_ERR_INT, &bar0->gpio_int_reg, 44018c2ecf20Sopenharmony_ci &sw_stat->parity_err_cnt)) 44028c2ecf20Sopenharmony_ci goto reset; 44038c2ecf20Sopenharmony_ci 44048c2ecf20Sopenharmony_ci /* Check for ring full counter */ 44058c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_II_DEVICE) { 44068c2ecf20Sopenharmony_ci val64 = readq(&bar0->ring_bump_counter1); 44078c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 44088c2ecf20Sopenharmony_ci temp64 = (val64 & vBIT(0xFFFF, (i*16), 16)); 44098c2ecf20Sopenharmony_ci temp64 >>= 64 - ((i+1)*16); 44108c2ecf20Sopenharmony_ci sw_stat->ring_full_cnt[i] += temp64; 44118c2ecf20Sopenharmony_ci } 44128c2ecf20Sopenharmony_ci 44138c2ecf20Sopenharmony_ci val64 = readq(&bar0->ring_bump_counter2); 44148c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 44158c2ecf20Sopenharmony_ci temp64 = (val64 & vBIT(0xFFFF, (i*16), 16)); 44168c2ecf20Sopenharmony_ci temp64 >>= 64 - ((i+1)*16); 44178c2ecf20Sopenharmony_ci sw_stat->ring_full_cnt[i+4] += temp64; 44188c2ecf20Sopenharmony_ci } 44198c2ecf20Sopenharmony_ci } 44208c2ecf20Sopenharmony_ci 44218c2ecf20Sopenharmony_ci val64 = readq(&bar0->txdma_int_status); 44228c2ecf20Sopenharmony_ci /*check for pfc_err*/ 44238c2ecf20Sopenharmony_ci if (val64 & TXDMA_PFC_INT) { 44248c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM | 44258c2ecf20Sopenharmony_ci PFC_MISC_0_ERR | PFC_MISC_1_ERR | 44268c2ecf20Sopenharmony_ci PFC_PCIX_ERR, 44278c2ecf20Sopenharmony_ci &bar0->pfc_err_reg, 44288c2ecf20Sopenharmony_ci &sw_stat->pfc_err_cnt)) 44298c2ecf20Sopenharmony_ci goto reset; 44308c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(PFC_ECC_SG_ERR, 44318c2ecf20Sopenharmony_ci &bar0->pfc_err_reg, 44328c2ecf20Sopenharmony_ci &sw_stat->pfc_err_cnt); 44338c2ecf20Sopenharmony_ci } 44348c2ecf20Sopenharmony_ci 44358c2ecf20Sopenharmony_ci /*check for tda_err*/ 44368c2ecf20Sopenharmony_ci if (val64 & TXDMA_TDA_INT) { 44378c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(TDA_Fn_ECC_DB_ERR | 44388c2ecf20Sopenharmony_ci TDA_SM0_ERR_ALARM | 44398c2ecf20Sopenharmony_ci TDA_SM1_ERR_ALARM, 44408c2ecf20Sopenharmony_ci &bar0->tda_err_reg, 44418c2ecf20Sopenharmony_ci &sw_stat->tda_err_cnt)) 44428c2ecf20Sopenharmony_ci goto reset; 44438c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(TDA_Fn_ECC_SG_ERR | TDA_PCIX_ERR, 44448c2ecf20Sopenharmony_ci &bar0->tda_err_reg, 44458c2ecf20Sopenharmony_ci &sw_stat->tda_err_cnt); 44468c2ecf20Sopenharmony_ci } 44478c2ecf20Sopenharmony_ci /*check for pcc_err*/ 44488c2ecf20Sopenharmony_ci if (val64 & TXDMA_PCC_INT) { 44498c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM | 44508c2ecf20Sopenharmony_ci PCC_N_SERR | PCC_6_COF_OV_ERR | 44518c2ecf20Sopenharmony_ci PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR | 44528c2ecf20Sopenharmony_ci PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR | 44538c2ecf20Sopenharmony_ci PCC_TXB_ECC_DB_ERR, 44548c2ecf20Sopenharmony_ci &bar0->pcc_err_reg, 44558c2ecf20Sopenharmony_ci &sw_stat->pcc_err_cnt)) 44568c2ecf20Sopenharmony_ci goto reset; 44578c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(PCC_FB_ECC_SG_ERR | PCC_TXB_ECC_SG_ERR, 44588c2ecf20Sopenharmony_ci &bar0->pcc_err_reg, 44598c2ecf20Sopenharmony_ci &sw_stat->pcc_err_cnt); 44608c2ecf20Sopenharmony_ci } 44618c2ecf20Sopenharmony_ci 44628c2ecf20Sopenharmony_ci /*check for tti_err*/ 44638c2ecf20Sopenharmony_ci if (val64 & TXDMA_TTI_INT) { 44648c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(TTI_SM_ERR_ALARM, 44658c2ecf20Sopenharmony_ci &bar0->tti_err_reg, 44668c2ecf20Sopenharmony_ci &sw_stat->tti_err_cnt)) 44678c2ecf20Sopenharmony_ci goto reset; 44688c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(TTI_ECC_SG_ERR | TTI_ECC_DB_ERR, 44698c2ecf20Sopenharmony_ci &bar0->tti_err_reg, 44708c2ecf20Sopenharmony_ci &sw_stat->tti_err_cnt); 44718c2ecf20Sopenharmony_ci } 44728c2ecf20Sopenharmony_ci 44738c2ecf20Sopenharmony_ci /*check for lso_err*/ 44748c2ecf20Sopenharmony_ci if (val64 & TXDMA_LSO_INT) { 44758c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(LSO6_ABORT | LSO7_ABORT | 44768c2ecf20Sopenharmony_ci LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM, 44778c2ecf20Sopenharmony_ci &bar0->lso_err_reg, 44788c2ecf20Sopenharmony_ci &sw_stat->lso_err_cnt)) 44798c2ecf20Sopenharmony_ci goto reset; 44808c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(LSO6_SEND_OFLOW | LSO7_SEND_OFLOW, 44818c2ecf20Sopenharmony_ci &bar0->lso_err_reg, 44828c2ecf20Sopenharmony_ci &sw_stat->lso_err_cnt); 44838c2ecf20Sopenharmony_ci } 44848c2ecf20Sopenharmony_ci 44858c2ecf20Sopenharmony_ci /*check for tpa_err*/ 44868c2ecf20Sopenharmony_ci if (val64 & TXDMA_TPA_INT) { 44878c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(TPA_SM_ERR_ALARM, 44888c2ecf20Sopenharmony_ci &bar0->tpa_err_reg, 44898c2ecf20Sopenharmony_ci &sw_stat->tpa_err_cnt)) 44908c2ecf20Sopenharmony_ci goto reset; 44918c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(TPA_TX_FRM_DROP, 44928c2ecf20Sopenharmony_ci &bar0->tpa_err_reg, 44938c2ecf20Sopenharmony_ci &sw_stat->tpa_err_cnt); 44948c2ecf20Sopenharmony_ci } 44958c2ecf20Sopenharmony_ci 44968c2ecf20Sopenharmony_ci /*check for sm_err*/ 44978c2ecf20Sopenharmony_ci if (val64 & TXDMA_SM_INT) { 44988c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(SM_SM_ERR_ALARM, 44998c2ecf20Sopenharmony_ci &bar0->sm_err_reg, 45008c2ecf20Sopenharmony_ci &sw_stat->sm_err_cnt)) 45018c2ecf20Sopenharmony_ci goto reset; 45028c2ecf20Sopenharmony_ci } 45038c2ecf20Sopenharmony_ci 45048c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_int_status); 45058c2ecf20Sopenharmony_ci if (val64 & MAC_INT_STATUS_TMAC_INT) { 45068c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR, 45078c2ecf20Sopenharmony_ci &bar0->mac_tmac_err_reg, 45088c2ecf20Sopenharmony_ci &sw_stat->mac_tmac_err_cnt)) 45098c2ecf20Sopenharmony_ci goto reset; 45108c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR | 45118c2ecf20Sopenharmony_ci TMAC_DESC_ECC_SG_ERR | 45128c2ecf20Sopenharmony_ci TMAC_DESC_ECC_DB_ERR, 45138c2ecf20Sopenharmony_ci &bar0->mac_tmac_err_reg, 45148c2ecf20Sopenharmony_ci &sw_stat->mac_tmac_err_cnt); 45158c2ecf20Sopenharmony_ci } 45168c2ecf20Sopenharmony_ci 45178c2ecf20Sopenharmony_ci val64 = readq(&bar0->xgxs_int_status); 45188c2ecf20Sopenharmony_ci if (val64 & XGXS_INT_STATUS_TXGXS) { 45198c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR, 45208c2ecf20Sopenharmony_ci &bar0->xgxs_txgxs_err_reg, 45218c2ecf20Sopenharmony_ci &sw_stat->xgxs_txgxs_err_cnt)) 45228c2ecf20Sopenharmony_ci goto reset; 45238c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR, 45248c2ecf20Sopenharmony_ci &bar0->xgxs_txgxs_err_reg, 45258c2ecf20Sopenharmony_ci &sw_stat->xgxs_txgxs_err_cnt); 45268c2ecf20Sopenharmony_ci } 45278c2ecf20Sopenharmony_ci 45288c2ecf20Sopenharmony_ci val64 = readq(&bar0->rxdma_int_status); 45298c2ecf20Sopenharmony_ci if (val64 & RXDMA_INT_RC_INT_M) { 45308c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(RC_PRCn_ECC_DB_ERR | 45318c2ecf20Sopenharmony_ci RC_FTC_ECC_DB_ERR | 45328c2ecf20Sopenharmony_ci RC_PRCn_SM_ERR_ALARM | 45338c2ecf20Sopenharmony_ci RC_FTC_SM_ERR_ALARM, 45348c2ecf20Sopenharmony_ci &bar0->rc_err_reg, 45358c2ecf20Sopenharmony_ci &sw_stat->rc_err_cnt)) 45368c2ecf20Sopenharmony_ci goto reset; 45378c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(RC_PRCn_ECC_SG_ERR | 45388c2ecf20Sopenharmony_ci RC_FTC_ECC_SG_ERR | 45398c2ecf20Sopenharmony_ci RC_RDA_FAIL_WR_Rn, &bar0->rc_err_reg, 45408c2ecf20Sopenharmony_ci &sw_stat->rc_err_cnt); 45418c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(PRC_PCI_AB_RD_Rn | 45428c2ecf20Sopenharmony_ci PRC_PCI_AB_WR_Rn | 45438c2ecf20Sopenharmony_ci PRC_PCI_AB_F_WR_Rn, 45448c2ecf20Sopenharmony_ci &bar0->prc_pcix_err_reg, 45458c2ecf20Sopenharmony_ci &sw_stat->prc_pcix_err_cnt)) 45468c2ecf20Sopenharmony_ci goto reset; 45478c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(PRC_PCI_DP_RD_Rn | 45488c2ecf20Sopenharmony_ci PRC_PCI_DP_WR_Rn | 45498c2ecf20Sopenharmony_ci PRC_PCI_DP_F_WR_Rn, 45508c2ecf20Sopenharmony_ci &bar0->prc_pcix_err_reg, 45518c2ecf20Sopenharmony_ci &sw_stat->prc_pcix_err_cnt); 45528c2ecf20Sopenharmony_ci } 45538c2ecf20Sopenharmony_ci 45548c2ecf20Sopenharmony_ci if (val64 & RXDMA_INT_RPA_INT_M) { 45558c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR, 45568c2ecf20Sopenharmony_ci &bar0->rpa_err_reg, 45578c2ecf20Sopenharmony_ci &sw_stat->rpa_err_cnt)) 45588c2ecf20Sopenharmony_ci goto reset; 45598c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, 45608c2ecf20Sopenharmony_ci &bar0->rpa_err_reg, 45618c2ecf20Sopenharmony_ci &sw_stat->rpa_err_cnt); 45628c2ecf20Sopenharmony_ci } 45638c2ecf20Sopenharmony_ci 45648c2ecf20Sopenharmony_ci if (val64 & RXDMA_INT_RDA_INT_M) { 45658c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(RDA_RXDn_ECC_DB_ERR | 45668c2ecf20Sopenharmony_ci RDA_FRM_ECC_DB_N_AERR | 45678c2ecf20Sopenharmony_ci RDA_SM1_ERR_ALARM | 45688c2ecf20Sopenharmony_ci RDA_SM0_ERR_ALARM | 45698c2ecf20Sopenharmony_ci RDA_RXD_ECC_DB_SERR, 45708c2ecf20Sopenharmony_ci &bar0->rda_err_reg, 45718c2ecf20Sopenharmony_ci &sw_stat->rda_err_cnt)) 45728c2ecf20Sopenharmony_ci goto reset; 45738c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(RDA_RXDn_ECC_SG_ERR | 45748c2ecf20Sopenharmony_ci RDA_FRM_ECC_SG_ERR | 45758c2ecf20Sopenharmony_ci RDA_MISC_ERR | 45768c2ecf20Sopenharmony_ci RDA_PCIX_ERR, 45778c2ecf20Sopenharmony_ci &bar0->rda_err_reg, 45788c2ecf20Sopenharmony_ci &sw_stat->rda_err_cnt); 45798c2ecf20Sopenharmony_ci } 45808c2ecf20Sopenharmony_ci 45818c2ecf20Sopenharmony_ci if (val64 & RXDMA_INT_RTI_INT_M) { 45828c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(RTI_SM_ERR_ALARM, 45838c2ecf20Sopenharmony_ci &bar0->rti_err_reg, 45848c2ecf20Sopenharmony_ci &sw_stat->rti_err_cnt)) 45858c2ecf20Sopenharmony_ci goto reset; 45868c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(RTI_ECC_SG_ERR | RTI_ECC_DB_ERR, 45878c2ecf20Sopenharmony_ci &bar0->rti_err_reg, 45888c2ecf20Sopenharmony_ci &sw_stat->rti_err_cnt); 45898c2ecf20Sopenharmony_ci } 45908c2ecf20Sopenharmony_ci 45918c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_int_status); 45928c2ecf20Sopenharmony_ci if (val64 & MAC_INT_STATUS_RMAC_INT) { 45938c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR, 45948c2ecf20Sopenharmony_ci &bar0->mac_rmac_err_reg, 45958c2ecf20Sopenharmony_ci &sw_stat->mac_rmac_err_cnt)) 45968c2ecf20Sopenharmony_ci goto reset; 45978c2ecf20Sopenharmony_ci do_s2io_chk_alarm_bit(RMAC_UNUSED_INT | 45988c2ecf20Sopenharmony_ci RMAC_SINGLE_ECC_ERR | 45998c2ecf20Sopenharmony_ci RMAC_DOUBLE_ECC_ERR, 46008c2ecf20Sopenharmony_ci &bar0->mac_rmac_err_reg, 46018c2ecf20Sopenharmony_ci &sw_stat->mac_rmac_err_cnt); 46028c2ecf20Sopenharmony_ci } 46038c2ecf20Sopenharmony_ci 46048c2ecf20Sopenharmony_ci val64 = readq(&bar0->xgxs_int_status); 46058c2ecf20Sopenharmony_ci if (val64 & XGXS_INT_STATUS_RXGXS) { 46068c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, 46078c2ecf20Sopenharmony_ci &bar0->xgxs_rxgxs_err_reg, 46088c2ecf20Sopenharmony_ci &sw_stat->xgxs_rxgxs_err_cnt)) 46098c2ecf20Sopenharmony_ci goto reset; 46108c2ecf20Sopenharmony_ci } 46118c2ecf20Sopenharmony_ci 46128c2ecf20Sopenharmony_ci val64 = readq(&bar0->mc_int_status); 46138c2ecf20Sopenharmony_ci if (val64 & MC_INT_STATUS_MC_INT) { 46148c2ecf20Sopenharmony_ci if (do_s2io_chk_alarm_bit(MC_ERR_REG_SM_ERR, 46158c2ecf20Sopenharmony_ci &bar0->mc_err_reg, 46168c2ecf20Sopenharmony_ci &sw_stat->mc_err_cnt)) 46178c2ecf20Sopenharmony_ci goto reset; 46188c2ecf20Sopenharmony_ci 46198c2ecf20Sopenharmony_ci /* Handling Ecc errors */ 46208c2ecf20Sopenharmony_ci if (val64 & (MC_ERR_REG_ECC_ALL_SNG | MC_ERR_REG_ECC_ALL_DBL)) { 46218c2ecf20Sopenharmony_ci writeq(val64, &bar0->mc_err_reg); 46228c2ecf20Sopenharmony_ci if (val64 & MC_ERR_REG_ECC_ALL_DBL) { 46238c2ecf20Sopenharmony_ci sw_stat->double_ecc_errs++; 46248c2ecf20Sopenharmony_ci if (sp->device_type != XFRAME_II_DEVICE) { 46258c2ecf20Sopenharmony_ci /* 46268c2ecf20Sopenharmony_ci * Reset XframeI only if critical error 46278c2ecf20Sopenharmony_ci */ 46288c2ecf20Sopenharmony_ci if (val64 & 46298c2ecf20Sopenharmony_ci (MC_ERR_REG_MIRI_ECC_DB_ERR_0 | 46308c2ecf20Sopenharmony_ci MC_ERR_REG_MIRI_ECC_DB_ERR_1)) 46318c2ecf20Sopenharmony_ci goto reset; 46328c2ecf20Sopenharmony_ci } 46338c2ecf20Sopenharmony_ci } else 46348c2ecf20Sopenharmony_ci sw_stat->single_ecc_errs++; 46358c2ecf20Sopenharmony_ci } 46368c2ecf20Sopenharmony_ci } 46378c2ecf20Sopenharmony_ci return; 46388c2ecf20Sopenharmony_ci 46398c2ecf20Sopenharmony_cireset: 46408c2ecf20Sopenharmony_ci s2io_stop_all_tx_queue(sp); 46418c2ecf20Sopenharmony_ci schedule_work(&sp->rst_timer_task); 46428c2ecf20Sopenharmony_ci sw_stat->soft_reset_cnt++; 46438c2ecf20Sopenharmony_ci} 46448c2ecf20Sopenharmony_ci 46458c2ecf20Sopenharmony_ci/** 46468c2ecf20Sopenharmony_ci * s2io_isr - ISR handler of the device . 46478c2ecf20Sopenharmony_ci * @irq: the irq of the device. 46488c2ecf20Sopenharmony_ci * @dev_id: a void pointer to the dev structure of the NIC. 46498c2ecf20Sopenharmony_ci * Description: This function is the ISR handler of the device. It 46508c2ecf20Sopenharmony_ci * identifies the reason for the interrupt and calls the relevant 46518c2ecf20Sopenharmony_ci * service routines. As a contongency measure, this ISR allocates the 46528c2ecf20Sopenharmony_ci * recv buffers, if their numbers are below the panic value which is 46538c2ecf20Sopenharmony_ci * presently set to 25% of the original number of rcv buffers allocated. 46548c2ecf20Sopenharmony_ci * Return value: 46558c2ecf20Sopenharmony_ci * IRQ_HANDLED: will be returned if IRQ was handled by this routine 46568c2ecf20Sopenharmony_ci * IRQ_NONE: will be returned if interrupt is not from our device 46578c2ecf20Sopenharmony_ci */ 46588c2ecf20Sopenharmony_cistatic irqreturn_t s2io_isr(int irq, void *dev_id) 46598c2ecf20Sopenharmony_ci{ 46608c2ecf20Sopenharmony_ci struct net_device *dev = (struct net_device *)dev_id; 46618c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 46628c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 46638c2ecf20Sopenharmony_ci int i; 46648c2ecf20Sopenharmony_ci u64 reason = 0; 46658c2ecf20Sopenharmony_ci struct mac_info *mac_control; 46668c2ecf20Sopenharmony_ci struct config_param *config; 46678c2ecf20Sopenharmony_ci 46688c2ecf20Sopenharmony_ci /* Pretend we handled any irq's from a disconnected card */ 46698c2ecf20Sopenharmony_ci if (pci_channel_offline(sp->pdev)) 46708c2ecf20Sopenharmony_ci return IRQ_NONE; 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_ci if (!is_s2io_card_up(sp)) 46738c2ecf20Sopenharmony_ci return IRQ_NONE; 46748c2ecf20Sopenharmony_ci 46758c2ecf20Sopenharmony_ci config = &sp->config; 46768c2ecf20Sopenharmony_ci mac_control = &sp->mac_control; 46778c2ecf20Sopenharmony_ci 46788c2ecf20Sopenharmony_ci /* 46798c2ecf20Sopenharmony_ci * Identify the cause for interrupt and call the appropriate 46808c2ecf20Sopenharmony_ci * interrupt handler. Causes for the interrupt could be; 46818c2ecf20Sopenharmony_ci * 1. Rx of packet. 46828c2ecf20Sopenharmony_ci * 2. Tx complete. 46838c2ecf20Sopenharmony_ci * 3. Link down. 46848c2ecf20Sopenharmony_ci */ 46858c2ecf20Sopenharmony_ci reason = readq(&bar0->general_int_status); 46868c2ecf20Sopenharmony_ci 46878c2ecf20Sopenharmony_ci if (unlikely(reason == S2IO_MINUS_ONE)) 46888c2ecf20Sopenharmony_ci return IRQ_HANDLED; /* Nothing much can be done. Get out */ 46898c2ecf20Sopenharmony_ci 46908c2ecf20Sopenharmony_ci if (reason & 46918c2ecf20Sopenharmony_ci (GEN_INTR_RXTRAFFIC | GEN_INTR_TXTRAFFIC | GEN_INTR_TXPIC)) { 46928c2ecf20Sopenharmony_ci writeq(S2IO_MINUS_ONE, &bar0->general_int_mask); 46938c2ecf20Sopenharmony_ci 46948c2ecf20Sopenharmony_ci if (config->napi) { 46958c2ecf20Sopenharmony_ci if (reason & GEN_INTR_RXTRAFFIC) { 46968c2ecf20Sopenharmony_ci napi_schedule(&sp->napi); 46978c2ecf20Sopenharmony_ci writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask); 46988c2ecf20Sopenharmony_ci writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); 46998c2ecf20Sopenharmony_ci readl(&bar0->rx_traffic_int); 47008c2ecf20Sopenharmony_ci } 47018c2ecf20Sopenharmony_ci } else { 47028c2ecf20Sopenharmony_ci /* 47038c2ecf20Sopenharmony_ci * rx_traffic_int reg is an R1 register, writing all 1's 47048c2ecf20Sopenharmony_ci * will ensure that the actual interrupt causing bit 47058c2ecf20Sopenharmony_ci * get's cleared and hence a read can be avoided. 47068c2ecf20Sopenharmony_ci */ 47078c2ecf20Sopenharmony_ci if (reason & GEN_INTR_RXTRAFFIC) 47088c2ecf20Sopenharmony_ci writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); 47098c2ecf20Sopenharmony_ci 47108c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 47118c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 47128c2ecf20Sopenharmony_ci 47138c2ecf20Sopenharmony_ci rx_intr_handler(ring, 0); 47148c2ecf20Sopenharmony_ci } 47158c2ecf20Sopenharmony_ci } 47168c2ecf20Sopenharmony_ci 47178c2ecf20Sopenharmony_ci /* 47188c2ecf20Sopenharmony_ci * tx_traffic_int reg is an R1 register, writing all 1's 47198c2ecf20Sopenharmony_ci * will ensure that the actual interrupt causing bit get's 47208c2ecf20Sopenharmony_ci * cleared and hence a read can be avoided. 47218c2ecf20Sopenharmony_ci */ 47228c2ecf20Sopenharmony_ci if (reason & GEN_INTR_TXTRAFFIC) 47238c2ecf20Sopenharmony_ci writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int); 47248c2ecf20Sopenharmony_ci 47258c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) 47268c2ecf20Sopenharmony_ci tx_intr_handler(&mac_control->fifos[i]); 47278c2ecf20Sopenharmony_ci 47288c2ecf20Sopenharmony_ci if (reason & GEN_INTR_TXPIC) 47298c2ecf20Sopenharmony_ci s2io_txpic_intr_handle(sp); 47308c2ecf20Sopenharmony_ci 47318c2ecf20Sopenharmony_ci /* 47328c2ecf20Sopenharmony_ci * Reallocate the buffers from the interrupt handler itself. 47338c2ecf20Sopenharmony_ci */ 47348c2ecf20Sopenharmony_ci if (!config->napi) { 47358c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 47368c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 47378c2ecf20Sopenharmony_ci 47388c2ecf20Sopenharmony_ci s2io_chk_rx_buffers(sp, ring); 47398c2ecf20Sopenharmony_ci } 47408c2ecf20Sopenharmony_ci } 47418c2ecf20Sopenharmony_ci writeq(sp->general_int_mask, &bar0->general_int_mask); 47428c2ecf20Sopenharmony_ci readl(&bar0->general_int_status); 47438c2ecf20Sopenharmony_ci 47448c2ecf20Sopenharmony_ci return IRQ_HANDLED; 47458c2ecf20Sopenharmony_ci 47468c2ecf20Sopenharmony_ci } else if (!reason) { 47478c2ecf20Sopenharmony_ci /* The interrupt was not raised by us */ 47488c2ecf20Sopenharmony_ci return IRQ_NONE; 47498c2ecf20Sopenharmony_ci } 47508c2ecf20Sopenharmony_ci 47518c2ecf20Sopenharmony_ci return IRQ_HANDLED; 47528c2ecf20Sopenharmony_ci} 47538c2ecf20Sopenharmony_ci 47548c2ecf20Sopenharmony_ci/* 47558c2ecf20Sopenharmony_ci * s2io_updt_stats - 47568c2ecf20Sopenharmony_ci */ 47578c2ecf20Sopenharmony_cistatic void s2io_updt_stats(struct s2io_nic *sp) 47588c2ecf20Sopenharmony_ci{ 47598c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 47608c2ecf20Sopenharmony_ci u64 val64; 47618c2ecf20Sopenharmony_ci int cnt = 0; 47628c2ecf20Sopenharmony_ci 47638c2ecf20Sopenharmony_ci if (is_s2io_card_up(sp)) { 47648c2ecf20Sopenharmony_ci /* Apprx 30us on a 133 MHz bus */ 47658c2ecf20Sopenharmony_ci val64 = SET_UPDT_CLICKS(10) | 47668c2ecf20Sopenharmony_ci STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN; 47678c2ecf20Sopenharmony_ci writeq(val64, &bar0->stat_cfg); 47688c2ecf20Sopenharmony_ci do { 47698c2ecf20Sopenharmony_ci udelay(100); 47708c2ecf20Sopenharmony_ci val64 = readq(&bar0->stat_cfg); 47718c2ecf20Sopenharmony_ci if (!(val64 & s2BIT(0))) 47728c2ecf20Sopenharmony_ci break; 47738c2ecf20Sopenharmony_ci cnt++; 47748c2ecf20Sopenharmony_ci if (cnt == 5) 47758c2ecf20Sopenharmony_ci break; /* Updt failed */ 47768c2ecf20Sopenharmony_ci } while (1); 47778c2ecf20Sopenharmony_ci } 47788c2ecf20Sopenharmony_ci} 47798c2ecf20Sopenharmony_ci 47808c2ecf20Sopenharmony_ci/** 47818c2ecf20Sopenharmony_ci * s2io_get_stats - Updates the device statistics structure. 47828c2ecf20Sopenharmony_ci * @dev : pointer to the device structure. 47838c2ecf20Sopenharmony_ci * Description: 47848c2ecf20Sopenharmony_ci * This function updates the device statistics structure in the s2io_nic 47858c2ecf20Sopenharmony_ci * structure and returns a pointer to the same. 47868c2ecf20Sopenharmony_ci * Return value: 47878c2ecf20Sopenharmony_ci * pointer to the updated net_device_stats structure. 47888c2ecf20Sopenharmony_ci */ 47898c2ecf20Sopenharmony_cistatic struct net_device_stats *s2io_get_stats(struct net_device *dev) 47908c2ecf20Sopenharmony_ci{ 47918c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 47928c2ecf20Sopenharmony_ci struct mac_info *mac_control = &sp->mac_control; 47938c2ecf20Sopenharmony_ci struct stat_block *stats = mac_control->stats_info; 47948c2ecf20Sopenharmony_ci u64 delta; 47958c2ecf20Sopenharmony_ci 47968c2ecf20Sopenharmony_ci /* Configure Stats for immediate updt */ 47978c2ecf20Sopenharmony_ci s2io_updt_stats(sp); 47988c2ecf20Sopenharmony_ci 47998c2ecf20Sopenharmony_ci /* A device reset will cause the on-adapter statistics to be zero'ed. 48008c2ecf20Sopenharmony_ci * This can be done while running by changing the MTU. To prevent the 48018c2ecf20Sopenharmony_ci * system from having the stats zero'ed, the driver keeps a copy of the 48028c2ecf20Sopenharmony_ci * last update to the system (which is also zero'ed on reset). This 48038c2ecf20Sopenharmony_ci * enables the driver to accurately know the delta between the last 48048c2ecf20Sopenharmony_ci * update and the current update. 48058c2ecf20Sopenharmony_ci */ 48068c2ecf20Sopenharmony_ci delta = ((u64) le32_to_cpu(stats->rmac_vld_frms_oflow) << 32 | 48078c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_vld_frms)) - sp->stats.rx_packets; 48088c2ecf20Sopenharmony_ci sp->stats.rx_packets += delta; 48098c2ecf20Sopenharmony_ci dev->stats.rx_packets += delta; 48108c2ecf20Sopenharmony_ci 48118c2ecf20Sopenharmony_ci delta = ((u64) le32_to_cpu(stats->tmac_frms_oflow) << 32 | 48128c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_frms)) - sp->stats.tx_packets; 48138c2ecf20Sopenharmony_ci sp->stats.tx_packets += delta; 48148c2ecf20Sopenharmony_ci dev->stats.tx_packets += delta; 48158c2ecf20Sopenharmony_ci 48168c2ecf20Sopenharmony_ci delta = ((u64) le32_to_cpu(stats->rmac_data_octets_oflow) << 32 | 48178c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_data_octets)) - sp->stats.rx_bytes; 48188c2ecf20Sopenharmony_ci sp->stats.rx_bytes += delta; 48198c2ecf20Sopenharmony_ci dev->stats.rx_bytes += delta; 48208c2ecf20Sopenharmony_ci 48218c2ecf20Sopenharmony_ci delta = ((u64) le32_to_cpu(stats->tmac_data_octets_oflow) << 32 | 48228c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_data_octets)) - sp->stats.tx_bytes; 48238c2ecf20Sopenharmony_ci sp->stats.tx_bytes += delta; 48248c2ecf20Sopenharmony_ci dev->stats.tx_bytes += delta; 48258c2ecf20Sopenharmony_ci 48268c2ecf20Sopenharmony_ci delta = le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_errors; 48278c2ecf20Sopenharmony_ci sp->stats.rx_errors += delta; 48288c2ecf20Sopenharmony_ci dev->stats.rx_errors += delta; 48298c2ecf20Sopenharmony_ci 48308c2ecf20Sopenharmony_ci delta = ((u64) le32_to_cpu(stats->tmac_any_err_frms_oflow) << 32 | 48318c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_any_err_frms)) - sp->stats.tx_errors; 48328c2ecf20Sopenharmony_ci sp->stats.tx_errors += delta; 48338c2ecf20Sopenharmony_ci dev->stats.tx_errors += delta; 48348c2ecf20Sopenharmony_ci 48358c2ecf20Sopenharmony_ci delta = le64_to_cpu(stats->rmac_drop_frms) - sp->stats.rx_dropped; 48368c2ecf20Sopenharmony_ci sp->stats.rx_dropped += delta; 48378c2ecf20Sopenharmony_ci dev->stats.rx_dropped += delta; 48388c2ecf20Sopenharmony_ci 48398c2ecf20Sopenharmony_ci delta = le64_to_cpu(stats->tmac_drop_frms) - sp->stats.tx_dropped; 48408c2ecf20Sopenharmony_ci sp->stats.tx_dropped += delta; 48418c2ecf20Sopenharmony_ci dev->stats.tx_dropped += delta; 48428c2ecf20Sopenharmony_ci 48438c2ecf20Sopenharmony_ci /* The adapter MAC interprets pause frames as multicast packets, but 48448c2ecf20Sopenharmony_ci * does not pass them up. This erroneously increases the multicast 48458c2ecf20Sopenharmony_ci * packet count and needs to be deducted when the multicast frame count 48468c2ecf20Sopenharmony_ci * is queried. 48478c2ecf20Sopenharmony_ci */ 48488c2ecf20Sopenharmony_ci delta = (u64) le32_to_cpu(stats->rmac_vld_mcst_frms_oflow) << 32 | 48498c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_vld_mcst_frms); 48508c2ecf20Sopenharmony_ci delta -= le64_to_cpu(stats->rmac_pause_ctrl_frms); 48518c2ecf20Sopenharmony_ci delta -= sp->stats.multicast; 48528c2ecf20Sopenharmony_ci sp->stats.multicast += delta; 48538c2ecf20Sopenharmony_ci dev->stats.multicast += delta; 48548c2ecf20Sopenharmony_ci 48558c2ecf20Sopenharmony_ci delta = ((u64) le32_to_cpu(stats->rmac_usized_frms_oflow) << 32 | 48568c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_usized_frms)) + 48578c2ecf20Sopenharmony_ci le64_to_cpu(stats->rmac_long_frms) - sp->stats.rx_length_errors; 48588c2ecf20Sopenharmony_ci sp->stats.rx_length_errors += delta; 48598c2ecf20Sopenharmony_ci dev->stats.rx_length_errors += delta; 48608c2ecf20Sopenharmony_ci 48618c2ecf20Sopenharmony_ci delta = le64_to_cpu(stats->rmac_fcs_err_frms) - sp->stats.rx_crc_errors; 48628c2ecf20Sopenharmony_ci sp->stats.rx_crc_errors += delta; 48638c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors += delta; 48648c2ecf20Sopenharmony_ci 48658c2ecf20Sopenharmony_ci return &dev->stats; 48668c2ecf20Sopenharmony_ci} 48678c2ecf20Sopenharmony_ci 48688c2ecf20Sopenharmony_ci/** 48698c2ecf20Sopenharmony_ci * s2io_set_multicast - entry point for multicast address enable/disable. 48708c2ecf20Sopenharmony_ci * @dev : pointer to the device structure 48718c2ecf20Sopenharmony_ci * Description: 48728c2ecf20Sopenharmony_ci * This function is a driver entry point which gets called by the kernel 48738c2ecf20Sopenharmony_ci * whenever multicast addresses must be enabled/disabled. This also gets 48748c2ecf20Sopenharmony_ci * called to set/reset promiscuous mode. Depending on the deivce flag, we 48758c2ecf20Sopenharmony_ci * determine, if multicast address must be enabled or if promiscuous mode 48768c2ecf20Sopenharmony_ci * is to be disabled etc. 48778c2ecf20Sopenharmony_ci * Return value: 48788c2ecf20Sopenharmony_ci * void. 48798c2ecf20Sopenharmony_ci */ 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_cistatic void s2io_set_multicast(struct net_device *dev) 48828c2ecf20Sopenharmony_ci{ 48838c2ecf20Sopenharmony_ci int i, j, prev_cnt; 48848c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 48858c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 48868c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 48878c2ecf20Sopenharmony_ci u64 val64 = 0, multi_mac = 0x010203040506ULL, mask = 48888c2ecf20Sopenharmony_ci 0xfeffffffffffULL; 48898c2ecf20Sopenharmony_ci u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, mac_addr = 0; 48908c2ecf20Sopenharmony_ci void __iomem *add; 48918c2ecf20Sopenharmony_ci struct config_param *config = &sp->config; 48928c2ecf20Sopenharmony_ci 48938c2ecf20Sopenharmony_ci if ((dev->flags & IFF_ALLMULTI) && (!sp->m_cast_flg)) { 48948c2ecf20Sopenharmony_ci /* Enable all Multicast addresses */ 48958c2ecf20Sopenharmony_ci writeq(RMAC_ADDR_DATA0_MEM_ADDR(multi_mac), 48968c2ecf20Sopenharmony_ci &bar0->rmac_addr_data0_mem); 48978c2ecf20Sopenharmony_ci writeq(RMAC_ADDR_DATA1_MEM_MASK(mask), 48988c2ecf20Sopenharmony_ci &bar0->rmac_addr_data1_mem); 48998c2ecf20Sopenharmony_ci val64 = RMAC_ADDR_CMD_MEM_WE | 49008c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | 49018c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_OFFSET(config->max_mc_addr - 1); 49028c2ecf20Sopenharmony_ci writeq(val64, &bar0->rmac_addr_cmd_mem); 49038c2ecf20Sopenharmony_ci /* Wait till command completes */ 49048c2ecf20Sopenharmony_ci wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, 49058c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, 49068c2ecf20Sopenharmony_ci S2IO_BIT_RESET); 49078c2ecf20Sopenharmony_ci 49088c2ecf20Sopenharmony_ci sp->m_cast_flg = 1; 49098c2ecf20Sopenharmony_ci sp->all_multi_pos = config->max_mc_addr - 1; 49108c2ecf20Sopenharmony_ci } else if ((dev->flags & IFF_ALLMULTI) && (sp->m_cast_flg)) { 49118c2ecf20Sopenharmony_ci /* Disable all Multicast addresses */ 49128c2ecf20Sopenharmony_ci writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr), 49138c2ecf20Sopenharmony_ci &bar0->rmac_addr_data0_mem); 49148c2ecf20Sopenharmony_ci writeq(RMAC_ADDR_DATA1_MEM_MASK(0x0), 49158c2ecf20Sopenharmony_ci &bar0->rmac_addr_data1_mem); 49168c2ecf20Sopenharmony_ci val64 = RMAC_ADDR_CMD_MEM_WE | 49178c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | 49188c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_OFFSET(sp->all_multi_pos); 49198c2ecf20Sopenharmony_ci writeq(val64, &bar0->rmac_addr_cmd_mem); 49208c2ecf20Sopenharmony_ci /* Wait till command completes */ 49218c2ecf20Sopenharmony_ci wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, 49228c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, 49238c2ecf20Sopenharmony_ci S2IO_BIT_RESET); 49248c2ecf20Sopenharmony_ci 49258c2ecf20Sopenharmony_ci sp->m_cast_flg = 0; 49268c2ecf20Sopenharmony_ci sp->all_multi_pos = 0; 49278c2ecf20Sopenharmony_ci } 49288c2ecf20Sopenharmony_ci 49298c2ecf20Sopenharmony_ci if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) { 49308c2ecf20Sopenharmony_ci /* Put the NIC into promiscuous mode */ 49318c2ecf20Sopenharmony_ci add = &bar0->mac_cfg; 49328c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_cfg); 49338c2ecf20Sopenharmony_ci val64 |= MAC_CFG_RMAC_PROM_ENABLE; 49348c2ecf20Sopenharmony_ci 49358c2ecf20Sopenharmony_ci writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); 49368c2ecf20Sopenharmony_ci writel((u32)val64, add); 49378c2ecf20Sopenharmony_ci writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); 49388c2ecf20Sopenharmony_ci writel((u32) (val64 >> 32), (add + 4)); 49398c2ecf20Sopenharmony_ci 49408c2ecf20Sopenharmony_ci if (vlan_tag_strip != 1) { 49418c2ecf20Sopenharmony_ci val64 = readq(&bar0->rx_pa_cfg); 49428c2ecf20Sopenharmony_ci val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG; 49438c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_pa_cfg); 49448c2ecf20Sopenharmony_ci sp->vlan_strip_flag = 0; 49458c2ecf20Sopenharmony_ci } 49468c2ecf20Sopenharmony_ci 49478c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_cfg); 49488c2ecf20Sopenharmony_ci sp->promisc_flg = 1; 49498c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: entered promiscuous mode\n", 49508c2ecf20Sopenharmony_ci dev->name); 49518c2ecf20Sopenharmony_ci } else if (!(dev->flags & IFF_PROMISC) && (sp->promisc_flg)) { 49528c2ecf20Sopenharmony_ci /* Remove the NIC from promiscuous mode */ 49538c2ecf20Sopenharmony_ci add = &bar0->mac_cfg; 49548c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_cfg); 49558c2ecf20Sopenharmony_ci val64 &= ~MAC_CFG_RMAC_PROM_ENABLE; 49568c2ecf20Sopenharmony_ci 49578c2ecf20Sopenharmony_ci writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); 49588c2ecf20Sopenharmony_ci writel((u32)val64, add); 49598c2ecf20Sopenharmony_ci writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); 49608c2ecf20Sopenharmony_ci writel((u32) (val64 >> 32), (add + 4)); 49618c2ecf20Sopenharmony_ci 49628c2ecf20Sopenharmony_ci if (vlan_tag_strip != 0) { 49638c2ecf20Sopenharmony_ci val64 = readq(&bar0->rx_pa_cfg); 49648c2ecf20Sopenharmony_ci val64 |= RX_PA_CFG_STRIP_VLAN_TAG; 49658c2ecf20Sopenharmony_ci writeq(val64, &bar0->rx_pa_cfg); 49668c2ecf20Sopenharmony_ci sp->vlan_strip_flag = 1; 49678c2ecf20Sopenharmony_ci } 49688c2ecf20Sopenharmony_ci 49698c2ecf20Sopenharmony_ci val64 = readq(&bar0->mac_cfg); 49708c2ecf20Sopenharmony_ci sp->promisc_flg = 0; 49718c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: left promiscuous mode\n", dev->name); 49728c2ecf20Sopenharmony_ci } 49738c2ecf20Sopenharmony_ci 49748c2ecf20Sopenharmony_ci /* Update individual M_CAST address list */ 49758c2ecf20Sopenharmony_ci if ((!sp->m_cast_flg) && netdev_mc_count(dev)) { 49768c2ecf20Sopenharmony_ci if (netdev_mc_count(dev) > 49778c2ecf20Sopenharmony_ci (config->max_mc_addr - config->max_mac_addr)) { 49788c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 49798c2ecf20Sopenharmony_ci "%s: No more Rx filters can be added - " 49808c2ecf20Sopenharmony_ci "please enable ALL_MULTI instead\n", 49818c2ecf20Sopenharmony_ci dev->name); 49828c2ecf20Sopenharmony_ci return; 49838c2ecf20Sopenharmony_ci } 49848c2ecf20Sopenharmony_ci 49858c2ecf20Sopenharmony_ci prev_cnt = sp->mc_addr_count; 49868c2ecf20Sopenharmony_ci sp->mc_addr_count = netdev_mc_count(dev); 49878c2ecf20Sopenharmony_ci 49888c2ecf20Sopenharmony_ci /* Clear out the previous list of Mc in the H/W. */ 49898c2ecf20Sopenharmony_ci for (i = 0; i < prev_cnt; i++) { 49908c2ecf20Sopenharmony_ci writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr), 49918c2ecf20Sopenharmony_ci &bar0->rmac_addr_data0_mem); 49928c2ecf20Sopenharmony_ci writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL), 49938c2ecf20Sopenharmony_ci &bar0->rmac_addr_data1_mem); 49948c2ecf20Sopenharmony_ci val64 = RMAC_ADDR_CMD_MEM_WE | 49958c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | 49968c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_OFFSET 49978c2ecf20Sopenharmony_ci (config->mc_start_offset + i); 49988c2ecf20Sopenharmony_ci writeq(val64, &bar0->rmac_addr_cmd_mem); 49998c2ecf20Sopenharmony_ci 50008c2ecf20Sopenharmony_ci /* Wait for command completes */ 50018c2ecf20Sopenharmony_ci if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, 50028c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, 50038c2ecf20Sopenharmony_ci S2IO_BIT_RESET)) { 50048c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 50058c2ecf20Sopenharmony_ci "%s: Adding Multicasts failed\n", 50068c2ecf20Sopenharmony_ci dev->name); 50078c2ecf20Sopenharmony_ci return; 50088c2ecf20Sopenharmony_ci } 50098c2ecf20Sopenharmony_ci } 50108c2ecf20Sopenharmony_ci 50118c2ecf20Sopenharmony_ci /* Create the new Rx filter list and update the same in H/W. */ 50128c2ecf20Sopenharmony_ci i = 0; 50138c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 50148c2ecf20Sopenharmony_ci mac_addr = 0; 50158c2ecf20Sopenharmony_ci for (j = 0; j < ETH_ALEN; j++) { 50168c2ecf20Sopenharmony_ci mac_addr |= ha->addr[j]; 50178c2ecf20Sopenharmony_ci mac_addr <<= 8; 50188c2ecf20Sopenharmony_ci } 50198c2ecf20Sopenharmony_ci mac_addr >>= 8; 50208c2ecf20Sopenharmony_ci writeq(RMAC_ADDR_DATA0_MEM_ADDR(mac_addr), 50218c2ecf20Sopenharmony_ci &bar0->rmac_addr_data0_mem); 50228c2ecf20Sopenharmony_ci writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL), 50238c2ecf20Sopenharmony_ci &bar0->rmac_addr_data1_mem); 50248c2ecf20Sopenharmony_ci val64 = RMAC_ADDR_CMD_MEM_WE | 50258c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | 50268c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_OFFSET 50278c2ecf20Sopenharmony_ci (i + config->mc_start_offset); 50288c2ecf20Sopenharmony_ci writeq(val64, &bar0->rmac_addr_cmd_mem); 50298c2ecf20Sopenharmony_ci 50308c2ecf20Sopenharmony_ci /* Wait for command completes */ 50318c2ecf20Sopenharmony_ci if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, 50328c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, 50338c2ecf20Sopenharmony_ci S2IO_BIT_RESET)) { 50348c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 50358c2ecf20Sopenharmony_ci "%s: Adding Multicasts failed\n", 50368c2ecf20Sopenharmony_ci dev->name); 50378c2ecf20Sopenharmony_ci return; 50388c2ecf20Sopenharmony_ci } 50398c2ecf20Sopenharmony_ci i++; 50408c2ecf20Sopenharmony_ci } 50418c2ecf20Sopenharmony_ci } 50428c2ecf20Sopenharmony_ci} 50438c2ecf20Sopenharmony_ci 50448c2ecf20Sopenharmony_ci/* read from CAM unicast & multicast addresses and store it in 50458c2ecf20Sopenharmony_ci * def_mac_addr structure 50468c2ecf20Sopenharmony_ci */ 50478c2ecf20Sopenharmony_cistatic void do_s2io_store_unicast_mc(struct s2io_nic *sp) 50488c2ecf20Sopenharmony_ci{ 50498c2ecf20Sopenharmony_ci int offset; 50508c2ecf20Sopenharmony_ci u64 mac_addr = 0x0; 50518c2ecf20Sopenharmony_ci struct config_param *config = &sp->config; 50528c2ecf20Sopenharmony_ci 50538c2ecf20Sopenharmony_ci /* store unicast & multicast mac addresses */ 50548c2ecf20Sopenharmony_ci for (offset = 0; offset < config->max_mc_addr; offset++) { 50558c2ecf20Sopenharmony_ci mac_addr = do_s2io_read_unicast_mc(sp, offset); 50568c2ecf20Sopenharmony_ci /* if read fails disable the entry */ 50578c2ecf20Sopenharmony_ci if (mac_addr == FAILURE) 50588c2ecf20Sopenharmony_ci mac_addr = S2IO_DISABLE_MAC_ENTRY; 50598c2ecf20Sopenharmony_ci do_s2io_copy_mac_addr(sp, offset, mac_addr); 50608c2ecf20Sopenharmony_ci } 50618c2ecf20Sopenharmony_ci} 50628c2ecf20Sopenharmony_ci 50638c2ecf20Sopenharmony_ci/* restore unicast & multicast MAC to CAM from def_mac_addr structure */ 50648c2ecf20Sopenharmony_cistatic void do_s2io_restore_unicast_mc(struct s2io_nic *sp) 50658c2ecf20Sopenharmony_ci{ 50668c2ecf20Sopenharmony_ci int offset; 50678c2ecf20Sopenharmony_ci struct config_param *config = &sp->config; 50688c2ecf20Sopenharmony_ci /* restore unicast mac address */ 50698c2ecf20Sopenharmony_ci for (offset = 0; offset < config->max_mac_addr; offset++) 50708c2ecf20Sopenharmony_ci do_s2io_prog_unicast(sp->dev, 50718c2ecf20Sopenharmony_ci sp->def_mac_addr[offset].mac_addr); 50728c2ecf20Sopenharmony_ci 50738c2ecf20Sopenharmony_ci /* restore multicast mac address */ 50748c2ecf20Sopenharmony_ci for (offset = config->mc_start_offset; 50758c2ecf20Sopenharmony_ci offset < config->max_mc_addr; offset++) 50768c2ecf20Sopenharmony_ci do_s2io_add_mc(sp, sp->def_mac_addr[offset].mac_addr); 50778c2ecf20Sopenharmony_ci} 50788c2ecf20Sopenharmony_ci 50798c2ecf20Sopenharmony_ci/* add a multicast MAC address to CAM */ 50808c2ecf20Sopenharmony_cistatic int do_s2io_add_mc(struct s2io_nic *sp, u8 *addr) 50818c2ecf20Sopenharmony_ci{ 50828c2ecf20Sopenharmony_ci int i; 50838c2ecf20Sopenharmony_ci u64 mac_addr = 0; 50848c2ecf20Sopenharmony_ci struct config_param *config = &sp->config; 50858c2ecf20Sopenharmony_ci 50868c2ecf20Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) { 50878c2ecf20Sopenharmony_ci mac_addr <<= 8; 50888c2ecf20Sopenharmony_ci mac_addr |= addr[i]; 50898c2ecf20Sopenharmony_ci } 50908c2ecf20Sopenharmony_ci if ((0ULL == mac_addr) || (mac_addr == S2IO_DISABLE_MAC_ENTRY)) 50918c2ecf20Sopenharmony_ci return SUCCESS; 50928c2ecf20Sopenharmony_ci 50938c2ecf20Sopenharmony_ci /* check if the multicast mac already preset in CAM */ 50948c2ecf20Sopenharmony_ci for (i = config->mc_start_offset; i < config->max_mc_addr; i++) { 50958c2ecf20Sopenharmony_ci u64 tmp64; 50968c2ecf20Sopenharmony_ci tmp64 = do_s2io_read_unicast_mc(sp, i); 50978c2ecf20Sopenharmony_ci if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */ 50988c2ecf20Sopenharmony_ci break; 50998c2ecf20Sopenharmony_ci 51008c2ecf20Sopenharmony_ci if (tmp64 == mac_addr) 51018c2ecf20Sopenharmony_ci return SUCCESS; 51028c2ecf20Sopenharmony_ci } 51038c2ecf20Sopenharmony_ci if (i == config->max_mc_addr) { 51048c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 51058c2ecf20Sopenharmony_ci "CAM full no space left for multicast MAC\n"); 51068c2ecf20Sopenharmony_ci return FAILURE; 51078c2ecf20Sopenharmony_ci } 51088c2ecf20Sopenharmony_ci /* Update the internal structure with this new mac address */ 51098c2ecf20Sopenharmony_ci do_s2io_copy_mac_addr(sp, i, mac_addr); 51108c2ecf20Sopenharmony_ci 51118c2ecf20Sopenharmony_ci return do_s2io_add_mac(sp, mac_addr, i); 51128c2ecf20Sopenharmony_ci} 51138c2ecf20Sopenharmony_ci 51148c2ecf20Sopenharmony_ci/* add MAC address to CAM */ 51158c2ecf20Sopenharmony_cistatic int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int off) 51168c2ecf20Sopenharmony_ci{ 51178c2ecf20Sopenharmony_ci u64 val64; 51188c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 51198c2ecf20Sopenharmony_ci 51208c2ecf20Sopenharmony_ci writeq(RMAC_ADDR_DATA0_MEM_ADDR(addr), 51218c2ecf20Sopenharmony_ci &bar0->rmac_addr_data0_mem); 51228c2ecf20Sopenharmony_ci 51238c2ecf20Sopenharmony_ci val64 = RMAC_ADDR_CMD_MEM_WE | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | 51248c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_OFFSET(off); 51258c2ecf20Sopenharmony_ci writeq(val64, &bar0->rmac_addr_cmd_mem); 51268c2ecf20Sopenharmony_ci 51278c2ecf20Sopenharmony_ci /* Wait till command completes */ 51288c2ecf20Sopenharmony_ci if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, 51298c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, 51308c2ecf20Sopenharmony_ci S2IO_BIT_RESET)) { 51318c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "do_s2io_add_mac failed\n"); 51328c2ecf20Sopenharmony_ci return FAILURE; 51338c2ecf20Sopenharmony_ci } 51348c2ecf20Sopenharmony_ci return SUCCESS; 51358c2ecf20Sopenharmony_ci} 51368c2ecf20Sopenharmony_ci/* deletes a specified unicast/multicast mac entry from CAM */ 51378c2ecf20Sopenharmony_cistatic int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr) 51388c2ecf20Sopenharmony_ci{ 51398c2ecf20Sopenharmony_ci int offset; 51408c2ecf20Sopenharmony_ci u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, tmp64; 51418c2ecf20Sopenharmony_ci struct config_param *config = &sp->config; 51428c2ecf20Sopenharmony_ci 51438c2ecf20Sopenharmony_ci for (offset = 1; 51448c2ecf20Sopenharmony_ci offset < config->max_mc_addr; offset++) { 51458c2ecf20Sopenharmony_ci tmp64 = do_s2io_read_unicast_mc(sp, offset); 51468c2ecf20Sopenharmony_ci if (tmp64 == addr) { 51478c2ecf20Sopenharmony_ci /* disable the entry by writing 0xffffffffffffULL */ 51488c2ecf20Sopenharmony_ci if (do_s2io_add_mac(sp, dis_addr, offset) == FAILURE) 51498c2ecf20Sopenharmony_ci return FAILURE; 51508c2ecf20Sopenharmony_ci /* store the new mac list from CAM */ 51518c2ecf20Sopenharmony_ci do_s2io_store_unicast_mc(sp); 51528c2ecf20Sopenharmony_ci return SUCCESS; 51538c2ecf20Sopenharmony_ci } 51548c2ecf20Sopenharmony_ci } 51558c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "MAC address 0x%llx not found in CAM\n", 51568c2ecf20Sopenharmony_ci (unsigned long long)addr); 51578c2ecf20Sopenharmony_ci return FAILURE; 51588c2ecf20Sopenharmony_ci} 51598c2ecf20Sopenharmony_ci 51608c2ecf20Sopenharmony_ci/* read mac entries from CAM */ 51618c2ecf20Sopenharmony_cistatic u64 do_s2io_read_unicast_mc(struct s2io_nic *sp, int offset) 51628c2ecf20Sopenharmony_ci{ 51638c2ecf20Sopenharmony_ci u64 tmp64, val64; 51648c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 51658c2ecf20Sopenharmony_ci 51668c2ecf20Sopenharmony_ci /* read mac addr */ 51678c2ecf20Sopenharmony_ci val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | 51688c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_OFFSET(offset); 51698c2ecf20Sopenharmony_ci writeq(val64, &bar0->rmac_addr_cmd_mem); 51708c2ecf20Sopenharmony_ci 51718c2ecf20Sopenharmony_ci /* Wait till command completes */ 51728c2ecf20Sopenharmony_ci if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, 51738c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, 51748c2ecf20Sopenharmony_ci S2IO_BIT_RESET)) { 51758c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "do_s2io_read_unicast_mc failed\n"); 51768c2ecf20Sopenharmony_ci return FAILURE; 51778c2ecf20Sopenharmony_ci } 51788c2ecf20Sopenharmony_ci tmp64 = readq(&bar0->rmac_addr_data0_mem); 51798c2ecf20Sopenharmony_ci 51808c2ecf20Sopenharmony_ci return tmp64 >> 16; 51818c2ecf20Sopenharmony_ci} 51828c2ecf20Sopenharmony_ci 51838c2ecf20Sopenharmony_ci/* 51848c2ecf20Sopenharmony_ci * s2io_set_mac_addr - driver entry point 51858c2ecf20Sopenharmony_ci */ 51868c2ecf20Sopenharmony_ci 51878c2ecf20Sopenharmony_cistatic int s2io_set_mac_addr(struct net_device *dev, void *p) 51888c2ecf20Sopenharmony_ci{ 51898c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 51908c2ecf20Sopenharmony_ci 51918c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 51928c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 51938c2ecf20Sopenharmony_ci 51948c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); 51958c2ecf20Sopenharmony_ci 51968c2ecf20Sopenharmony_ci /* store the MAC address in CAM */ 51978c2ecf20Sopenharmony_ci return do_s2io_prog_unicast(dev, dev->dev_addr); 51988c2ecf20Sopenharmony_ci} 51998c2ecf20Sopenharmony_ci/** 52008c2ecf20Sopenharmony_ci * do_s2io_prog_unicast - Programs the Xframe mac address 52018c2ecf20Sopenharmony_ci * @dev : pointer to the device structure. 52028c2ecf20Sopenharmony_ci * @addr: a uchar pointer to the new mac address which is to be set. 52038c2ecf20Sopenharmony_ci * Description : This procedure will program the Xframe to receive 52048c2ecf20Sopenharmony_ci * frames with new Mac Address 52058c2ecf20Sopenharmony_ci * Return value: SUCCESS on success and an appropriate (-)ve integer 52068c2ecf20Sopenharmony_ci * as defined in errno.h file on failure. 52078c2ecf20Sopenharmony_ci */ 52088c2ecf20Sopenharmony_ci 52098c2ecf20Sopenharmony_cistatic int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) 52108c2ecf20Sopenharmony_ci{ 52118c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 52128c2ecf20Sopenharmony_ci register u64 mac_addr = 0, perm_addr = 0; 52138c2ecf20Sopenharmony_ci int i; 52148c2ecf20Sopenharmony_ci u64 tmp64; 52158c2ecf20Sopenharmony_ci struct config_param *config = &sp->config; 52168c2ecf20Sopenharmony_ci 52178c2ecf20Sopenharmony_ci /* 52188c2ecf20Sopenharmony_ci * Set the new MAC address as the new unicast filter and reflect this 52198c2ecf20Sopenharmony_ci * change on the device address registered with the OS. It will be 52208c2ecf20Sopenharmony_ci * at offset 0. 52218c2ecf20Sopenharmony_ci */ 52228c2ecf20Sopenharmony_ci for (i = 0; i < ETH_ALEN; i++) { 52238c2ecf20Sopenharmony_ci mac_addr <<= 8; 52248c2ecf20Sopenharmony_ci mac_addr |= addr[i]; 52258c2ecf20Sopenharmony_ci perm_addr <<= 8; 52268c2ecf20Sopenharmony_ci perm_addr |= sp->def_mac_addr[0].mac_addr[i]; 52278c2ecf20Sopenharmony_ci } 52288c2ecf20Sopenharmony_ci 52298c2ecf20Sopenharmony_ci /* check if the dev_addr is different than perm_addr */ 52308c2ecf20Sopenharmony_ci if (mac_addr == perm_addr) 52318c2ecf20Sopenharmony_ci return SUCCESS; 52328c2ecf20Sopenharmony_ci 52338c2ecf20Sopenharmony_ci /* check if the mac already preset in CAM */ 52348c2ecf20Sopenharmony_ci for (i = 1; i < config->max_mac_addr; i++) { 52358c2ecf20Sopenharmony_ci tmp64 = do_s2io_read_unicast_mc(sp, i); 52368c2ecf20Sopenharmony_ci if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */ 52378c2ecf20Sopenharmony_ci break; 52388c2ecf20Sopenharmony_ci 52398c2ecf20Sopenharmony_ci if (tmp64 == mac_addr) { 52408c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, 52418c2ecf20Sopenharmony_ci "MAC addr:0x%llx already present in CAM\n", 52428c2ecf20Sopenharmony_ci (unsigned long long)mac_addr); 52438c2ecf20Sopenharmony_ci return SUCCESS; 52448c2ecf20Sopenharmony_ci } 52458c2ecf20Sopenharmony_ci } 52468c2ecf20Sopenharmony_ci if (i == config->max_mac_addr) { 52478c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "CAM full no space left for Unicast MAC\n"); 52488c2ecf20Sopenharmony_ci return FAILURE; 52498c2ecf20Sopenharmony_ci } 52508c2ecf20Sopenharmony_ci /* Update the internal structure with this new mac address */ 52518c2ecf20Sopenharmony_ci do_s2io_copy_mac_addr(sp, i, mac_addr); 52528c2ecf20Sopenharmony_ci 52538c2ecf20Sopenharmony_ci return do_s2io_add_mac(sp, mac_addr, i); 52548c2ecf20Sopenharmony_ci} 52558c2ecf20Sopenharmony_ci 52568c2ecf20Sopenharmony_ci/** 52578c2ecf20Sopenharmony_ci * s2io_ethtool_set_link_ksettings - Sets different link parameters. 52588c2ecf20Sopenharmony_ci * @dev : pointer to netdev 52598c2ecf20Sopenharmony_ci * @cmd: pointer to the structure with parameters given by ethtool to set 52608c2ecf20Sopenharmony_ci * link information. 52618c2ecf20Sopenharmony_ci * Description: 52628c2ecf20Sopenharmony_ci * The function sets different link parameters provided by the user onto 52638c2ecf20Sopenharmony_ci * the NIC. 52648c2ecf20Sopenharmony_ci * Return value: 52658c2ecf20Sopenharmony_ci * 0 on success. 52668c2ecf20Sopenharmony_ci */ 52678c2ecf20Sopenharmony_ci 52688c2ecf20Sopenharmony_cistatic int 52698c2ecf20Sopenharmony_cis2io_ethtool_set_link_ksettings(struct net_device *dev, 52708c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 52718c2ecf20Sopenharmony_ci{ 52728c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 52738c2ecf20Sopenharmony_ci if ((cmd->base.autoneg == AUTONEG_ENABLE) || 52748c2ecf20Sopenharmony_ci (cmd->base.speed != SPEED_10000) || 52758c2ecf20Sopenharmony_ci (cmd->base.duplex != DUPLEX_FULL)) 52768c2ecf20Sopenharmony_ci return -EINVAL; 52778c2ecf20Sopenharmony_ci else { 52788c2ecf20Sopenharmony_ci s2io_close(sp->dev); 52798c2ecf20Sopenharmony_ci s2io_open(sp->dev); 52808c2ecf20Sopenharmony_ci } 52818c2ecf20Sopenharmony_ci 52828c2ecf20Sopenharmony_ci return 0; 52838c2ecf20Sopenharmony_ci} 52848c2ecf20Sopenharmony_ci 52858c2ecf20Sopenharmony_ci/** 52868c2ecf20Sopenharmony_ci * s2io_ethtol_get_link_ksettings - Return link specific information. 52878c2ecf20Sopenharmony_ci * @dev: pointer to netdev 52888c2ecf20Sopenharmony_ci * @cmd : pointer to the structure with parameters given by ethtool 52898c2ecf20Sopenharmony_ci * to return link information. 52908c2ecf20Sopenharmony_ci * Description: 52918c2ecf20Sopenharmony_ci * Returns link specific information like speed, duplex etc.. to ethtool. 52928c2ecf20Sopenharmony_ci * Return value : 52938c2ecf20Sopenharmony_ci * return 0 on success. 52948c2ecf20Sopenharmony_ci */ 52958c2ecf20Sopenharmony_ci 52968c2ecf20Sopenharmony_cistatic int 52978c2ecf20Sopenharmony_cis2io_ethtool_get_link_ksettings(struct net_device *dev, 52988c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 52998c2ecf20Sopenharmony_ci{ 53008c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 53018c2ecf20Sopenharmony_ci 53028c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, supported); 53038c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, 10000baseT_Full); 53048c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE); 53058c2ecf20Sopenharmony_ci 53068c2ecf20Sopenharmony_ci ethtool_link_ksettings_zero_link_mode(cmd, advertising); 53078c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, 10000baseT_Full); 53088c2ecf20Sopenharmony_ci ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE); 53098c2ecf20Sopenharmony_ci 53108c2ecf20Sopenharmony_ci cmd->base.port = PORT_FIBRE; 53118c2ecf20Sopenharmony_ci 53128c2ecf20Sopenharmony_ci if (netif_carrier_ok(sp->dev)) { 53138c2ecf20Sopenharmony_ci cmd->base.speed = SPEED_10000; 53148c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_FULL; 53158c2ecf20Sopenharmony_ci } else { 53168c2ecf20Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 53178c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 53188c2ecf20Sopenharmony_ci } 53198c2ecf20Sopenharmony_ci 53208c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 53218c2ecf20Sopenharmony_ci return 0; 53228c2ecf20Sopenharmony_ci} 53238c2ecf20Sopenharmony_ci 53248c2ecf20Sopenharmony_ci/** 53258c2ecf20Sopenharmony_ci * s2io_ethtool_gdrvinfo - Returns driver specific information. 53268c2ecf20Sopenharmony_ci * @dev: pointer to netdev 53278c2ecf20Sopenharmony_ci * @info : pointer to the structure with parameters given by ethtool to 53288c2ecf20Sopenharmony_ci * return driver information. 53298c2ecf20Sopenharmony_ci * Description: 53308c2ecf20Sopenharmony_ci * Returns driver specefic information like name, version etc.. to ethtool. 53318c2ecf20Sopenharmony_ci * Return value: 53328c2ecf20Sopenharmony_ci * void 53338c2ecf20Sopenharmony_ci */ 53348c2ecf20Sopenharmony_ci 53358c2ecf20Sopenharmony_cistatic void s2io_ethtool_gdrvinfo(struct net_device *dev, 53368c2ecf20Sopenharmony_ci struct ethtool_drvinfo *info) 53378c2ecf20Sopenharmony_ci{ 53388c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 53398c2ecf20Sopenharmony_ci 53408c2ecf20Sopenharmony_ci strlcpy(info->driver, s2io_driver_name, sizeof(info->driver)); 53418c2ecf20Sopenharmony_ci strlcpy(info->version, s2io_driver_version, sizeof(info->version)); 53428c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(sp->pdev), sizeof(info->bus_info)); 53438c2ecf20Sopenharmony_ci} 53448c2ecf20Sopenharmony_ci 53458c2ecf20Sopenharmony_ci/** 53468c2ecf20Sopenharmony_ci * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer. 53478c2ecf20Sopenharmony_ci * @dev: pointer to netdev 53488c2ecf20Sopenharmony_ci * @regs : pointer to the structure with parameters given by ethtool for 53498c2ecf20Sopenharmony_ci * dumping the registers. 53508c2ecf20Sopenharmony_ci * @space: The input argument into which all the registers are dumped. 53518c2ecf20Sopenharmony_ci * Description: 53528c2ecf20Sopenharmony_ci * Dumps the entire register space of xFrame NIC into the user given 53538c2ecf20Sopenharmony_ci * buffer area. 53548c2ecf20Sopenharmony_ci * Return value : 53558c2ecf20Sopenharmony_ci * void . 53568c2ecf20Sopenharmony_ci */ 53578c2ecf20Sopenharmony_ci 53588c2ecf20Sopenharmony_cistatic void s2io_ethtool_gregs(struct net_device *dev, 53598c2ecf20Sopenharmony_ci struct ethtool_regs *regs, void *space) 53608c2ecf20Sopenharmony_ci{ 53618c2ecf20Sopenharmony_ci int i; 53628c2ecf20Sopenharmony_ci u64 reg; 53638c2ecf20Sopenharmony_ci u8 *reg_space = (u8 *)space; 53648c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 53658c2ecf20Sopenharmony_ci 53668c2ecf20Sopenharmony_ci regs->len = XENA_REG_SPACE; 53678c2ecf20Sopenharmony_ci regs->version = sp->pdev->subsystem_device; 53688c2ecf20Sopenharmony_ci 53698c2ecf20Sopenharmony_ci for (i = 0; i < regs->len; i += 8) { 53708c2ecf20Sopenharmony_ci reg = readq(sp->bar0 + i); 53718c2ecf20Sopenharmony_ci memcpy((reg_space + i), ®, 8); 53728c2ecf20Sopenharmony_ci } 53738c2ecf20Sopenharmony_ci} 53748c2ecf20Sopenharmony_ci 53758c2ecf20Sopenharmony_ci/* 53768c2ecf20Sopenharmony_ci * s2io_set_led - control NIC led 53778c2ecf20Sopenharmony_ci */ 53788c2ecf20Sopenharmony_cistatic void s2io_set_led(struct s2io_nic *sp, bool on) 53798c2ecf20Sopenharmony_ci{ 53808c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 53818c2ecf20Sopenharmony_ci u16 subid = sp->pdev->subsystem_device; 53828c2ecf20Sopenharmony_ci u64 val64; 53838c2ecf20Sopenharmony_ci 53848c2ecf20Sopenharmony_ci if ((sp->device_type == XFRAME_II_DEVICE) || 53858c2ecf20Sopenharmony_ci ((subid & 0xFF) >= 0x07)) { 53868c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_control); 53878c2ecf20Sopenharmony_ci if (on) 53888c2ecf20Sopenharmony_ci val64 |= GPIO_CTRL_GPIO_0; 53898c2ecf20Sopenharmony_ci else 53908c2ecf20Sopenharmony_ci val64 &= ~GPIO_CTRL_GPIO_0; 53918c2ecf20Sopenharmony_ci 53928c2ecf20Sopenharmony_ci writeq(val64, &bar0->gpio_control); 53938c2ecf20Sopenharmony_ci } else { 53948c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_control); 53958c2ecf20Sopenharmony_ci if (on) 53968c2ecf20Sopenharmony_ci val64 |= ADAPTER_LED_ON; 53978c2ecf20Sopenharmony_ci else 53988c2ecf20Sopenharmony_ci val64 &= ~ADAPTER_LED_ON; 53998c2ecf20Sopenharmony_ci 54008c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 54018c2ecf20Sopenharmony_ci } 54028c2ecf20Sopenharmony_ci 54038c2ecf20Sopenharmony_ci} 54048c2ecf20Sopenharmony_ci 54058c2ecf20Sopenharmony_ci/** 54068c2ecf20Sopenharmony_ci * s2io_ethtool_set_led - To physically identify the nic on the system. 54078c2ecf20Sopenharmony_ci * @dev : network device 54088c2ecf20Sopenharmony_ci * @state: led setting 54098c2ecf20Sopenharmony_ci * 54108c2ecf20Sopenharmony_ci * Description: Used to physically identify the NIC on the system. 54118c2ecf20Sopenharmony_ci * The Link LED will blink for a time specified by the user for 54128c2ecf20Sopenharmony_ci * identification. 54138c2ecf20Sopenharmony_ci * NOTE: The Link has to be Up to be able to blink the LED. Hence 54148c2ecf20Sopenharmony_ci * identification is possible only if it's link is up. 54158c2ecf20Sopenharmony_ci */ 54168c2ecf20Sopenharmony_ci 54178c2ecf20Sopenharmony_cistatic int s2io_ethtool_set_led(struct net_device *dev, 54188c2ecf20Sopenharmony_ci enum ethtool_phys_id_state state) 54198c2ecf20Sopenharmony_ci{ 54208c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 54218c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 54228c2ecf20Sopenharmony_ci u16 subid = sp->pdev->subsystem_device; 54238c2ecf20Sopenharmony_ci 54248c2ecf20Sopenharmony_ci if ((sp->device_type == XFRAME_I_DEVICE) && ((subid & 0xFF) < 0x07)) { 54258c2ecf20Sopenharmony_ci u64 val64 = readq(&bar0->adapter_control); 54268c2ecf20Sopenharmony_ci if (!(val64 & ADAPTER_CNTL_EN)) { 54278c2ecf20Sopenharmony_ci pr_err("Adapter Link down, cannot blink LED\n"); 54288c2ecf20Sopenharmony_ci return -EAGAIN; 54298c2ecf20Sopenharmony_ci } 54308c2ecf20Sopenharmony_ci } 54318c2ecf20Sopenharmony_ci 54328c2ecf20Sopenharmony_ci switch (state) { 54338c2ecf20Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 54348c2ecf20Sopenharmony_ci sp->adapt_ctrl_org = readq(&bar0->gpio_control); 54358c2ecf20Sopenharmony_ci return 1; /* cycle on/off once per second */ 54368c2ecf20Sopenharmony_ci 54378c2ecf20Sopenharmony_ci case ETHTOOL_ID_ON: 54388c2ecf20Sopenharmony_ci s2io_set_led(sp, true); 54398c2ecf20Sopenharmony_ci break; 54408c2ecf20Sopenharmony_ci 54418c2ecf20Sopenharmony_ci case ETHTOOL_ID_OFF: 54428c2ecf20Sopenharmony_ci s2io_set_led(sp, false); 54438c2ecf20Sopenharmony_ci break; 54448c2ecf20Sopenharmony_ci 54458c2ecf20Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 54468c2ecf20Sopenharmony_ci if (CARDS_WITH_FAULTY_LINK_INDICATORS(sp->device_type, subid)) 54478c2ecf20Sopenharmony_ci writeq(sp->adapt_ctrl_org, &bar0->gpio_control); 54488c2ecf20Sopenharmony_ci } 54498c2ecf20Sopenharmony_ci 54508c2ecf20Sopenharmony_ci return 0; 54518c2ecf20Sopenharmony_ci} 54528c2ecf20Sopenharmony_ci 54538c2ecf20Sopenharmony_cistatic void s2io_ethtool_gringparam(struct net_device *dev, 54548c2ecf20Sopenharmony_ci struct ethtool_ringparam *ering) 54558c2ecf20Sopenharmony_ci{ 54568c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 54578c2ecf20Sopenharmony_ci int i, tx_desc_count = 0, rx_desc_count = 0; 54588c2ecf20Sopenharmony_ci 54598c2ecf20Sopenharmony_ci if (sp->rxd_mode == RXD_MODE_1) { 54608c2ecf20Sopenharmony_ci ering->rx_max_pending = MAX_RX_DESC_1; 54618c2ecf20Sopenharmony_ci ering->rx_jumbo_max_pending = MAX_RX_DESC_1; 54628c2ecf20Sopenharmony_ci } else { 54638c2ecf20Sopenharmony_ci ering->rx_max_pending = MAX_RX_DESC_2; 54648c2ecf20Sopenharmony_ci ering->rx_jumbo_max_pending = MAX_RX_DESC_2; 54658c2ecf20Sopenharmony_ci } 54668c2ecf20Sopenharmony_ci 54678c2ecf20Sopenharmony_ci ering->tx_max_pending = MAX_TX_DESC; 54688c2ecf20Sopenharmony_ci 54698c2ecf20Sopenharmony_ci for (i = 0; i < sp->config.rx_ring_num; i++) 54708c2ecf20Sopenharmony_ci rx_desc_count += sp->config.rx_cfg[i].num_rxd; 54718c2ecf20Sopenharmony_ci ering->rx_pending = rx_desc_count; 54728c2ecf20Sopenharmony_ci ering->rx_jumbo_pending = rx_desc_count; 54738c2ecf20Sopenharmony_ci 54748c2ecf20Sopenharmony_ci for (i = 0; i < sp->config.tx_fifo_num; i++) 54758c2ecf20Sopenharmony_ci tx_desc_count += sp->config.tx_cfg[i].fifo_len; 54768c2ecf20Sopenharmony_ci ering->tx_pending = tx_desc_count; 54778c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "max txds: %d\n", sp->config.max_txds); 54788c2ecf20Sopenharmony_ci} 54798c2ecf20Sopenharmony_ci 54808c2ecf20Sopenharmony_ci/** 54818c2ecf20Sopenharmony_ci * s2io_ethtool_getpause_data -Pause frame frame generation and reception. 54828c2ecf20Sopenharmony_ci * @dev: pointer to netdev 54838c2ecf20Sopenharmony_ci * @ep : pointer to the structure with pause parameters given by ethtool. 54848c2ecf20Sopenharmony_ci * Description: 54858c2ecf20Sopenharmony_ci * Returns the Pause frame generation and reception capability of the NIC. 54868c2ecf20Sopenharmony_ci * Return value: 54878c2ecf20Sopenharmony_ci * void 54888c2ecf20Sopenharmony_ci */ 54898c2ecf20Sopenharmony_cistatic void s2io_ethtool_getpause_data(struct net_device *dev, 54908c2ecf20Sopenharmony_ci struct ethtool_pauseparam *ep) 54918c2ecf20Sopenharmony_ci{ 54928c2ecf20Sopenharmony_ci u64 val64; 54938c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 54948c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 54958c2ecf20Sopenharmony_ci 54968c2ecf20Sopenharmony_ci val64 = readq(&bar0->rmac_pause_cfg); 54978c2ecf20Sopenharmony_ci if (val64 & RMAC_PAUSE_GEN_ENABLE) 54988c2ecf20Sopenharmony_ci ep->tx_pause = true; 54998c2ecf20Sopenharmony_ci if (val64 & RMAC_PAUSE_RX_ENABLE) 55008c2ecf20Sopenharmony_ci ep->rx_pause = true; 55018c2ecf20Sopenharmony_ci ep->autoneg = false; 55028c2ecf20Sopenharmony_ci} 55038c2ecf20Sopenharmony_ci 55048c2ecf20Sopenharmony_ci/** 55058c2ecf20Sopenharmony_ci * s2io_ethtool_setpause_data - set/reset pause frame generation. 55068c2ecf20Sopenharmony_ci * @dev: pointer to netdev 55078c2ecf20Sopenharmony_ci * @ep : pointer to the structure with pause parameters given by ethtool. 55088c2ecf20Sopenharmony_ci * Description: 55098c2ecf20Sopenharmony_ci * It can be used to set or reset Pause frame generation or reception 55108c2ecf20Sopenharmony_ci * support of the NIC. 55118c2ecf20Sopenharmony_ci * Return value: 55128c2ecf20Sopenharmony_ci * int, returns 0 on Success 55138c2ecf20Sopenharmony_ci */ 55148c2ecf20Sopenharmony_ci 55158c2ecf20Sopenharmony_cistatic int s2io_ethtool_setpause_data(struct net_device *dev, 55168c2ecf20Sopenharmony_ci struct ethtool_pauseparam *ep) 55178c2ecf20Sopenharmony_ci{ 55188c2ecf20Sopenharmony_ci u64 val64; 55198c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 55208c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 55218c2ecf20Sopenharmony_ci 55228c2ecf20Sopenharmony_ci val64 = readq(&bar0->rmac_pause_cfg); 55238c2ecf20Sopenharmony_ci if (ep->tx_pause) 55248c2ecf20Sopenharmony_ci val64 |= RMAC_PAUSE_GEN_ENABLE; 55258c2ecf20Sopenharmony_ci else 55268c2ecf20Sopenharmony_ci val64 &= ~RMAC_PAUSE_GEN_ENABLE; 55278c2ecf20Sopenharmony_ci if (ep->rx_pause) 55288c2ecf20Sopenharmony_ci val64 |= RMAC_PAUSE_RX_ENABLE; 55298c2ecf20Sopenharmony_ci else 55308c2ecf20Sopenharmony_ci val64 &= ~RMAC_PAUSE_RX_ENABLE; 55318c2ecf20Sopenharmony_ci writeq(val64, &bar0->rmac_pause_cfg); 55328c2ecf20Sopenharmony_ci return 0; 55338c2ecf20Sopenharmony_ci} 55348c2ecf20Sopenharmony_ci 55358c2ecf20Sopenharmony_ci#define S2IO_DEV_ID 5 55368c2ecf20Sopenharmony_ci/** 55378c2ecf20Sopenharmony_ci * read_eeprom - reads 4 bytes of data from user given offset. 55388c2ecf20Sopenharmony_ci * @sp : private member of the device structure, which is a pointer to the 55398c2ecf20Sopenharmony_ci * s2io_nic structure. 55408c2ecf20Sopenharmony_ci * @off : offset at which the data must be written 55418c2ecf20Sopenharmony_ci * @data : Its an output parameter where the data read at the given 55428c2ecf20Sopenharmony_ci * offset is stored. 55438c2ecf20Sopenharmony_ci * Description: 55448c2ecf20Sopenharmony_ci * Will read 4 bytes of data from the user given offset and return the 55458c2ecf20Sopenharmony_ci * read data. 55468c2ecf20Sopenharmony_ci * NOTE: Will allow to read only part of the EEPROM visible through the 55478c2ecf20Sopenharmony_ci * I2C bus. 55488c2ecf20Sopenharmony_ci * Return value: 55498c2ecf20Sopenharmony_ci * -1 on failure and 0 on success. 55508c2ecf20Sopenharmony_ci */ 55518c2ecf20Sopenharmony_cistatic int read_eeprom(struct s2io_nic *sp, int off, u64 *data) 55528c2ecf20Sopenharmony_ci{ 55538c2ecf20Sopenharmony_ci int ret = -1; 55548c2ecf20Sopenharmony_ci u32 exit_cnt = 0; 55558c2ecf20Sopenharmony_ci u64 val64; 55568c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 55578c2ecf20Sopenharmony_ci 55588c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_I_DEVICE) { 55598c2ecf20Sopenharmony_ci val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | 55608c2ecf20Sopenharmony_ci I2C_CONTROL_ADDR(off) | 55618c2ecf20Sopenharmony_ci I2C_CONTROL_BYTE_CNT(0x3) | 55628c2ecf20Sopenharmony_ci I2C_CONTROL_READ | 55638c2ecf20Sopenharmony_ci I2C_CONTROL_CNTL_START; 55648c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); 55658c2ecf20Sopenharmony_ci 55668c2ecf20Sopenharmony_ci while (exit_cnt < 5) { 55678c2ecf20Sopenharmony_ci val64 = readq(&bar0->i2c_control); 55688c2ecf20Sopenharmony_ci if (I2C_CONTROL_CNTL_END(val64)) { 55698c2ecf20Sopenharmony_ci *data = I2C_CONTROL_GET_DATA(val64); 55708c2ecf20Sopenharmony_ci ret = 0; 55718c2ecf20Sopenharmony_ci break; 55728c2ecf20Sopenharmony_ci } 55738c2ecf20Sopenharmony_ci msleep(50); 55748c2ecf20Sopenharmony_ci exit_cnt++; 55758c2ecf20Sopenharmony_ci } 55768c2ecf20Sopenharmony_ci } 55778c2ecf20Sopenharmony_ci 55788c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_II_DEVICE) { 55798c2ecf20Sopenharmony_ci val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 | 55808c2ecf20Sopenharmony_ci SPI_CONTROL_BYTECNT(0x3) | 55818c2ecf20Sopenharmony_ci SPI_CONTROL_CMD(0x3) | SPI_CONTROL_ADDR(off); 55828c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); 55838c2ecf20Sopenharmony_ci val64 |= SPI_CONTROL_REQ; 55848c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); 55858c2ecf20Sopenharmony_ci while (exit_cnt < 5) { 55868c2ecf20Sopenharmony_ci val64 = readq(&bar0->spi_control); 55878c2ecf20Sopenharmony_ci if (val64 & SPI_CONTROL_NACK) { 55888c2ecf20Sopenharmony_ci ret = 1; 55898c2ecf20Sopenharmony_ci break; 55908c2ecf20Sopenharmony_ci } else if (val64 & SPI_CONTROL_DONE) { 55918c2ecf20Sopenharmony_ci *data = readq(&bar0->spi_data); 55928c2ecf20Sopenharmony_ci *data &= 0xffffff; 55938c2ecf20Sopenharmony_ci ret = 0; 55948c2ecf20Sopenharmony_ci break; 55958c2ecf20Sopenharmony_ci } 55968c2ecf20Sopenharmony_ci msleep(50); 55978c2ecf20Sopenharmony_ci exit_cnt++; 55988c2ecf20Sopenharmony_ci } 55998c2ecf20Sopenharmony_ci } 56008c2ecf20Sopenharmony_ci return ret; 56018c2ecf20Sopenharmony_ci} 56028c2ecf20Sopenharmony_ci 56038c2ecf20Sopenharmony_ci/** 56048c2ecf20Sopenharmony_ci * write_eeprom - actually writes the relevant part of the data value. 56058c2ecf20Sopenharmony_ci * @sp : private member of the device structure, which is a pointer to the 56068c2ecf20Sopenharmony_ci * s2io_nic structure. 56078c2ecf20Sopenharmony_ci * @off : offset at which the data must be written 56088c2ecf20Sopenharmony_ci * @data : The data that is to be written 56098c2ecf20Sopenharmony_ci * @cnt : Number of bytes of the data that are actually to be written into 56108c2ecf20Sopenharmony_ci * the Eeprom. (max of 3) 56118c2ecf20Sopenharmony_ci * Description: 56128c2ecf20Sopenharmony_ci * Actually writes the relevant part of the data value into the Eeprom 56138c2ecf20Sopenharmony_ci * through the I2C bus. 56148c2ecf20Sopenharmony_ci * Return value: 56158c2ecf20Sopenharmony_ci * 0 on success, -1 on failure. 56168c2ecf20Sopenharmony_ci */ 56178c2ecf20Sopenharmony_ci 56188c2ecf20Sopenharmony_cistatic int write_eeprom(struct s2io_nic *sp, int off, u64 data, int cnt) 56198c2ecf20Sopenharmony_ci{ 56208c2ecf20Sopenharmony_ci int exit_cnt = 0, ret = -1; 56218c2ecf20Sopenharmony_ci u64 val64; 56228c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 56238c2ecf20Sopenharmony_ci 56248c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_I_DEVICE) { 56258c2ecf20Sopenharmony_ci val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | 56268c2ecf20Sopenharmony_ci I2C_CONTROL_ADDR(off) | 56278c2ecf20Sopenharmony_ci I2C_CONTROL_BYTE_CNT(cnt) | 56288c2ecf20Sopenharmony_ci I2C_CONTROL_SET_DATA((u32)data) | 56298c2ecf20Sopenharmony_ci I2C_CONTROL_CNTL_START; 56308c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->i2c_control, LF); 56318c2ecf20Sopenharmony_ci 56328c2ecf20Sopenharmony_ci while (exit_cnt < 5) { 56338c2ecf20Sopenharmony_ci val64 = readq(&bar0->i2c_control); 56348c2ecf20Sopenharmony_ci if (I2C_CONTROL_CNTL_END(val64)) { 56358c2ecf20Sopenharmony_ci if (!(val64 & I2C_CONTROL_NACK)) 56368c2ecf20Sopenharmony_ci ret = 0; 56378c2ecf20Sopenharmony_ci break; 56388c2ecf20Sopenharmony_ci } 56398c2ecf20Sopenharmony_ci msleep(50); 56408c2ecf20Sopenharmony_ci exit_cnt++; 56418c2ecf20Sopenharmony_ci } 56428c2ecf20Sopenharmony_ci } 56438c2ecf20Sopenharmony_ci 56448c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_II_DEVICE) { 56458c2ecf20Sopenharmony_ci int write_cnt = (cnt == 8) ? 0 : cnt; 56468c2ecf20Sopenharmony_ci writeq(SPI_DATA_WRITE(data, (cnt << 3)), &bar0->spi_data); 56478c2ecf20Sopenharmony_ci 56488c2ecf20Sopenharmony_ci val64 = SPI_CONTROL_KEY(0x9) | SPI_CONTROL_SEL1 | 56498c2ecf20Sopenharmony_ci SPI_CONTROL_BYTECNT(write_cnt) | 56508c2ecf20Sopenharmony_ci SPI_CONTROL_CMD(0x2) | SPI_CONTROL_ADDR(off); 56518c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); 56528c2ecf20Sopenharmony_ci val64 |= SPI_CONTROL_REQ; 56538c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->spi_control, LF); 56548c2ecf20Sopenharmony_ci while (exit_cnt < 5) { 56558c2ecf20Sopenharmony_ci val64 = readq(&bar0->spi_control); 56568c2ecf20Sopenharmony_ci if (val64 & SPI_CONTROL_NACK) { 56578c2ecf20Sopenharmony_ci ret = 1; 56588c2ecf20Sopenharmony_ci break; 56598c2ecf20Sopenharmony_ci } else if (val64 & SPI_CONTROL_DONE) { 56608c2ecf20Sopenharmony_ci ret = 0; 56618c2ecf20Sopenharmony_ci break; 56628c2ecf20Sopenharmony_ci } 56638c2ecf20Sopenharmony_ci msleep(50); 56648c2ecf20Sopenharmony_ci exit_cnt++; 56658c2ecf20Sopenharmony_ci } 56668c2ecf20Sopenharmony_ci } 56678c2ecf20Sopenharmony_ci return ret; 56688c2ecf20Sopenharmony_ci} 56698c2ecf20Sopenharmony_cistatic void s2io_vpd_read(struct s2io_nic *nic) 56708c2ecf20Sopenharmony_ci{ 56718c2ecf20Sopenharmony_ci u8 *vpd_data; 56728c2ecf20Sopenharmony_ci u8 data; 56738c2ecf20Sopenharmony_ci int i = 0, cnt, len, fail = 0; 56748c2ecf20Sopenharmony_ci int vpd_addr = 0x80; 56758c2ecf20Sopenharmony_ci struct swStat *swstats = &nic->mac_control.stats_info->sw_stat; 56768c2ecf20Sopenharmony_ci 56778c2ecf20Sopenharmony_ci if (nic->device_type == XFRAME_II_DEVICE) { 56788c2ecf20Sopenharmony_ci strcpy(nic->product_name, "Xframe II 10GbE network adapter"); 56798c2ecf20Sopenharmony_ci vpd_addr = 0x80; 56808c2ecf20Sopenharmony_ci } else { 56818c2ecf20Sopenharmony_ci strcpy(nic->product_name, "Xframe I 10GbE network adapter"); 56828c2ecf20Sopenharmony_ci vpd_addr = 0x50; 56838c2ecf20Sopenharmony_ci } 56848c2ecf20Sopenharmony_ci strcpy(nic->serial_num, "NOT AVAILABLE"); 56858c2ecf20Sopenharmony_ci 56868c2ecf20Sopenharmony_ci vpd_data = kmalloc(256, GFP_KERNEL); 56878c2ecf20Sopenharmony_ci if (!vpd_data) { 56888c2ecf20Sopenharmony_ci swstats->mem_alloc_fail_cnt++; 56898c2ecf20Sopenharmony_ci return; 56908c2ecf20Sopenharmony_ci } 56918c2ecf20Sopenharmony_ci swstats->mem_allocated += 256; 56928c2ecf20Sopenharmony_ci 56938c2ecf20Sopenharmony_ci for (i = 0; i < 256; i += 4) { 56948c2ecf20Sopenharmony_ci pci_write_config_byte(nic->pdev, (vpd_addr + 2), i); 56958c2ecf20Sopenharmony_ci pci_read_config_byte(nic->pdev, (vpd_addr + 2), &data); 56968c2ecf20Sopenharmony_ci pci_write_config_byte(nic->pdev, (vpd_addr + 3), 0); 56978c2ecf20Sopenharmony_ci for (cnt = 0; cnt < 5; cnt++) { 56988c2ecf20Sopenharmony_ci msleep(2); 56998c2ecf20Sopenharmony_ci pci_read_config_byte(nic->pdev, (vpd_addr + 3), &data); 57008c2ecf20Sopenharmony_ci if (data == 0x80) 57018c2ecf20Sopenharmony_ci break; 57028c2ecf20Sopenharmony_ci } 57038c2ecf20Sopenharmony_ci if (cnt >= 5) { 57048c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Read of VPD data failed\n"); 57058c2ecf20Sopenharmony_ci fail = 1; 57068c2ecf20Sopenharmony_ci break; 57078c2ecf20Sopenharmony_ci } 57088c2ecf20Sopenharmony_ci pci_read_config_dword(nic->pdev, (vpd_addr + 4), 57098c2ecf20Sopenharmony_ci (u32 *)&vpd_data[i]); 57108c2ecf20Sopenharmony_ci } 57118c2ecf20Sopenharmony_ci 57128c2ecf20Sopenharmony_ci if (!fail) { 57138c2ecf20Sopenharmony_ci /* read serial number of adapter */ 57148c2ecf20Sopenharmony_ci for (cnt = 0; cnt < 252; cnt++) { 57158c2ecf20Sopenharmony_ci if ((vpd_data[cnt] == 'S') && 57168c2ecf20Sopenharmony_ci (vpd_data[cnt+1] == 'N')) { 57178c2ecf20Sopenharmony_ci len = vpd_data[cnt+2]; 57188c2ecf20Sopenharmony_ci if (len < min(VPD_STRING_LEN, 256-cnt-2)) { 57198c2ecf20Sopenharmony_ci memcpy(nic->serial_num, 57208c2ecf20Sopenharmony_ci &vpd_data[cnt + 3], 57218c2ecf20Sopenharmony_ci len); 57228c2ecf20Sopenharmony_ci memset(nic->serial_num+len, 57238c2ecf20Sopenharmony_ci 0, 57248c2ecf20Sopenharmony_ci VPD_STRING_LEN-len); 57258c2ecf20Sopenharmony_ci break; 57268c2ecf20Sopenharmony_ci } 57278c2ecf20Sopenharmony_ci } 57288c2ecf20Sopenharmony_ci } 57298c2ecf20Sopenharmony_ci } 57308c2ecf20Sopenharmony_ci 57318c2ecf20Sopenharmony_ci if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) { 57328c2ecf20Sopenharmony_ci len = vpd_data[1]; 57338c2ecf20Sopenharmony_ci memcpy(nic->product_name, &vpd_data[3], len); 57348c2ecf20Sopenharmony_ci nic->product_name[len] = 0; 57358c2ecf20Sopenharmony_ci } 57368c2ecf20Sopenharmony_ci kfree(vpd_data); 57378c2ecf20Sopenharmony_ci swstats->mem_freed += 256; 57388c2ecf20Sopenharmony_ci} 57398c2ecf20Sopenharmony_ci 57408c2ecf20Sopenharmony_ci/** 57418c2ecf20Sopenharmony_ci * s2io_ethtool_geeprom - reads the value stored in the Eeprom. 57428c2ecf20Sopenharmony_ci * @dev: pointer to netdev 57438c2ecf20Sopenharmony_ci * @eeprom : pointer to the user level structure provided by ethtool, 57448c2ecf20Sopenharmony_ci * containing all relevant information. 57458c2ecf20Sopenharmony_ci * @data_buf : user defined value to be written into Eeprom. 57468c2ecf20Sopenharmony_ci * Description: Reads the values stored in the Eeprom at given offset 57478c2ecf20Sopenharmony_ci * for a given length. Stores these values int the input argument data 57488c2ecf20Sopenharmony_ci * buffer 'data_buf' and returns these to the caller (ethtool.) 57498c2ecf20Sopenharmony_ci * Return value: 57508c2ecf20Sopenharmony_ci * int 0 on success 57518c2ecf20Sopenharmony_ci */ 57528c2ecf20Sopenharmony_ci 57538c2ecf20Sopenharmony_cistatic int s2io_ethtool_geeprom(struct net_device *dev, 57548c2ecf20Sopenharmony_ci struct ethtool_eeprom *eeprom, u8 * data_buf) 57558c2ecf20Sopenharmony_ci{ 57568c2ecf20Sopenharmony_ci u32 i, valid; 57578c2ecf20Sopenharmony_ci u64 data; 57588c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 57598c2ecf20Sopenharmony_ci 57608c2ecf20Sopenharmony_ci eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16); 57618c2ecf20Sopenharmony_ci 57628c2ecf20Sopenharmony_ci if ((eeprom->offset + eeprom->len) > (XENA_EEPROM_SPACE)) 57638c2ecf20Sopenharmony_ci eeprom->len = XENA_EEPROM_SPACE - eeprom->offset; 57648c2ecf20Sopenharmony_ci 57658c2ecf20Sopenharmony_ci for (i = 0; i < eeprom->len; i += 4) { 57668c2ecf20Sopenharmony_ci if (read_eeprom(sp, (eeprom->offset + i), &data)) { 57678c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n"); 57688c2ecf20Sopenharmony_ci return -EFAULT; 57698c2ecf20Sopenharmony_ci } 57708c2ecf20Sopenharmony_ci valid = INV(data); 57718c2ecf20Sopenharmony_ci memcpy((data_buf + i), &valid, 4); 57728c2ecf20Sopenharmony_ci } 57738c2ecf20Sopenharmony_ci return 0; 57748c2ecf20Sopenharmony_ci} 57758c2ecf20Sopenharmony_ci 57768c2ecf20Sopenharmony_ci/** 57778c2ecf20Sopenharmony_ci * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom 57788c2ecf20Sopenharmony_ci * @dev: pointer to netdev 57798c2ecf20Sopenharmony_ci * @eeprom : pointer to the user level structure provided by ethtool, 57808c2ecf20Sopenharmony_ci * containing all relevant information. 57818c2ecf20Sopenharmony_ci * @data_buf : user defined value to be written into Eeprom. 57828c2ecf20Sopenharmony_ci * Description: 57838c2ecf20Sopenharmony_ci * Tries to write the user provided value in the Eeprom, at the offset 57848c2ecf20Sopenharmony_ci * given by the user. 57858c2ecf20Sopenharmony_ci * Return value: 57868c2ecf20Sopenharmony_ci * 0 on success, -EFAULT on failure. 57878c2ecf20Sopenharmony_ci */ 57888c2ecf20Sopenharmony_ci 57898c2ecf20Sopenharmony_cistatic int s2io_ethtool_seeprom(struct net_device *dev, 57908c2ecf20Sopenharmony_ci struct ethtool_eeprom *eeprom, 57918c2ecf20Sopenharmony_ci u8 *data_buf) 57928c2ecf20Sopenharmony_ci{ 57938c2ecf20Sopenharmony_ci int len = eeprom->len, cnt = 0; 57948c2ecf20Sopenharmony_ci u64 valid = 0, data; 57958c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 57968c2ecf20Sopenharmony_ci 57978c2ecf20Sopenharmony_ci if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { 57988c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 57998c2ecf20Sopenharmony_ci "ETHTOOL_WRITE_EEPROM Err: " 58008c2ecf20Sopenharmony_ci "Magic value is wrong, it is 0x%x should be 0x%x\n", 58018c2ecf20Sopenharmony_ci (sp->pdev->vendor | (sp->pdev->device << 16)), 58028c2ecf20Sopenharmony_ci eeprom->magic); 58038c2ecf20Sopenharmony_ci return -EFAULT; 58048c2ecf20Sopenharmony_ci } 58058c2ecf20Sopenharmony_ci 58068c2ecf20Sopenharmony_ci while (len) { 58078c2ecf20Sopenharmony_ci data = (u32)data_buf[cnt] & 0x000000FF; 58088c2ecf20Sopenharmony_ci if (data) 58098c2ecf20Sopenharmony_ci valid = (u32)(data << 24); 58108c2ecf20Sopenharmony_ci else 58118c2ecf20Sopenharmony_ci valid = data; 58128c2ecf20Sopenharmony_ci 58138c2ecf20Sopenharmony_ci if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) { 58148c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 58158c2ecf20Sopenharmony_ci "ETHTOOL_WRITE_EEPROM Err: " 58168c2ecf20Sopenharmony_ci "Cannot write into the specified offset\n"); 58178c2ecf20Sopenharmony_ci return -EFAULT; 58188c2ecf20Sopenharmony_ci } 58198c2ecf20Sopenharmony_ci cnt++; 58208c2ecf20Sopenharmony_ci len--; 58218c2ecf20Sopenharmony_ci } 58228c2ecf20Sopenharmony_ci 58238c2ecf20Sopenharmony_ci return 0; 58248c2ecf20Sopenharmony_ci} 58258c2ecf20Sopenharmony_ci 58268c2ecf20Sopenharmony_ci/** 58278c2ecf20Sopenharmony_ci * s2io_register_test - reads and writes into all clock domains. 58288c2ecf20Sopenharmony_ci * @sp : private member of the device structure, which is a pointer to the 58298c2ecf20Sopenharmony_ci * s2io_nic structure. 58308c2ecf20Sopenharmony_ci * @data : variable that returns the result of each of the test conducted b 58318c2ecf20Sopenharmony_ci * by the driver. 58328c2ecf20Sopenharmony_ci * Description: 58338c2ecf20Sopenharmony_ci * Read and write into all clock domains. The NIC has 3 clock domains, 58348c2ecf20Sopenharmony_ci * see that registers in all the three regions are accessible. 58358c2ecf20Sopenharmony_ci * Return value: 58368c2ecf20Sopenharmony_ci * 0 on success. 58378c2ecf20Sopenharmony_ci */ 58388c2ecf20Sopenharmony_ci 58398c2ecf20Sopenharmony_cistatic int s2io_register_test(struct s2io_nic *sp, uint64_t *data) 58408c2ecf20Sopenharmony_ci{ 58418c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 58428c2ecf20Sopenharmony_ci u64 val64 = 0, exp_val; 58438c2ecf20Sopenharmony_ci int fail = 0; 58448c2ecf20Sopenharmony_ci 58458c2ecf20Sopenharmony_ci val64 = readq(&bar0->pif_rd_swapper_fb); 58468c2ecf20Sopenharmony_ci if (val64 != 0x123456789abcdefULL) { 58478c2ecf20Sopenharmony_ci fail = 1; 58488c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 1); 58498c2ecf20Sopenharmony_ci } 58508c2ecf20Sopenharmony_ci 58518c2ecf20Sopenharmony_ci val64 = readq(&bar0->rmac_pause_cfg); 58528c2ecf20Sopenharmony_ci if (val64 != 0xc000ffff00000000ULL) { 58538c2ecf20Sopenharmony_ci fail = 1; 58548c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 2); 58558c2ecf20Sopenharmony_ci } 58568c2ecf20Sopenharmony_ci 58578c2ecf20Sopenharmony_ci val64 = readq(&bar0->rx_queue_cfg); 58588c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_II_DEVICE) 58598c2ecf20Sopenharmony_ci exp_val = 0x0404040404040404ULL; 58608c2ecf20Sopenharmony_ci else 58618c2ecf20Sopenharmony_ci exp_val = 0x0808080808080808ULL; 58628c2ecf20Sopenharmony_ci if (val64 != exp_val) { 58638c2ecf20Sopenharmony_ci fail = 1; 58648c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 3); 58658c2ecf20Sopenharmony_ci } 58668c2ecf20Sopenharmony_ci 58678c2ecf20Sopenharmony_ci val64 = readq(&bar0->xgxs_efifo_cfg); 58688c2ecf20Sopenharmony_ci if (val64 != 0x000000001923141EULL) { 58698c2ecf20Sopenharmony_ci fail = 1; 58708c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "Read Test level %d fails\n", 4); 58718c2ecf20Sopenharmony_ci } 58728c2ecf20Sopenharmony_ci 58738c2ecf20Sopenharmony_ci val64 = 0x5A5A5A5A5A5A5A5AULL; 58748c2ecf20Sopenharmony_ci writeq(val64, &bar0->xmsi_data); 58758c2ecf20Sopenharmony_ci val64 = readq(&bar0->xmsi_data); 58768c2ecf20Sopenharmony_ci if (val64 != 0x5A5A5A5A5A5A5A5AULL) { 58778c2ecf20Sopenharmony_ci fail = 1; 58788c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Write Test level %d fails\n", 1); 58798c2ecf20Sopenharmony_ci } 58808c2ecf20Sopenharmony_ci 58818c2ecf20Sopenharmony_ci val64 = 0xA5A5A5A5A5A5A5A5ULL; 58828c2ecf20Sopenharmony_ci writeq(val64, &bar0->xmsi_data); 58838c2ecf20Sopenharmony_ci val64 = readq(&bar0->xmsi_data); 58848c2ecf20Sopenharmony_ci if (val64 != 0xA5A5A5A5A5A5A5A5ULL) { 58858c2ecf20Sopenharmony_ci fail = 1; 58868c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Write Test level %d fails\n", 2); 58878c2ecf20Sopenharmony_ci } 58888c2ecf20Sopenharmony_ci 58898c2ecf20Sopenharmony_ci *data = fail; 58908c2ecf20Sopenharmony_ci return fail; 58918c2ecf20Sopenharmony_ci} 58928c2ecf20Sopenharmony_ci 58938c2ecf20Sopenharmony_ci/** 58948c2ecf20Sopenharmony_ci * s2io_eeprom_test - to verify that EEprom in the xena can be programmed. 58958c2ecf20Sopenharmony_ci * @sp : private member of the device structure, which is a pointer to the 58968c2ecf20Sopenharmony_ci * s2io_nic structure. 58978c2ecf20Sopenharmony_ci * @data:variable that returns the result of each of the test conducted by 58988c2ecf20Sopenharmony_ci * the driver. 58998c2ecf20Sopenharmony_ci * Description: 59008c2ecf20Sopenharmony_ci * Verify that EEPROM in the xena can be programmed using I2C_CONTROL 59018c2ecf20Sopenharmony_ci * register. 59028c2ecf20Sopenharmony_ci * Return value: 59038c2ecf20Sopenharmony_ci * 0 on success. 59048c2ecf20Sopenharmony_ci */ 59058c2ecf20Sopenharmony_ci 59068c2ecf20Sopenharmony_cistatic int s2io_eeprom_test(struct s2io_nic *sp, uint64_t *data) 59078c2ecf20Sopenharmony_ci{ 59088c2ecf20Sopenharmony_ci int fail = 0; 59098c2ecf20Sopenharmony_ci u64 ret_data, org_4F0, org_7F0; 59108c2ecf20Sopenharmony_ci u8 saved_4F0 = 0, saved_7F0 = 0; 59118c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 59128c2ecf20Sopenharmony_ci 59138c2ecf20Sopenharmony_ci /* Test Write Error at offset 0 */ 59148c2ecf20Sopenharmony_ci /* Note that SPI interface allows write access to all areas 59158c2ecf20Sopenharmony_ci * of EEPROM. Hence doing all negative testing only for Xframe I. 59168c2ecf20Sopenharmony_ci */ 59178c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_I_DEVICE) 59188c2ecf20Sopenharmony_ci if (!write_eeprom(sp, 0, 0, 3)) 59198c2ecf20Sopenharmony_ci fail = 1; 59208c2ecf20Sopenharmony_ci 59218c2ecf20Sopenharmony_ci /* Save current values at offsets 0x4F0 and 0x7F0 */ 59228c2ecf20Sopenharmony_ci if (!read_eeprom(sp, 0x4F0, &org_4F0)) 59238c2ecf20Sopenharmony_ci saved_4F0 = 1; 59248c2ecf20Sopenharmony_ci if (!read_eeprom(sp, 0x7F0, &org_7F0)) 59258c2ecf20Sopenharmony_ci saved_7F0 = 1; 59268c2ecf20Sopenharmony_ci 59278c2ecf20Sopenharmony_ci /* Test Write at offset 4f0 */ 59288c2ecf20Sopenharmony_ci if (write_eeprom(sp, 0x4F0, 0x012345, 3)) 59298c2ecf20Sopenharmony_ci fail = 1; 59308c2ecf20Sopenharmony_ci if (read_eeprom(sp, 0x4F0, &ret_data)) 59318c2ecf20Sopenharmony_ci fail = 1; 59328c2ecf20Sopenharmony_ci 59338c2ecf20Sopenharmony_ci if (ret_data != 0x012345) { 59348c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. " 59358c2ecf20Sopenharmony_ci "Data written %llx Data read %llx\n", 59368c2ecf20Sopenharmony_ci dev->name, (unsigned long long)0x12345, 59378c2ecf20Sopenharmony_ci (unsigned long long)ret_data); 59388c2ecf20Sopenharmony_ci fail = 1; 59398c2ecf20Sopenharmony_ci } 59408c2ecf20Sopenharmony_ci 59418c2ecf20Sopenharmony_ci /* Reset the EEPROM data go FFFF */ 59428c2ecf20Sopenharmony_ci write_eeprom(sp, 0x4F0, 0xFFFFFF, 3); 59438c2ecf20Sopenharmony_ci 59448c2ecf20Sopenharmony_ci /* Test Write Request Error at offset 0x7c */ 59458c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_I_DEVICE) 59468c2ecf20Sopenharmony_ci if (!write_eeprom(sp, 0x07C, 0, 3)) 59478c2ecf20Sopenharmony_ci fail = 1; 59488c2ecf20Sopenharmony_ci 59498c2ecf20Sopenharmony_ci /* Test Write Request at offset 0x7f0 */ 59508c2ecf20Sopenharmony_ci if (write_eeprom(sp, 0x7F0, 0x012345, 3)) 59518c2ecf20Sopenharmony_ci fail = 1; 59528c2ecf20Sopenharmony_ci if (read_eeprom(sp, 0x7F0, &ret_data)) 59538c2ecf20Sopenharmony_ci fail = 1; 59548c2ecf20Sopenharmony_ci 59558c2ecf20Sopenharmony_ci if (ret_data != 0x012345) { 59568c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. " 59578c2ecf20Sopenharmony_ci "Data written %llx Data read %llx\n", 59588c2ecf20Sopenharmony_ci dev->name, (unsigned long long)0x12345, 59598c2ecf20Sopenharmony_ci (unsigned long long)ret_data); 59608c2ecf20Sopenharmony_ci fail = 1; 59618c2ecf20Sopenharmony_ci } 59628c2ecf20Sopenharmony_ci 59638c2ecf20Sopenharmony_ci /* Reset the EEPROM data go FFFF */ 59648c2ecf20Sopenharmony_ci write_eeprom(sp, 0x7F0, 0xFFFFFF, 3); 59658c2ecf20Sopenharmony_ci 59668c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_I_DEVICE) { 59678c2ecf20Sopenharmony_ci /* Test Write Error at offset 0x80 */ 59688c2ecf20Sopenharmony_ci if (!write_eeprom(sp, 0x080, 0, 3)) 59698c2ecf20Sopenharmony_ci fail = 1; 59708c2ecf20Sopenharmony_ci 59718c2ecf20Sopenharmony_ci /* Test Write Error at offset 0xfc */ 59728c2ecf20Sopenharmony_ci if (!write_eeprom(sp, 0x0FC, 0, 3)) 59738c2ecf20Sopenharmony_ci fail = 1; 59748c2ecf20Sopenharmony_ci 59758c2ecf20Sopenharmony_ci /* Test Write Error at offset 0x100 */ 59768c2ecf20Sopenharmony_ci if (!write_eeprom(sp, 0x100, 0, 3)) 59778c2ecf20Sopenharmony_ci fail = 1; 59788c2ecf20Sopenharmony_ci 59798c2ecf20Sopenharmony_ci /* Test Write Error at offset 4ec */ 59808c2ecf20Sopenharmony_ci if (!write_eeprom(sp, 0x4EC, 0, 3)) 59818c2ecf20Sopenharmony_ci fail = 1; 59828c2ecf20Sopenharmony_ci } 59838c2ecf20Sopenharmony_ci 59848c2ecf20Sopenharmony_ci /* Restore values at offsets 0x4F0 and 0x7F0 */ 59858c2ecf20Sopenharmony_ci if (saved_4F0) 59868c2ecf20Sopenharmony_ci write_eeprom(sp, 0x4F0, org_4F0, 3); 59878c2ecf20Sopenharmony_ci if (saved_7F0) 59888c2ecf20Sopenharmony_ci write_eeprom(sp, 0x7F0, org_7F0, 3); 59898c2ecf20Sopenharmony_ci 59908c2ecf20Sopenharmony_ci *data = fail; 59918c2ecf20Sopenharmony_ci return fail; 59928c2ecf20Sopenharmony_ci} 59938c2ecf20Sopenharmony_ci 59948c2ecf20Sopenharmony_ci/** 59958c2ecf20Sopenharmony_ci * s2io_bist_test - invokes the MemBist test of the card . 59968c2ecf20Sopenharmony_ci * @sp : private member of the device structure, which is a pointer to the 59978c2ecf20Sopenharmony_ci * s2io_nic structure. 59988c2ecf20Sopenharmony_ci * @data:variable that returns the result of each of the test conducted by 59998c2ecf20Sopenharmony_ci * the driver. 60008c2ecf20Sopenharmony_ci * Description: 60018c2ecf20Sopenharmony_ci * This invokes the MemBist test of the card. We give around 60028c2ecf20Sopenharmony_ci * 2 secs time for the Test to complete. If it's still not complete 60038c2ecf20Sopenharmony_ci * within this peiod, we consider that the test failed. 60048c2ecf20Sopenharmony_ci * Return value: 60058c2ecf20Sopenharmony_ci * 0 on success and -1 on failure. 60068c2ecf20Sopenharmony_ci */ 60078c2ecf20Sopenharmony_ci 60088c2ecf20Sopenharmony_cistatic int s2io_bist_test(struct s2io_nic *sp, uint64_t *data) 60098c2ecf20Sopenharmony_ci{ 60108c2ecf20Sopenharmony_ci u8 bist = 0; 60118c2ecf20Sopenharmony_ci int cnt = 0, ret = -1; 60128c2ecf20Sopenharmony_ci 60138c2ecf20Sopenharmony_ci pci_read_config_byte(sp->pdev, PCI_BIST, &bist); 60148c2ecf20Sopenharmony_ci bist |= PCI_BIST_START; 60158c2ecf20Sopenharmony_ci pci_write_config_word(sp->pdev, PCI_BIST, bist); 60168c2ecf20Sopenharmony_ci 60178c2ecf20Sopenharmony_ci while (cnt < 20) { 60188c2ecf20Sopenharmony_ci pci_read_config_byte(sp->pdev, PCI_BIST, &bist); 60198c2ecf20Sopenharmony_ci if (!(bist & PCI_BIST_START)) { 60208c2ecf20Sopenharmony_ci *data = (bist & PCI_BIST_CODE_MASK); 60218c2ecf20Sopenharmony_ci ret = 0; 60228c2ecf20Sopenharmony_ci break; 60238c2ecf20Sopenharmony_ci } 60248c2ecf20Sopenharmony_ci msleep(100); 60258c2ecf20Sopenharmony_ci cnt++; 60268c2ecf20Sopenharmony_ci } 60278c2ecf20Sopenharmony_ci 60288c2ecf20Sopenharmony_ci return ret; 60298c2ecf20Sopenharmony_ci} 60308c2ecf20Sopenharmony_ci 60318c2ecf20Sopenharmony_ci/** 60328c2ecf20Sopenharmony_ci * s2io_link_test - verifies the link state of the nic 60338c2ecf20Sopenharmony_ci * @sp: private member of the device structure, which is a pointer to the 60348c2ecf20Sopenharmony_ci * s2io_nic structure. 60358c2ecf20Sopenharmony_ci * @data: variable that returns the result of each of the test conducted by 60368c2ecf20Sopenharmony_ci * the driver. 60378c2ecf20Sopenharmony_ci * Description: 60388c2ecf20Sopenharmony_ci * The function verifies the link state of the NIC and updates the input 60398c2ecf20Sopenharmony_ci * argument 'data' appropriately. 60408c2ecf20Sopenharmony_ci * Return value: 60418c2ecf20Sopenharmony_ci * 0 on success. 60428c2ecf20Sopenharmony_ci */ 60438c2ecf20Sopenharmony_ci 60448c2ecf20Sopenharmony_cistatic int s2io_link_test(struct s2io_nic *sp, uint64_t *data) 60458c2ecf20Sopenharmony_ci{ 60468c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 60478c2ecf20Sopenharmony_ci u64 val64; 60488c2ecf20Sopenharmony_ci 60498c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_status); 60508c2ecf20Sopenharmony_ci if (!(LINK_IS_UP(val64))) 60518c2ecf20Sopenharmony_ci *data = 1; 60528c2ecf20Sopenharmony_ci else 60538c2ecf20Sopenharmony_ci *data = 0; 60548c2ecf20Sopenharmony_ci 60558c2ecf20Sopenharmony_ci return *data; 60568c2ecf20Sopenharmony_ci} 60578c2ecf20Sopenharmony_ci 60588c2ecf20Sopenharmony_ci/** 60598c2ecf20Sopenharmony_ci * s2io_rldram_test - offline test for access to the RldRam chip on the NIC 60608c2ecf20Sopenharmony_ci * @sp: private member of the device structure, which is a pointer to the 60618c2ecf20Sopenharmony_ci * s2io_nic structure. 60628c2ecf20Sopenharmony_ci * @data: variable that returns the result of each of the test 60638c2ecf20Sopenharmony_ci * conducted by the driver. 60648c2ecf20Sopenharmony_ci * Description: 60658c2ecf20Sopenharmony_ci * This is one of the offline test that tests the read and write 60668c2ecf20Sopenharmony_ci * access to the RldRam chip on the NIC. 60678c2ecf20Sopenharmony_ci * Return value: 60688c2ecf20Sopenharmony_ci * 0 on success. 60698c2ecf20Sopenharmony_ci */ 60708c2ecf20Sopenharmony_ci 60718c2ecf20Sopenharmony_cistatic int s2io_rldram_test(struct s2io_nic *sp, uint64_t *data) 60728c2ecf20Sopenharmony_ci{ 60738c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 60748c2ecf20Sopenharmony_ci u64 val64; 60758c2ecf20Sopenharmony_ci int cnt, iteration = 0, test_fail = 0; 60768c2ecf20Sopenharmony_ci 60778c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_control); 60788c2ecf20Sopenharmony_ci val64 &= ~ADAPTER_ECC_EN; 60798c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 60808c2ecf20Sopenharmony_ci 60818c2ecf20Sopenharmony_ci val64 = readq(&bar0->mc_rldram_test_ctrl); 60828c2ecf20Sopenharmony_ci val64 |= MC_RLDRAM_TEST_MODE; 60838c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); 60848c2ecf20Sopenharmony_ci 60858c2ecf20Sopenharmony_ci val64 = readq(&bar0->mc_rldram_mrs); 60868c2ecf20Sopenharmony_ci val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE; 60878c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF); 60888c2ecf20Sopenharmony_ci 60898c2ecf20Sopenharmony_ci val64 |= MC_RLDRAM_MRS_ENABLE; 60908c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF); 60918c2ecf20Sopenharmony_ci 60928c2ecf20Sopenharmony_ci while (iteration < 2) { 60938c2ecf20Sopenharmony_ci val64 = 0x55555555aaaa0000ULL; 60948c2ecf20Sopenharmony_ci if (iteration == 1) 60958c2ecf20Sopenharmony_ci val64 ^= 0xFFFFFFFFFFFF0000ULL; 60968c2ecf20Sopenharmony_ci writeq(val64, &bar0->mc_rldram_test_d0); 60978c2ecf20Sopenharmony_ci 60988c2ecf20Sopenharmony_ci val64 = 0xaaaa5a5555550000ULL; 60998c2ecf20Sopenharmony_ci if (iteration == 1) 61008c2ecf20Sopenharmony_ci val64 ^= 0xFFFFFFFFFFFF0000ULL; 61018c2ecf20Sopenharmony_ci writeq(val64, &bar0->mc_rldram_test_d1); 61028c2ecf20Sopenharmony_ci 61038c2ecf20Sopenharmony_ci val64 = 0x55aaaaaaaa5a0000ULL; 61048c2ecf20Sopenharmony_ci if (iteration == 1) 61058c2ecf20Sopenharmony_ci val64 ^= 0xFFFFFFFFFFFF0000ULL; 61068c2ecf20Sopenharmony_ci writeq(val64, &bar0->mc_rldram_test_d2); 61078c2ecf20Sopenharmony_ci 61088c2ecf20Sopenharmony_ci val64 = (u64) (0x0000003ffffe0100ULL); 61098c2ecf20Sopenharmony_ci writeq(val64, &bar0->mc_rldram_test_add); 61108c2ecf20Sopenharmony_ci 61118c2ecf20Sopenharmony_ci val64 = MC_RLDRAM_TEST_MODE | 61128c2ecf20Sopenharmony_ci MC_RLDRAM_TEST_WRITE | 61138c2ecf20Sopenharmony_ci MC_RLDRAM_TEST_GO; 61148c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); 61158c2ecf20Sopenharmony_ci 61168c2ecf20Sopenharmony_ci for (cnt = 0; cnt < 5; cnt++) { 61178c2ecf20Sopenharmony_ci val64 = readq(&bar0->mc_rldram_test_ctrl); 61188c2ecf20Sopenharmony_ci if (val64 & MC_RLDRAM_TEST_DONE) 61198c2ecf20Sopenharmony_ci break; 61208c2ecf20Sopenharmony_ci msleep(200); 61218c2ecf20Sopenharmony_ci } 61228c2ecf20Sopenharmony_ci 61238c2ecf20Sopenharmony_ci if (cnt == 5) 61248c2ecf20Sopenharmony_ci break; 61258c2ecf20Sopenharmony_ci 61268c2ecf20Sopenharmony_ci val64 = MC_RLDRAM_TEST_MODE | MC_RLDRAM_TEST_GO; 61278c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_test_ctrl, LF); 61288c2ecf20Sopenharmony_ci 61298c2ecf20Sopenharmony_ci for (cnt = 0; cnt < 5; cnt++) { 61308c2ecf20Sopenharmony_ci val64 = readq(&bar0->mc_rldram_test_ctrl); 61318c2ecf20Sopenharmony_ci if (val64 & MC_RLDRAM_TEST_DONE) 61328c2ecf20Sopenharmony_ci break; 61338c2ecf20Sopenharmony_ci msleep(500); 61348c2ecf20Sopenharmony_ci } 61358c2ecf20Sopenharmony_ci 61368c2ecf20Sopenharmony_ci if (cnt == 5) 61378c2ecf20Sopenharmony_ci break; 61388c2ecf20Sopenharmony_ci 61398c2ecf20Sopenharmony_ci val64 = readq(&bar0->mc_rldram_test_ctrl); 61408c2ecf20Sopenharmony_ci if (!(val64 & MC_RLDRAM_TEST_PASS)) 61418c2ecf20Sopenharmony_ci test_fail = 1; 61428c2ecf20Sopenharmony_ci 61438c2ecf20Sopenharmony_ci iteration++; 61448c2ecf20Sopenharmony_ci } 61458c2ecf20Sopenharmony_ci 61468c2ecf20Sopenharmony_ci *data = test_fail; 61478c2ecf20Sopenharmony_ci 61488c2ecf20Sopenharmony_ci /* Bring the adapter out of test mode */ 61498c2ecf20Sopenharmony_ci SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF); 61508c2ecf20Sopenharmony_ci 61518c2ecf20Sopenharmony_ci return test_fail; 61528c2ecf20Sopenharmony_ci} 61538c2ecf20Sopenharmony_ci 61548c2ecf20Sopenharmony_ci/** 61558c2ecf20Sopenharmony_ci * s2io_ethtool_test - conducts 6 tsets to determine the health of card. 61568c2ecf20Sopenharmony_ci * @dev: pointer to netdev 61578c2ecf20Sopenharmony_ci * @ethtest : pointer to a ethtool command specific structure that will be 61588c2ecf20Sopenharmony_ci * returned to the user. 61598c2ecf20Sopenharmony_ci * @data : variable that returns the result of each of the test 61608c2ecf20Sopenharmony_ci * conducted by the driver. 61618c2ecf20Sopenharmony_ci * Description: 61628c2ecf20Sopenharmony_ci * This function conducts 6 tests ( 4 offline and 2 online) to determine 61638c2ecf20Sopenharmony_ci * the health of the card. 61648c2ecf20Sopenharmony_ci * Return value: 61658c2ecf20Sopenharmony_ci * void 61668c2ecf20Sopenharmony_ci */ 61678c2ecf20Sopenharmony_ci 61688c2ecf20Sopenharmony_cistatic void s2io_ethtool_test(struct net_device *dev, 61698c2ecf20Sopenharmony_ci struct ethtool_test *ethtest, 61708c2ecf20Sopenharmony_ci uint64_t *data) 61718c2ecf20Sopenharmony_ci{ 61728c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 61738c2ecf20Sopenharmony_ci int orig_state = netif_running(sp->dev); 61748c2ecf20Sopenharmony_ci 61758c2ecf20Sopenharmony_ci if (ethtest->flags == ETH_TEST_FL_OFFLINE) { 61768c2ecf20Sopenharmony_ci /* Offline Tests. */ 61778c2ecf20Sopenharmony_ci if (orig_state) 61788c2ecf20Sopenharmony_ci s2io_close(sp->dev); 61798c2ecf20Sopenharmony_ci 61808c2ecf20Sopenharmony_ci if (s2io_register_test(sp, &data[0])) 61818c2ecf20Sopenharmony_ci ethtest->flags |= ETH_TEST_FL_FAILED; 61828c2ecf20Sopenharmony_ci 61838c2ecf20Sopenharmony_ci s2io_reset(sp); 61848c2ecf20Sopenharmony_ci 61858c2ecf20Sopenharmony_ci if (s2io_rldram_test(sp, &data[3])) 61868c2ecf20Sopenharmony_ci ethtest->flags |= ETH_TEST_FL_FAILED; 61878c2ecf20Sopenharmony_ci 61888c2ecf20Sopenharmony_ci s2io_reset(sp); 61898c2ecf20Sopenharmony_ci 61908c2ecf20Sopenharmony_ci if (s2io_eeprom_test(sp, &data[1])) 61918c2ecf20Sopenharmony_ci ethtest->flags |= ETH_TEST_FL_FAILED; 61928c2ecf20Sopenharmony_ci 61938c2ecf20Sopenharmony_ci if (s2io_bist_test(sp, &data[4])) 61948c2ecf20Sopenharmony_ci ethtest->flags |= ETH_TEST_FL_FAILED; 61958c2ecf20Sopenharmony_ci 61968c2ecf20Sopenharmony_ci if (orig_state) 61978c2ecf20Sopenharmony_ci s2io_open(sp->dev); 61988c2ecf20Sopenharmony_ci 61998c2ecf20Sopenharmony_ci data[2] = 0; 62008c2ecf20Sopenharmony_ci } else { 62018c2ecf20Sopenharmony_ci /* Online Tests. */ 62028c2ecf20Sopenharmony_ci if (!orig_state) { 62038c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: is not up, cannot run test\n", 62048c2ecf20Sopenharmony_ci dev->name); 62058c2ecf20Sopenharmony_ci data[0] = -1; 62068c2ecf20Sopenharmony_ci data[1] = -1; 62078c2ecf20Sopenharmony_ci data[2] = -1; 62088c2ecf20Sopenharmony_ci data[3] = -1; 62098c2ecf20Sopenharmony_ci data[4] = -1; 62108c2ecf20Sopenharmony_ci } 62118c2ecf20Sopenharmony_ci 62128c2ecf20Sopenharmony_ci if (s2io_link_test(sp, &data[2])) 62138c2ecf20Sopenharmony_ci ethtest->flags |= ETH_TEST_FL_FAILED; 62148c2ecf20Sopenharmony_ci 62158c2ecf20Sopenharmony_ci data[0] = 0; 62168c2ecf20Sopenharmony_ci data[1] = 0; 62178c2ecf20Sopenharmony_ci data[3] = 0; 62188c2ecf20Sopenharmony_ci data[4] = 0; 62198c2ecf20Sopenharmony_ci } 62208c2ecf20Sopenharmony_ci} 62218c2ecf20Sopenharmony_ci 62228c2ecf20Sopenharmony_cistatic void s2io_get_ethtool_stats(struct net_device *dev, 62238c2ecf20Sopenharmony_ci struct ethtool_stats *estats, 62248c2ecf20Sopenharmony_ci u64 *tmp_stats) 62258c2ecf20Sopenharmony_ci{ 62268c2ecf20Sopenharmony_ci int i = 0, k; 62278c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 62288c2ecf20Sopenharmony_ci struct stat_block *stats = sp->mac_control.stats_info; 62298c2ecf20Sopenharmony_ci struct swStat *swstats = &stats->sw_stat; 62308c2ecf20Sopenharmony_ci struct xpakStat *xstats = &stats->xpak_stat; 62318c2ecf20Sopenharmony_ci 62328c2ecf20Sopenharmony_ci s2io_updt_stats(sp); 62338c2ecf20Sopenharmony_ci tmp_stats[i++] = 62348c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_frms_oflow) << 32 | 62358c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_frms); 62368c2ecf20Sopenharmony_ci tmp_stats[i++] = 62378c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_data_octets_oflow) << 32 | 62388c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_data_octets); 62398c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->tmac_drop_frms); 62408c2ecf20Sopenharmony_ci tmp_stats[i++] = 62418c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_mcst_frms_oflow) << 32 | 62428c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_mcst_frms); 62438c2ecf20Sopenharmony_ci tmp_stats[i++] = 62448c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_bcst_frms_oflow) << 32 | 62458c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_bcst_frms); 62468c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->tmac_pause_ctrl_frms); 62478c2ecf20Sopenharmony_ci tmp_stats[i++] = 62488c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_ttl_octets_oflow) << 32 | 62498c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_ttl_octets); 62508c2ecf20Sopenharmony_ci tmp_stats[i++] = 62518c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_ucst_frms_oflow) << 32 | 62528c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_ucst_frms); 62538c2ecf20Sopenharmony_ci tmp_stats[i++] = 62548c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_nucst_frms_oflow) << 32 | 62558c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_nucst_frms); 62568c2ecf20Sopenharmony_ci tmp_stats[i++] = 62578c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_any_err_frms_oflow) << 32 | 62588c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_any_err_frms); 62598c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->tmac_ttl_less_fb_octets); 62608c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->tmac_vld_ip_octets); 62618c2ecf20Sopenharmony_ci tmp_stats[i++] = 62628c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_vld_ip_oflow) << 32 | 62638c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_vld_ip); 62648c2ecf20Sopenharmony_ci tmp_stats[i++] = 62658c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_drop_ip_oflow) << 32 | 62668c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_drop_ip); 62678c2ecf20Sopenharmony_ci tmp_stats[i++] = 62688c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_icmp_oflow) << 32 | 62698c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_icmp); 62708c2ecf20Sopenharmony_ci tmp_stats[i++] = 62718c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->tmac_rst_tcp_oflow) << 32 | 62728c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_rst_tcp); 62738c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->tmac_tcp); 62748c2ecf20Sopenharmony_ci tmp_stats[i++] = (u64)le32_to_cpu(stats->tmac_udp_oflow) << 32 | 62758c2ecf20Sopenharmony_ci le32_to_cpu(stats->tmac_udp); 62768c2ecf20Sopenharmony_ci tmp_stats[i++] = 62778c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_vld_frms_oflow) << 32 | 62788c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_vld_frms); 62798c2ecf20Sopenharmony_ci tmp_stats[i++] = 62808c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_data_octets_oflow) << 32 | 62818c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_data_octets); 62828c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_fcs_err_frms); 62838c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_drop_frms); 62848c2ecf20Sopenharmony_ci tmp_stats[i++] = 62858c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_vld_mcst_frms_oflow) << 32 | 62868c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_vld_mcst_frms); 62878c2ecf20Sopenharmony_ci tmp_stats[i++] = 62888c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_vld_bcst_frms_oflow) << 32 | 62898c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_vld_bcst_frms); 62908c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rmac_in_rng_len_err_frms); 62918c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rmac_out_rng_len_err_frms); 62928c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_long_frms); 62938c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_pause_ctrl_frms); 62948c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_unsup_ctrl_frms); 62958c2ecf20Sopenharmony_ci tmp_stats[i++] = 62968c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_ttl_octets_oflow) << 32 | 62978c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_ttl_octets); 62988c2ecf20Sopenharmony_ci tmp_stats[i++] = 62998c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_accepted_ucst_frms_oflow) << 32 63008c2ecf20Sopenharmony_ci | le32_to_cpu(stats->rmac_accepted_ucst_frms); 63018c2ecf20Sopenharmony_ci tmp_stats[i++] = 63028c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_accepted_nucst_frms_oflow) 63038c2ecf20Sopenharmony_ci << 32 | le32_to_cpu(stats->rmac_accepted_nucst_frms); 63048c2ecf20Sopenharmony_ci tmp_stats[i++] = 63058c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_discarded_frms_oflow) << 32 | 63068c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_discarded_frms); 63078c2ecf20Sopenharmony_ci tmp_stats[i++] = 63088c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_drop_events_oflow) 63098c2ecf20Sopenharmony_ci << 32 | le32_to_cpu(stats->rmac_drop_events); 63108c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_less_fb_octets); 63118c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_frms); 63128c2ecf20Sopenharmony_ci tmp_stats[i++] = 63138c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_usized_frms_oflow) << 32 | 63148c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_usized_frms); 63158c2ecf20Sopenharmony_ci tmp_stats[i++] = 63168c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_osized_frms_oflow) << 32 | 63178c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_osized_frms); 63188c2ecf20Sopenharmony_ci tmp_stats[i++] = 63198c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_frag_frms_oflow) << 32 | 63208c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_frag_frms); 63218c2ecf20Sopenharmony_ci tmp_stats[i++] = 63228c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_jabber_frms_oflow) << 32 | 63238c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_jabber_frms); 63248c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_64_frms); 63258c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_65_127_frms); 63268c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_128_255_frms); 63278c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_256_511_frms); 63288c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_512_1023_frms); 63298c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_1024_1518_frms); 63308c2ecf20Sopenharmony_ci tmp_stats[i++] = 63318c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_ip_oflow) << 32 | 63328c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_ip); 63338c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_ip_octets); 63348c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rmac_hdr_err_ip); 63358c2ecf20Sopenharmony_ci tmp_stats[i++] = 63368c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_drop_ip_oflow) << 32 | 63378c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_drop_ip); 63388c2ecf20Sopenharmony_ci tmp_stats[i++] = 63398c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_icmp_oflow) << 32 | 63408c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_icmp); 63418c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_tcp); 63428c2ecf20Sopenharmony_ci tmp_stats[i++] = 63438c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_udp_oflow) << 32 | 63448c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_udp); 63458c2ecf20Sopenharmony_ci tmp_stats[i++] = 63468c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_err_drp_udp_oflow) << 32 | 63478c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_err_drp_udp); 63488c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_xgmii_err_sym); 63498c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q0); 63508c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q1); 63518c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q2); 63528c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q3); 63538c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q4); 63548c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q5); 63558c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q6); 63568c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_frms_q7); 63578c2ecf20Sopenharmony_ci tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q0); 63588c2ecf20Sopenharmony_ci tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q1); 63598c2ecf20Sopenharmony_ci tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q2); 63608c2ecf20Sopenharmony_ci tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q3); 63618c2ecf20Sopenharmony_ci tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q4); 63628c2ecf20Sopenharmony_ci tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q5); 63638c2ecf20Sopenharmony_ci tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q6); 63648c2ecf20Sopenharmony_ci tmp_stats[i++] = le16_to_cpu(stats->rmac_full_q7); 63658c2ecf20Sopenharmony_ci tmp_stats[i++] = 63668c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_pause_cnt_oflow) << 32 | 63678c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_pause_cnt); 63688c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_xgmii_data_err_cnt); 63698c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_xgmii_ctrl_err_cnt); 63708c2ecf20Sopenharmony_ci tmp_stats[i++] = 63718c2ecf20Sopenharmony_ci (u64)le32_to_cpu(stats->rmac_accepted_ip_oflow) << 32 | 63728c2ecf20Sopenharmony_ci le32_to_cpu(stats->rmac_accepted_ip); 63738c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rmac_err_tcp); 63748c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rd_req_cnt); 63758c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->new_rd_req_cnt); 63768c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->new_rd_req_rtry_cnt); 63778c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rd_rtry_cnt); 63788c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->wr_rtry_rd_ack_cnt); 63798c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->wr_req_cnt); 63808c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->new_wr_req_cnt); 63818c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->new_wr_req_rtry_cnt); 63828c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->wr_rtry_cnt); 63838c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->wr_disc_cnt); 63848c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rd_rtry_wr_ack_cnt); 63858c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->txp_wr_cnt); 63868c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->txd_rd_cnt); 63878c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->txd_wr_cnt); 63888c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rxd_rd_cnt); 63898c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rxd_wr_cnt); 63908c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->txf_rd_cnt); 63918c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rxf_wr_cnt); 63928c2ecf20Sopenharmony_ci 63938c2ecf20Sopenharmony_ci /* Enhanced statistics exist only for Hercules */ 63948c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_II_DEVICE) { 63958c2ecf20Sopenharmony_ci tmp_stats[i++] = 63968c2ecf20Sopenharmony_ci le64_to_cpu(stats->rmac_ttl_1519_4095_frms); 63978c2ecf20Sopenharmony_ci tmp_stats[i++] = 63988c2ecf20Sopenharmony_ci le64_to_cpu(stats->rmac_ttl_4096_8191_frms); 63998c2ecf20Sopenharmony_ci tmp_stats[i++] = 64008c2ecf20Sopenharmony_ci le64_to_cpu(stats->rmac_ttl_8192_max_frms); 64018c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_ttl_gt_max_frms); 64028c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_osized_alt_frms); 64038c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_jabber_alt_frms); 64048c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_gt_max_alt_frms); 64058c2ecf20Sopenharmony_ci tmp_stats[i++] = le64_to_cpu(stats->rmac_vlan_frms); 64068c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rmac_len_discard); 64078c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rmac_fcs_discard); 64088c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rmac_pf_discard); 64098c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rmac_da_discard); 64108c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rmac_red_discard); 64118c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rmac_rts_discard); 64128c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->rmac_ingm_full_discard); 64138c2ecf20Sopenharmony_ci tmp_stats[i++] = le32_to_cpu(stats->link_fault_cnt); 64148c2ecf20Sopenharmony_ci } 64158c2ecf20Sopenharmony_ci 64168c2ecf20Sopenharmony_ci tmp_stats[i++] = 0; 64178c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->single_ecc_errs; 64188c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->double_ecc_errs; 64198c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->parity_err_cnt; 64208c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->serious_err_cnt; 64218c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->soft_reset_cnt; 64228c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->fifo_full_cnt; 64238c2ecf20Sopenharmony_ci for (k = 0; k < MAX_RX_RINGS; k++) 64248c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->ring_full_cnt[k]; 64258c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->alarm_transceiver_temp_high; 64268c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->alarm_transceiver_temp_low; 64278c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->alarm_laser_bias_current_high; 64288c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->alarm_laser_bias_current_low; 64298c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->alarm_laser_output_power_high; 64308c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->alarm_laser_output_power_low; 64318c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->warn_transceiver_temp_high; 64328c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->warn_transceiver_temp_low; 64338c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->warn_laser_bias_current_high; 64348c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->warn_laser_bias_current_low; 64358c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->warn_laser_output_power_high; 64368c2ecf20Sopenharmony_ci tmp_stats[i++] = xstats->warn_laser_output_power_low; 64378c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->clubbed_frms_cnt; 64388c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->sending_both; 64398c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->outof_sequence_pkts; 64408c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->flush_max_pkts; 64418c2ecf20Sopenharmony_ci if (swstats->num_aggregations) { 64428c2ecf20Sopenharmony_ci u64 tmp = swstats->sum_avg_pkts_aggregated; 64438c2ecf20Sopenharmony_ci int count = 0; 64448c2ecf20Sopenharmony_ci /* 64458c2ecf20Sopenharmony_ci * Since 64-bit divide does not work on all platforms, 64468c2ecf20Sopenharmony_ci * do repeated subtraction. 64478c2ecf20Sopenharmony_ci */ 64488c2ecf20Sopenharmony_ci while (tmp >= swstats->num_aggregations) { 64498c2ecf20Sopenharmony_ci tmp -= swstats->num_aggregations; 64508c2ecf20Sopenharmony_ci count++; 64518c2ecf20Sopenharmony_ci } 64528c2ecf20Sopenharmony_ci tmp_stats[i++] = count; 64538c2ecf20Sopenharmony_ci } else 64548c2ecf20Sopenharmony_ci tmp_stats[i++] = 0; 64558c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->mem_alloc_fail_cnt; 64568c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->pci_map_fail_cnt; 64578c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->watchdog_timer_cnt; 64588c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->mem_allocated; 64598c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->mem_freed; 64608c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->link_up_cnt; 64618c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->link_down_cnt; 64628c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->link_up_time; 64638c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->link_down_time; 64648c2ecf20Sopenharmony_ci 64658c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->tx_buf_abort_cnt; 64668c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->tx_desc_abort_cnt; 64678c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->tx_parity_err_cnt; 64688c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->tx_link_loss_cnt; 64698c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->tx_list_proc_err_cnt; 64708c2ecf20Sopenharmony_ci 64718c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rx_parity_err_cnt; 64728c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rx_abort_cnt; 64738c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rx_parity_abort_cnt; 64748c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rx_rda_fail_cnt; 64758c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rx_unkn_prot_cnt; 64768c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rx_fcs_err_cnt; 64778c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rx_buf_size_err_cnt; 64788c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rx_rxd_corrupt_cnt; 64798c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rx_unkn_err_cnt; 64808c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->tda_err_cnt; 64818c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->pfc_err_cnt; 64828c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->pcc_err_cnt; 64838c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->tti_err_cnt; 64848c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->tpa_err_cnt; 64858c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->sm_err_cnt; 64868c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->lso_err_cnt; 64878c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->mac_tmac_err_cnt; 64888c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->mac_rmac_err_cnt; 64898c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->xgxs_txgxs_err_cnt; 64908c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->xgxs_rxgxs_err_cnt; 64918c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rc_err_cnt; 64928c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->prc_pcix_err_cnt; 64938c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rpa_err_cnt; 64948c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rda_err_cnt; 64958c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->rti_err_cnt; 64968c2ecf20Sopenharmony_ci tmp_stats[i++] = swstats->mc_err_cnt; 64978c2ecf20Sopenharmony_ci} 64988c2ecf20Sopenharmony_ci 64998c2ecf20Sopenharmony_cistatic int s2io_ethtool_get_regs_len(struct net_device *dev) 65008c2ecf20Sopenharmony_ci{ 65018c2ecf20Sopenharmony_ci return XENA_REG_SPACE; 65028c2ecf20Sopenharmony_ci} 65038c2ecf20Sopenharmony_ci 65048c2ecf20Sopenharmony_ci 65058c2ecf20Sopenharmony_cistatic int s2io_get_eeprom_len(struct net_device *dev) 65068c2ecf20Sopenharmony_ci{ 65078c2ecf20Sopenharmony_ci return XENA_EEPROM_SPACE; 65088c2ecf20Sopenharmony_ci} 65098c2ecf20Sopenharmony_ci 65108c2ecf20Sopenharmony_cistatic int s2io_get_sset_count(struct net_device *dev, int sset) 65118c2ecf20Sopenharmony_ci{ 65128c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 65138c2ecf20Sopenharmony_ci 65148c2ecf20Sopenharmony_ci switch (sset) { 65158c2ecf20Sopenharmony_ci case ETH_SS_TEST: 65168c2ecf20Sopenharmony_ci return S2IO_TEST_LEN; 65178c2ecf20Sopenharmony_ci case ETH_SS_STATS: 65188c2ecf20Sopenharmony_ci switch (sp->device_type) { 65198c2ecf20Sopenharmony_ci case XFRAME_I_DEVICE: 65208c2ecf20Sopenharmony_ci return XFRAME_I_STAT_LEN; 65218c2ecf20Sopenharmony_ci case XFRAME_II_DEVICE: 65228c2ecf20Sopenharmony_ci return XFRAME_II_STAT_LEN; 65238c2ecf20Sopenharmony_ci default: 65248c2ecf20Sopenharmony_ci return 0; 65258c2ecf20Sopenharmony_ci } 65268c2ecf20Sopenharmony_ci default: 65278c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 65288c2ecf20Sopenharmony_ci } 65298c2ecf20Sopenharmony_ci} 65308c2ecf20Sopenharmony_ci 65318c2ecf20Sopenharmony_cistatic void s2io_ethtool_get_strings(struct net_device *dev, 65328c2ecf20Sopenharmony_ci u32 stringset, u8 *data) 65338c2ecf20Sopenharmony_ci{ 65348c2ecf20Sopenharmony_ci int stat_size = 0; 65358c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 65368c2ecf20Sopenharmony_ci 65378c2ecf20Sopenharmony_ci switch (stringset) { 65388c2ecf20Sopenharmony_ci case ETH_SS_TEST: 65398c2ecf20Sopenharmony_ci memcpy(data, s2io_gstrings, S2IO_STRINGS_LEN); 65408c2ecf20Sopenharmony_ci break; 65418c2ecf20Sopenharmony_ci case ETH_SS_STATS: 65428c2ecf20Sopenharmony_ci stat_size = sizeof(ethtool_xena_stats_keys); 65438c2ecf20Sopenharmony_ci memcpy(data, ðtool_xena_stats_keys, stat_size); 65448c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_II_DEVICE) { 65458c2ecf20Sopenharmony_ci memcpy(data + stat_size, 65468c2ecf20Sopenharmony_ci ðtool_enhanced_stats_keys, 65478c2ecf20Sopenharmony_ci sizeof(ethtool_enhanced_stats_keys)); 65488c2ecf20Sopenharmony_ci stat_size += sizeof(ethtool_enhanced_stats_keys); 65498c2ecf20Sopenharmony_ci } 65508c2ecf20Sopenharmony_ci 65518c2ecf20Sopenharmony_ci memcpy(data + stat_size, ðtool_driver_stats_keys, 65528c2ecf20Sopenharmony_ci sizeof(ethtool_driver_stats_keys)); 65538c2ecf20Sopenharmony_ci } 65548c2ecf20Sopenharmony_ci} 65558c2ecf20Sopenharmony_ci 65568c2ecf20Sopenharmony_cistatic int s2io_set_features(struct net_device *dev, netdev_features_t features) 65578c2ecf20Sopenharmony_ci{ 65588c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 65598c2ecf20Sopenharmony_ci netdev_features_t changed = (features ^ dev->features) & NETIF_F_LRO; 65608c2ecf20Sopenharmony_ci 65618c2ecf20Sopenharmony_ci if (changed && netif_running(dev)) { 65628c2ecf20Sopenharmony_ci int rc; 65638c2ecf20Sopenharmony_ci 65648c2ecf20Sopenharmony_ci s2io_stop_all_tx_queue(sp); 65658c2ecf20Sopenharmony_ci s2io_card_down(sp); 65668c2ecf20Sopenharmony_ci dev->features = features; 65678c2ecf20Sopenharmony_ci rc = s2io_card_up(sp); 65688c2ecf20Sopenharmony_ci if (rc) 65698c2ecf20Sopenharmony_ci s2io_reset(sp); 65708c2ecf20Sopenharmony_ci else 65718c2ecf20Sopenharmony_ci s2io_start_all_tx_queue(sp); 65728c2ecf20Sopenharmony_ci 65738c2ecf20Sopenharmony_ci return rc ? rc : 1; 65748c2ecf20Sopenharmony_ci } 65758c2ecf20Sopenharmony_ci 65768c2ecf20Sopenharmony_ci return 0; 65778c2ecf20Sopenharmony_ci} 65788c2ecf20Sopenharmony_ci 65798c2ecf20Sopenharmony_cistatic const struct ethtool_ops netdev_ethtool_ops = { 65808c2ecf20Sopenharmony_ci .get_drvinfo = s2io_ethtool_gdrvinfo, 65818c2ecf20Sopenharmony_ci .get_regs_len = s2io_ethtool_get_regs_len, 65828c2ecf20Sopenharmony_ci .get_regs = s2io_ethtool_gregs, 65838c2ecf20Sopenharmony_ci .get_link = ethtool_op_get_link, 65848c2ecf20Sopenharmony_ci .get_eeprom_len = s2io_get_eeprom_len, 65858c2ecf20Sopenharmony_ci .get_eeprom = s2io_ethtool_geeprom, 65868c2ecf20Sopenharmony_ci .set_eeprom = s2io_ethtool_seeprom, 65878c2ecf20Sopenharmony_ci .get_ringparam = s2io_ethtool_gringparam, 65888c2ecf20Sopenharmony_ci .get_pauseparam = s2io_ethtool_getpause_data, 65898c2ecf20Sopenharmony_ci .set_pauseparam = s2io_ethtool_setpause_data, 65908c2ecf20Sopenharmony_ci .self_test = s2io_ethtool_test, 65918c2ecf20Sopenharmony_ci .get_strings = s2io_ethtool_get_strings, 65928c2ecf20Sopenharmony_ci .set_phys_id = s2io_ethtool_set_led, 65938c2ecf20Sopenharmony_ci .get_ethtool_stats = s2io_get_ethtool_stats, 65948c2ecf20Sopenharmony_ci .get_sset_count = s2io_get_sset_count, 65958c2ecf20Sopenharmony_ci .get_link_ksettings = s2io_ethtool_get_link_ksettings, 65968c2ecf20Sopenharmony_ci .set_link_ksettings = s2io_ethtool_set_link_ksettings, 65978c2ecf20Sopenharmony_ci}; 65988c2ecf20Sopenharmony_ci 65998c2ecf20Sopenharmony_ci/** 66008c2ecf20Sopenharmony_ci * s2io_ioctl - Entry point for the Ioctl 66018c2ecf20Sopenharmony_ci * @dev : Device pointer. 66028c2ecf20Sopenharmony_ci * @rq : An IOCTL specefic structure, that can contain a pointer to 66038c2ecf20Sopenharmony_ci * a proprietary structure used to pass information to the driver. 66048c2ecf20Sopenharmony_ci * @cmd : This is used to distinguish between the different commands that 66058c2ecf20Sopenharmony_ci * can be passed to the IOCTL functions. 66068c2ecf20Sopenharmony_ci * Description: 66078c2ecf20Sopenharmony_ci * Currently there are no special functionality supported in IOCTL, hence 66088c2ecf20Sopenharmony_ci * function always return EOPNOTSUPPORTED 66098c2ecf20Sopenharmony_ci */ 66108c2ecf20Sopenharmony_ci 66118c2ecf20Sopenharmony_cistatic int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 66128c2ecf20Sopenharmony_ci{ 66138c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 66148c2ecf20Sopenharmony_ci} 66158c2ecf20Sopenharmony_ci 66168c2ecf20Sopenharmony_ci/** 66178c2ecf20Sopenharmony_ci * s2io_change_mtu - entry point to change MTU size for the device. 66188c2ecf20Sopenharmony_ci * @dev : device pointer. 66198c2ecf20Sopenharmony_ci * @new_mtu : the new MTU size for the device. 66208c2ecf20Sopenharmony_ci * Description: A driver entry point to change MTU size for the device. 66218c2ecf20Sopenharmony_ci * Before changing the MTU the device must be stopped. 66228c2ecf20Sopenharmony_ci * Return value: 66238c2ecf20Sopenharmony_ci * 0 on success and an appropriate (-)ve integer as defined in errno.h 66248c2ecf20Sopenharmony_ci * file on failure. 66258c2ecf20Sopenharmony_ci */ 66268c2ecf20Sopenharmony_ci 66278c2ecf20Sopenharmony_cistatic int s2io_change_mtu(struct net_device *dev, int new_mtu) 66288c2ecf20Sopenharmony_ci{ 66298c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 66308c2ecf20Sopenharmony_ci int ret = 0; 66318c2ecf20Sopenharmony_ci 66328c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 66338c2ecf20Sopenharmony_ci if (netif_running(dev)) { 66348c2ecf20Sopenharmony_ci s2io_stop_all_tx_queue(sp); 66358c2ecf20Sopenharmony_ci s2io_card_down(sp); 66368c2ecf20Sopenharmony_ci ret = s2io_card_up(sp); 66378c2ecf20Sopenharmony_ci if (ret) { 66388c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n", 66398c2ecf20Sopenharmony_ci __func__); 66408c2ecf20Sopenharmony_ci return ret; 66418c2ecf20Sopenharmony_ci } 66428c2ecf20Sopenharmony_ci s2io_wake_all_tx_queue(sp); 66438c2ecf20Sopenharmony_ci } else { /* Device is down */ 66448c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 66458c2ecf20Sopenharmony_ci u64 val64 = new_mtu; 66468c2ecf20Sopenharmony_ci 66478c2ecf20Sopenharmony_ci writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len); 66488c2ecf20Sopenharmony_ci } 66498c2ecf20Sopenharmony_ci 66508c2ecf20Sopenharmony_ci return ret; 66518c2ecf20Sopenharmony_ci} 66528c2ecf20Sopenharmony_ci 66538c2ecf20Sopenharmony_ci/** 66548c2ecf20Sopenharmony_ci * s2io_set_link - Set the LInk status 66558c2ecf20Sopenharmony_ci * @work: work struct containing a pointer to device private structue 66568c2ecf20Sopenharmony_ci * Description: Sets the link status for the adapter 66578c2ecf20Sopenharmony_ci */ 66588c2ecf20Sopenharmony_ci 66598c2ecf20Sopenharmony_cistatic void s2io_set_link(struct work_struct *work) 66608c2ecf20Sopenharmony_ci{ 66618c2ecf20Sopenharmony_ci struct s2io_nic *nic = container_of(work, struct s2io_nic, 66628c2ecf20Sopenharmony_ci set_link_task); 66638c2ecf20Sopenharmony_ci struct net_device *dev = nic->dev; 66648c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 66658c2ecf20Sopenharmony_ci register u64 val64; 66668c2ecf20Sopenharmony_ci u16 subid; 66678c2ecf20Sopenharmony_ci 66688c2ecf20Sopenharmony_ci rtnl_lock(); 66698c2ecf20Sopenharmony_ci 66708c2ecf20Sopenharmony_ci if (!netif_running(dev)) 66718c2ecf20Sopenharmony_ci goto out_unlock; 66728c2ecf20Sopenharmony_ci 66738c2ecf20Sopenharmony_ci if (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(nic->state))) { 66748c2ecf20Sopenharmony_ci /* The card is being reset, no point doing anything */ 66758c2ecf20Sopenharmony_ci goto out_unlock; 66768c2ecf20Sopenharmony_ci } 66778c2ecf20Sopenharmony_ci 66788c2ecf20Sopenharmony_ci subid = nic->pdev->subsystem_device; 66798c2ecf20Sopenharmony_ci if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { 66808c2ecf20Sopenharmony_ci /* 66818c2ecf20Sopenharmony_ci * Allow a small delay for the NICs self initiated 66828c2ecf20Sopenharmony_ci * cleanup to complete. 66838c2ecf20Sopenharmony_ci */ 66848c2ecf20Sopenharmony_ci msleep(100); 66858c2ecf20Sopenharmony_ci } 66868c2ecf20Sopenharmony_ci 66878c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_status); 66888c2ecf20Sopenharmony_ci if (LINK_IS_UP(val64)) { 66898c2ecf20Sopenharmony_ci if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) { 66908c2ecf20Sopenharmony_ci if (verify_xena_quiescence(nic)) { 66918c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_control); 66928c2ecf20Sopenharmony_ci val64 |= ADAPTER_CNTL_EN; 66938c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 66948c2ecf20Sopenharmony_ci if (CARDS_WITH_FAULTY_LINK_INDICATORS( 66958c2ecf20Sopenharmony_ci nic->device_type, subid)) { 66968c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_control); 66978c2ecf20Sopenharmony_ci val64 |= GPIO_CTRL_GPIO_0; 66988c2ecf20Sopenharmony_ci writeq(val64, &bar0->gpio_control); 66998c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_control); 67008c2ecf20Sopenharmony_ci } else { 67018c2ecf20Sopenharmony_ci val64 |= ADAPTER_LED_ON; 67028c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 67038c2ecf20Sopenharmony_ci } 67048c2ecf20Sopenharmony_ci nic->device_enabled_once = true; 67058c2ecf20Sopenharmony_ci } else { 67068c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 67078c2ecf20Sopenharmony_ci "%s: Error: device is not Quiescent\n", 67088c2ecf20Sopenharmony_ci dev->name); 67098c2ecf20Sopenharmony_ci s2io_stop_all_tx_queue(nic); 67108c2ecf20Sopenharmony_ci } 67118c2ecf20Sopenharmony_ci } 67128c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_control); 67138c2ecf20Sopenharmony_ci val64 |= ADAPTER_LED_ON; 67148c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 67158c2ecf20Sopenharmony_ci s2io_link(nic, LINK_UP); 67168c2ecf20Sopenharmony_ci } else { 67178c2ecf20Sopenharmony_ci if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type, 67188c2ecf20Sopenharmony_ci subid)) { 67198c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_control); 67208c2ecf20Sopenharmony_ci val64 &= ~GPIO_CTRL_GPIO_0; 67218c2ecf20Sopenharmony_ci writeq(val64, &bar0->gpio_control); 67228c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_control); 67238c2ecf20Sopenharmony_ci } 67248c2ecf20Sopenharmony_ci /* turn off LED */ 67258c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_control); 67268c2ecf20Sopenharmony_ci val64 = val64 & (~ADAPTER_LED_ON); 67278c2ecf20Sopenharmony_ci writeq(val64, &bar0->adapter_control); 67288c2ecf20Sopenharmony_ci s2io_link(nic, LINK_DOWN); 67298c2ecf20Sopenharmony_ci } 67308c2ecf20Sopenharmony_ci clear_bit(__S2IO_STATE_LINK_TASK, &(nic->state)); 67318c2ecf20Sopenharmony_ci 67328c2ecf20Sopenharmony_ciout_unlock: 67338c2ecf20Sopenharmony_ci rtnl_unlock(); 67348c2ecf20Sopenharmony_ci} 67358c2ecf20Sopenharmony_ci 67368c2ecf20Sopenharmony_cistatic int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, 67378c2ecf20Sopenharmony_ci struct buffAdd *ba, 67388c2ecf20Sopenharmony_ci struct sk_buff **skb, u64 *temp0, u64 *temp1, 67398c2ecf20Sopenharmony_ci u64 *temp2, int size) 67408c2ecf20Sopenharmony_ci{ 67418c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 67428c2ecf20Sopenharmony_ci struct swStat *stats = &sp->mac_control.stats_info->sw_stat; 67438c2ecf20Sopenharmony_ci 67448c2ecf20Sopenharmony_ci if ((sp->rxd_mode == RXD_MODE_1) && (rxdp->Host_Control == 0)) { 67458c2ecf20Sopenharmony_ci struct RxD1 *rxdp1 = (struct RxD1 *)rxdp; 67468c2ecf20Sopenharmony_ci /* allocate skb */ 67478c2ecf20Sopenharmony_ci if (*skb) { 67488c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "SKB is not NULL\n"); 67498c2ecf20Sopenharmony_ci /* 67508c2ecf20Sopenharmony_ci * As Rx frame are not going to be processed, 67518c2ecf20Sopenharmony_ci * using same mapped address for the Rxd 67528c2ecf20Sopenharmony_ci * buffer pointer 67538c2ecf20Sopenharmony_ci */ 67548c2ecf20Sopenharmony_ci rxdp1->Buffer0_ptr = *temp0; 67558c2ecf20Sopenharmony_ci } else { 67568c2ecf20Sopenharmony_ci *skb = netdev_alloc_skb(dev, size); 67578c2ecf20Sopenharmony_ci if (!(*skb)) { 67588c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, 67598c2ecf20Sopenharmony_ci "%s: Out of memory to allocate %s\n", 67608c2ecf20Sopenharmony_ci dev->name, "1 buf mode SKBs"); 67618c2ecf20Sopenharmony_ci stats->mem_alloc_fail_cnt++; 67628c2ecf20Sopenharmony_ci return -ENOMEM ; 67638c2ecf20Sopenharmony_ci } 67648c2ecf20Sopenharmony_ci stats->mem_allocated += (*skb)->truesize; 67658c2ecf20Sopenharmony_ci /* storing the mapped addr in a temp variable 67668c2ecf20Sopenharmony_ci * such it will be used for next rxd whose 67678c2ecf20Sopenharmony_ci * Host Control is NULL 67688c2ecf20Sopenharmony_ci */ 67698c2ecf20Sopenharmony_ci rxdp1->Buffer0_ptr = *temp0 = 67708c2ecf20Sopenharmony_ci dma_map_single(&sp->pdev->dev, (*skb)->data, 67718c2ecf20Sopenharmony_ci size - NET_IP_ALIGN, 67728c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 67738c2ecf20Sopenharmony_ci if (dma_mapping_error(&sp->pdev->dev, rxdp1->Buffer0_ptr)) 67748c2ecf20Sopenharmony_ci goto memalloc_failed; 67758c2ecf20Sopenharmony_ci rxdp->Host_Control = (unsigned long) (*skb); 67768c2ecf20Sopenharmony_ci } 67778c2ecf20Sopenharmony_ci } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) { 67788c2ecf20Sopenharmony_ci struct RxD3 *rxdp3 = (struct RxD3 *)rxdp; 67798c2ecf20Sopenharmony_ci /* Two buffer Mode */ 67808c2ecf20Sopenharmony_ci if (*skb) { 67818c2ecf20Sopenharmony_ci rxdp3->Buffer2_ptr = *temp2; 67828c2ecf20Sopenharmony_ci rxdp3->Buffer0_ptr = *temp0; 67838c2ecf20Sopenharmony_ci rxdp3->Buffer1_ptr = *temp1; 67848c2ecf20Sopenharmony_ci } else { 67858c2ecf20Sopenharmony_ci *skb = netdev_alloc_skb(dev, size); 67868c2ecf20Sopenharmony_ci if (!(*skb)) { 67878c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, 67888c2ecf20Sopenharmony_ci "%s: Out of memory to allocate %s\n", 67898c2ecf20Sopenharmony_ci dev->name, 67908c2ecf20Sopenharmony_ci "2 buf mode SKBs"); 67918c2ecf20Sopenharmony_ci stats->mem_alloc_fail_cnt++; 67928c2ecf20Sopenharmony_ci return -ENOMEM; 67938c2ecf20Sopenharmony_ci } 67948c2ecf20Sopenharmony_ci stats->mem_allocated += (*skb)->truesize; 67958c2ecf20Sopenharmony_ci rxdp3->Buffer2_ptr = *temp2 = 67968c2ecf20Sopenharmony_ci dma_map_single(&sp->pdev->dev, (*skb)->data, 67978c2ecf20Sopenharmony_ci dev->mtu + 4, DMA_FROM_DEVICE); 67988c2ecf20Sopenharmony_ci if (dma_mapping_error(&sp->pdev->dev, rxdp3->Buffer2_ptr)) 67998c2ecf20Sopenharmony_ci goto memalloc_failed; 68008c2ecf20Sopenharmony_ci rxdp3->Buffer0_ptr = *temp0 = 68018c2ecf20Sopenharmony_ci dma_map_single(&sp->pdev->dev, ba->ba_0, 68028c2ecf20Sopenharmony_ci BUF0_LEN, DMA_FROM_DEVICE); 68038c2ecf20Sopenharmony_ci if (dma_mapping_error(&sp->pdev->dev, rxdp3->Buffer0_ptr)) { 68048c2ecf20Sopenharmony_ci dma_unmap_single(&sp->pdev->dev, 68058c2ecf20Sopenharmony_ci (dma_addr_t)rxdp3->Buffer2_ptr, 68068c2ecf20Sopenharmony_ci dev->mtu + 4, 68078c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 68088c2ecf20Sopenharmony_ci goto memalloc_failed; 68098c2ecf20Sopenharmony_ci } 68108c2ecf20Sopenharmony_ci rxdp->Host_Control = (unsigned long) (*skb); 68118c2ecf20Sopenharmony_ci 68128c2ecf20Sopenharmony_ci /* Buffer-1 will be dummy buffer not used */ 68138c2ecf20Sopenharmony_ci rxdp3->Buffer1_ptr = *temp1 = 68148c2ecf20Sopenharmony_ci dma_map_single(&sp->pdev->dev, ba->ba_1, 68158c2ecf20Sopenharmony_ci BUF1_LEN, DMA_FROM_DEVICE); 68168c2ecf20Sopenharmony_ci if (dma_mapping_error(&sp->pdev->dev, rxdp3->Buffer1_ptr)) { 68178c2ecf20Sopenharmony_ci dma_unmap_single(&sp->pdev->dev, 68188c2ecf20Sopenharmony_ci (dma_addr_t)rxdp3->Buffer0_ptr, 68198c2ecf20Sopenharmony_ci BUF0_LEN, DMA_FROM_DEVICE); 68208c2ecf20Sopenharmony_ci dma_unmap_single(&sp->pdev->dev, 68218c2ecf20Sopenharmony_ci (dma_addr_t)rxdp3->Buffer2_ptr, 68228c2ecf20Sopenharmony_ci dev->mtu + 4, 68238c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 68248c2ecf20Sopenharmony_ci goto memalloc_failed; 68258c2ecf20Sopenharmony_ci } 68268c2ecf20Sopenharmony_ci } 68278c2ecf20Sopenharmony_ci } 68288c2ecf20Sopenharmony_ci return 0; 68298c2ecf20Sopenharmony_ci 68308c2ecf20Sopenharmony_cimemalloc_failed: 68318c2ecf20Sopenharmony_ci stats->pci_map_fail_cnt++; 68328c2ecf20Sopenharmony_ci stats->mem_freed += (*skb)->truesize; 68338c2ecf20Sopenharmony_ci dev_kfree_skb(*skb); 68348c2ecf20Sopenharmony_ci return -ENOMEM; 68358c2ecf20Sopenharmony_ci} 68368c2ecf20Sopenharmony_ci 68378c2ecf20Sopenharmony_cistatic void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp, 68388c2ecf20Sopenharmony_ci int size) 68398c2ecf20Sopenharmony_ci{ 68408c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 68418c2ecf20Sopenharmony_ci if (sp->rxd_mode == RXD_MODE_1) { 68428c2ecf20Sopenharmony_ci rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN); 68438c2ecf20Sopenharmony_ci } else if (sp->rxd_mode == RXD_MODE_3B) { 68448c2ecf20Sopenharmony_ci rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN); 68458c2ecf20Sopenharmony_ci rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1); 68468c2ecf20Sopenharmony_ci rxdp->Control_2 |= SET_BUFFER2_SIZE_3(dev->mtu + 4); 68478c2ecf20Sopenharmony_ci } 68488c2ecf20Sopenharmony_ci} 68498c2ecf20Sopenharmony_ci 68508c2ecf20Sopenharmony_cistatic int rxd_owner_bit_reset(struct s2io_nic *sp) 68518c2ecf20Sopenharmony_ci{ 68528c2ecf20Sopenharmony_ci int i, j, k, blk_cnt = 0, size; 68538c2ecf20Sopenharmony_ci struct config_param *config = &sp->config; 68548c2ecf20Sopenharmony_ci struct mac_info *mac_control = &sp->mac_control; 68558c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 68568c2ecf20Sopenharmony_ci struct RxD_t *rxdp = NULL; 68578c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 68588c2ecf20Sopenharmony_ci struct buffAdd *ba = NULL; 68598c2ecf20Sopenharmony_ci u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0; 68608c2ecf20Sopenharmony_ci 68618c2ecf20Sopenharmony_ci /* Calculate the size based on ring mode */ 68628c2ecf20Sopenharmony_ci size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE + 68638c2ecf20Sopenharmony_ci HEADER_802_2_SIZE + HEADER_SNAP_SIZE; 68648c2ecf20Sopenharmony_ci if (sp->rxd_mode == RXD_MODE_1) 68658c2ecf20Sopenharmony_ci size += NET_IP_ALIGN; 68668c2ecf20Sopenharmony_ci else if (sp->rxd_mode == RXD_MODE_3B) 68678c2ecf20Sopenharmony_ci size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4; 68688c2ecf20Sopenharmony_ci 68698c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 68708c2ecf20Sopenharmony_ci struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; 68718c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 68728c2ecf20Sopenharmony_ci 68738c2ecf20Sopenharmony_ci blk_cnt = rx_cfg->num_rxd / (rxd_count[sp->rxd_mode] + 1); 68748c2ecf20Sopenharmony_ci 68758c2ecf20Sopenharmony_ci for (j = 0; j < blk_cnt; j++) { 68768c2ecf20Sopenharmony_ci for (k = 0; k < rxd_count[sp->rxd_mode]; k++) { 68778c2ecf20Sopenharmony_ci rxdp = ring->rx_blocks[j].rxds[k].virt_addr; 68788c2ecf20Sopenharmony_ci if (sp->rxd_mode == RXD_MODE_3B) 68798c2ecf20Sopenharmony_ci ba = &ring->ba[j][k]; 68808c2ecf20Sopenharmony_ci if (set_rxd_buffer_pointer(sp, rxdp, ba, &skb, 68818c2ecf20Sopenharmony_ci &temp0_64, 68828c2ecf20Sopenharmony_ci &temp1_64, 68838c2ecf20Sopenharmony_ci &temp2_64, 68848c2ecf20Sopenharmony_ci size) == -ENOMEM) { 68858c2ecf20Sopenharmony_ci return 0; 68868c2ecf20Sopenharmony_ci } 68878c2ecf20Sopenharmony_ci 68888c2ecf20Sopenharmony_ci set_rxd_buffer_size(sp, rxdp, size); 68898c2ecf20Sopenharmony_ci dma_wmb(); 68908c2ecf20Sopenharmony_ci /* flip the Ownership bit to Hardware */ 68918c2ecf20Sopenharmony_ci rxdp->Control_1 |= RXD_OWN_XENA; 68928c2ecf20Sopenharmony_ci } 68938c2ecf20Sopenharmony_ci } 68948c2ecf20Sopenharmony_ci } 68958c2ecf20Sopenharmony_ci return 0; 68968c2ecf20Sopenharmony_ci 68978c2ecf20Sopenharmony_ci} 68988c2ecf20Sopenharmony_ci 68998c2ecf20Sopenharmony_cistatic int s2io_add_isr(struct s2io_nic *sp) 69008c2ecf20Sopenharmony_ci{ 69018c2ecf20Sopenharmony_ci int ret = 0; 69028c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 69038c2ecf20Sopenharmony_ci int err = 0; 69048c2ecf20Sopenharmony_ci 69058c2ecf20Sopenharmony_ci if (sp->config.intr_type == MSI_X) 69068c2ecf20Sopenharmony_ci ret = s2io_enable_msi_x(sp); 69078c2ecf20Sopenharmony_ci if (ret) { 69088c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name); 69098c2ecf20Sopenharmony_ci sp->config.intr_type = INTA; 69108c2ecf20Sopenharmony_ci } 69118c2ecf20Sopenharmony_ci 69128c2ecf20Sopenharmony_ci /* 69138c2ecf20Sopenharmony_ci * Store the values of the MSIX table in 69148c2ecf20Sopenharmony_ci * the struct s2io_nic structure 69158c2ecf20Sopenharmony_ci */ 69168c2ecf20Sopenharmony_ci store_xmsi_data(sp); 69178c2ecf20Sopenharmony_ci 69188c2ecf20Sopenharmony_ci /* After proper initialization of H/W, register ISR */ 69198c2ecf20Sopenharmony_ci if (sp->config.intr_type == MSI_X) { 69208c2ecf20Sopenharmony_ci int i, msix_rx_cnt = 0; 69218c2ecf20Sopenharmony_ci 69228c2ecf20Sopenharmony_ci for (i = 0; i < sp->num_entries; i++) { 69238c2ecf20Sopenharmony_ci if (sp->s2io_entries[i].in_use == MSIX_FLG) { 69248c2ecf20Sopenharmony_ci if (sp->s2io_entries[i].type == 69258c2ecf20Sopenharmony_ci MSIX_RING_TYPE) { 69268c2ecf20Sopenharmony_ci snprintf(sp->desc[i], 69278c2ecf20Sopenharmony_ci sizeof(sp->desc[i]), 69288c2ecf20Sopenharmony_ci "%s:MSI-X-%d-RX", 69298c2ecf20Sopenharmony_ci dev->name, i); 69308c2ecf20Sopenharmony_ci err = request_irq(sp->entries[i].vector, 69318c2ecf20Sopenharmony_ci s2io_msix_ring_handle, 69328c2ecf20Sopenharmony_ci 0, 69338c2ecf20Sopenharmony_ci sp->desc[i], 69348c2ecf20Sopenharmony_ci sp->s2io_entries[i].arg); 69358c2ecf20Sopenharmony_ci } else if (sp->s2io_entries[i].type == 69368c2ecf20Sopenharmony_ci MSIX_ALARM_TYPE) { 69378c2ecf20Sopenharmony_ci snprintf(sp->desc[i], 69388c2ecf20Sopenharmony_ci sizeof(sp->desc[i]), 69398c2ecf20Sopenharmony_ci "%s:MSI-X-%d-TX", 69408c2ecf20Sopenharmony_ci dev->name, i); 69418c2ecf20Sopenharmony_ci err = request_irq(sp->entries[i].vector, 69428c2ecf20Sopenharmony_ci s2io_msix_fifo_handle, 69438c2ecf20Sopenharmony_ci 0, 69448c2ecf20Sopenharmony_ci sp->desc[i], 69458c2ecf20Sopenharmony_ci sp->s2io_entries[i].arg); 69468c2ecf20Sopenharmony_ci 69478c2ecf20Sopenharmony_ci } 69488c2ecf20Sopenharmony_ci /* if either data or addr is zero print it. */ 69498c2ecf20Sopenharmony_ci if (!(sp->msix_info[i].addr && 69508c2ecf20Sopenharmony_ci sp->msix_info[i].data)) { 69518c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 69528c2ecf20Sopenharmony_ci "%s @Addr:0x%llx Data:0x%llx\n", 69538c2ecf20Sopenharmony_ci sp->desc[i], 69548c2ecf20Sopenharmony_ci (unsigned long long) 69558c2ecf20Sopenharmony_ci sp->msix_info[i].addr, 69568c2ecf20Sopenharmony_ci (unsigned long long) 69578c2ecf20Sopenharmony_ci ntohl(sp->msix_info[i].data)); 69588c2ecf20Sopenharmony_ci } else 69598c2ecf20Sopenharmony_ci msix_rx_cnt++; 69608c2ecf20Sopenharmony_ci if (err) { 69618c2ecf20Sopenharmony_ci remove_msix_isr(sp); 69628c2ecf20Sopenharmony_ci 69638c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 69648c2ecf20Sopenharmony_ci "%s:MSI-X-%d registration " 69658c2ecf20Sopenharmony_ci "failed\n", dev->name, i); 69668c2ecf20Sopenharmony_ci 69678c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 69688c2ecf20Sopenharmony_ci "%s: Defaulting to INTA\n", 69698c2ecf20Sopenharmony_ci dev->name); 69708c2ecf20Sopenharmony_ci sp->config.intr_type = INTA; 69718c2ecf20Sopenharmony_ci break; 69728c2ecf20Sopenharmony_ci } 69738c2ecf20Sopenharmony_ci sp->s2io_entries[i].in_use = 69748c2ecf20Sopenharmony_ci MSIX_REGISTERED_SUCCESS; 69758c2ecf20Sopenharmony_ci } 69768c2ecf20Sopenharmony_ci } 69778c2ecf20Sopenharmony_ci if (!err) { 69788c2ecf20Sopenharmony_ci pr_info("MSI-X-RX %d entries enabled\n", --msix_rx_cnt); 69798c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, 69808c2ecf20Sopenharmony_ci "MSI-X-TX entries enabled through alarm vector\n"); 69818c2ecf20Sopenharmony_ci } 69828c2ecf20Sopenharmony_ci } 69838c2ecf20Sopenharmony_ci if (sp->config.intr_type == INTA) { 69848c2ecf20Sopenharmony_ci err = request_irq(sp->pdev->irq, s2io_isr, IRQF_SHARED, 69858c2ecf20Sopenharmony_ci sp->name, dev); 69868c2ecf20Sopenharmony_ci if (err) { 69878c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", 69888c2ecf20Sopenharmony_ci dev->name); 69898c2ecf20Sopenharmony_ci return -1; 69908c2ecf20Sopenharmony_ci } 69918c2ecf20Sopenharmony_ci } 69928c2ecf20Sopenharmony_ci return 0; 69938c2ecf20Sopenharmony_ci} 69948c2ecf20Sopenharmony_ci 69958c2ecf20Sopenharmony_cistatic void s2io_rem_isr(struct s2io_nic *sp) 69968c2ecf20Sopenharmony_ci{ 69978c2ecf20Sopenharmony_ci if (sp->config.intr_type == MSI_X) 69988c2ecf20Sopenharmony_ci remove_msix_isr(sp); 69998c2ecf20Sopenharmony_ci else 70008c2ecf20Sopenharmony_ci remove_inta_isr(sp); 70018c2ecf20Sopenharmony_ci} 70028c2ecf20Sopenharmony_ci 70038c2ecf20Sopenharmony_cistatic void do_s2io_card_down(struct s2io_nic *sp, int do_io) 70048c2ecf20Sopenharmony_ci{ 70058c2ecf20Sopenharmony_ci int cnt = 0; 70068c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = sp->bar0; 70078c2ecf20Sopenharmony_ci register u64 val64 = 0; 70088c2ecf20Sopenharmony_ci struct config_param *config; 70098c2ecf20Sopenharmony_ci config = &sp->config; 70108c2ecf20Sopenharmony_ci 70118c2ecf20Sopenharmony_ci if (!is_s2io_card_up(sp)) 70128c2ecf20Sopenharmony_ci return; 70138c2ecf20Sopenharmony_ci 70148c2ecf20Sopenharmony_ci del_timer_sync(&sp->alarm_timer); 70158c2ecf20Sopenharmony_ci /* If s2io_set_link task is executing, wait till it completes. */ 70168c2ecf20Sopenharmony_ci while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state))) 70178c2ecf20Sopenharmony_ci msleep(50); 70188c2ecf20Sopenharmony_ci clear_bit(__S2IO_STATE_CARD_UP, &sp->state); 70198c2ecf20Sopenharmony_ci 70208c2ecf20Sopenharmony_ci /* Disable napi */ 70218c2ecf20Sopenharmony_ci if (sp->config.napi) { 70228c2ecf20Sopenharmony_ci int off = 0; 70238c2ecf20Sopenharmony_ci if (config->intr_type == MSI_X) { 70248c2ecf20Sopenharmony_ci for (; off < sp->config.rx_ring_num; off++) 70258c2ecf20Sopenharmony_ci napi_disable(&sp->mac_control.rings[off].napi); 70268c2ecf20Sopenharmony_ci } 70278c2ecf20Sopenharmony_ci else 70288c2ecf20Sopenharmony_ci napi_disable(&sp->napi); 70298c2ecf20Sopenharmony_ci } 70308c2ecf20Sopenharmony_ci 70318c2ecf20Sopenharmony_ci /* disable Tx and Rx traffic on the NIC */ 70328c2ecf20Sopenharmony_ci if (do_io) 70338c2ecf20Sopenharmony_ci stop_nic(sp); 70348c2ecf20Sopenharmony_ci 70358c2ecf20Sopenharmony_ci s2io_rem_isr(sp); 70368c2ecf20Sopenharmony_ci 70378c2ecf20Sopenharmony_ci /* stop the tx queue, indicate link down */ 70388c2ecf20Sopenharmony_ci s2io_link(sp, LINK_DOWN); 70398c2ecf20Sopenharmony_ci 70408c2ecf20Sopenharmony_ci /* Check if the device is Quiescent and then Reset the NIC */ 70418c2ecf20Sopenharmony_ci while (do_io) { 70428c2ecf20Sopenharmony_ci /* As per the HW requirement we need to replenish the 70438c2ecf20Sopenharmony_ci * receive buffer to avoid the ring bump. Since there is 70448c2ecf20Sopenharmony_ci * no intention of processing the Rx frame at this pointwe are 70458c2ecf20Sopenharmony_ci * just setting the ownership bit of rxd in Each Rx 70468c2ecf20Sopenharmony_ci * ring to HW and set the appropriate buffer size 70478c2ecf20Sopenharmony_ci * based on the ring mode 70488c2ecf20Sopenharmony_ci */ 70498c2ecf20Sopenharmony_ci rxd_owner_bit_reset(sp); 70508c2ecf20Sopenharmony_ci 70518c2ecf20Sopenharmony_ci val64 = readq(&bar0->adapter_status); 70528c2ecf20Sopenharmony_ci if (verify_xena_quiescence(sp)) { 70538c2ecf20Sopenharmony_ci if (verify_pcc_quiescent(sp, sp->device_enabled_once)) 70548c2ecf20Sopenharmony_ci break; 70558c2ecf20Sopenharmony_ci } 70568c2ecf20Sopenharmony_ci 70578c2ecf20Sopenharmony_ci msleep(50); 70588c2ecf20Sopenharmony_ci cnt++; 70598c2ecf20Sopenharmony_ci if (cnt == 10) { 70608c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Device not Quiescent - " 70618c2ecf20Sopenharmony_ci "adapter status reads 0x%llx\n", 70628c2ecf20Sopenharmony_ci (unsigned long long)val64); 70638c2ecf20Sopenharmony_ci break; 70648c2ecf20Sopenharmony_ci } 70658c2ecf20Sopenharmony_ci } 70668c2ecf20Sopenharmony_ci if (do_io) 70678c2ecf20Sopenharmony_ci s2io_reset(sp); 70688c2ecf20Sopenharmony_ci 70698c2ecf20Sopenharmony_ci /* Free all Tx buffers */ 70708c2ecf20Sopenharmony_ci free_tx_buffers(sp); 70718c2ecf20Sopenharmony_ci 70728c2ecf20Sopenharmony_ci /* Free all Rx buffers */ 70738c2ecf20Sopenharmony_ci free_rx_buffers(sp); 70748c2ecf20Sopenharmony_ci 70758c2ecf20Sopenharmony_ci clear_bit(__S2IO_STATE_LINK_TASK, &(sp->state)); 70768c2ecf20Sopenharmony_ci} 70778c2ecf20Sopenharmony_ci 70788c2ecf20Sopenharmony_cistatic void s2io_card_down(struct s2io_nic *sp) 70798c2ecf20Sopenharmony_ci{ 70808c2ecf20Sopenharmony_ci do_s2io_card_down(sp, 1); 70818c2ecf20Sopenharmony_ci} 70828c2ecf20Sopenharmony_ci 70838c2ecf20Sopenharmony_cistatic int s2io_card_up(struct s2io_nic *sp) 70848c2ecf20Sopenharmony_ci{ 70858c2ecf20Sopenharmony_ci int i, ret = 0; 70868c2ecf20Sopenharmony_ci struct config_param *config; 70878c2ecf20Sopenharmony_ci struct mac_info *mac_control; 70888c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 70898c2ecf20Sopenharmony_ci u16 interruptible; 70908c2ecf20Sopenharmony_ci 70918c2ecf20Sopenharmony_ci /* Initialize the H/W I/O registers */ 70928c2ecf20Sopenharmony_ci ret = init_nic(sp); 70938c2ecf20Sopenharmony_ci if (ret != 0) { 70948c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n", 70958c2ecf20Sopenharmony_ci dev->name); 70968c2ecf20Sopenharmony_ci if (ret != -EIO) 70978c2ecf20Sopenharmony_ci s2io_reset(sp); 70988c2ecf20Sopenharmony_ci return ret; 70998c2ecf20Sopenharmony_ci } 71008c2ecf20Sopenharmony_ci 71018c2ecf20Sopenharmony_ci /* 71028c2ecf20Sopenharmony_ci * Initializing the Rx buffers. For now we are considering only 1 71038c2ecf20Sopenharmony_ci * Rx ring and initializing buffers into 30 Rx blocks 71048c2ecf20Sopenharmony_ci */ 71058c2ecf20Sopenharmony_ci config = &sp->config; 71068c2ecf20Sopenharmony_ci mac_control = &sp->mac_control; 71078c2ecf20Sopenharmony_ci 71088c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 71098c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 71108c2ecf20Sopenharmony_ci 71118c2ecf20Sopenharmony_ci ring->mtu = dev->mtu; 71128c2ecf20Sopenharmony_ci ring->lro = !!(dev->features & NETIF_F_LRO); 71138c2ecf20Sopenharmony_ci ret = fill_rx_buffers(sp, ring, 1); 71148c2ecf20Sopenharmony_ci if (ret) { 71158c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n", 71168c2ecf20Sopenharmony_ci dev->name); 71178c2ecf20Sopenharmony_ci ret = -ENOMEM; 71188c2ecf20Sopenharmony_ci goto err_fill_buff; 71198c2ecf20Sopenharmony_ci } 71208c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i, 71218c2ecf20Sopenharmony_ci ring->rx_bufs_left); 71228c2ecf20Sopenharmony_ci } 71238c2ecf20Sopenharmony_ci 71248c2ecf20Sopenharmony_ci /* Initialise napi */ 71258c2ecf20Sopenharmony_ci if (config->napi) { 71268c2ecf20Sopenharmony_ci if (config->intr_type == MSI_X) { 71278c2ecf20Sopenharmony_ci for (i = 0; i < sp->config.rx_ring_num; i++) 71288c2ecf20Sopenharmony_ci napi_enable(&sp->mac_control.rings[i].napi); 71298c2ecf20Sopenharmony_ci } else { 71308c2ecf20Sopenharmony_ci napi_enable(&sp->napi); 71318c2ecf20Sopenharmony_ci } 71328c2ecf20Sopenharmony_ci } 71338c2ecf20Sopenharmony_ci 71348c2ecf20Sopenharmony_ci /* Maintain the state prior to the open */ 71358c2ecf20Sopenharmony_ci if (sp->promisc_flg) 71368c2ecf20Sopenharmony_ci sp->promisc_flg = 0; 71378c2ecf20Sopenharmony_ci if (sp->m_cast_flg) { 71388c2ecf20Sopenharmony_ci sp->m_cast_flg = 0; 71398c2ecf20Sopenharmony_ci sp->all_multi_pos = 0; 71408c2ecf20Sopenharmony_ci } 71418c2ecf20Sopenharmony_ci 71428c2ecf20Sopenharmony_ci /* Setting its receive mode */ 71438c2ecf20Sopenharmony_ci s2io_set_multicast(dev); 71448c2ecf20Sopenharmony_ci 71458c2ecf20Sopenharmony_ci if (dev->features & NETIF_F_LRO) { 71468c2ecf20Sopenharmony_ci /* Initialize max aggregatable pkts per session based on MTU */ 71478c2ecf20Sopenharmony_ci sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu; 71488c2ecf20Sopenharmony_ci /* Check if we can use (if specified) user provided value */ 71498c2ecf20Sopenharmony_ci if (lro_max_pkts < sp->lro_max_aggr_per_sess) 71508c2ecf20Sopenharmony_ci sp->lro_max_aggr_per_sess = lro_max_pkts; 71518c2ecf20Sopenharmony_ci } 71528c2ecf20Sopenharmony_ci 71538c2ecf20Sopenharmony_ci /* Enable Rx Traffic and interrupts on the NIC */ 71548c2ecf20Sopenharmony_ci if (start_nic(sp)) { 71558c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name); 71568c2ecf20Sopenharmony_ci ret = -ENODEV; 71578c2ecf20Sopenharmony_ci goto err_out; 71588c2ecf20Sopenharmony_ci } 71598c2ecf20Sopenharmony_ci 71608c2ecf20Sopenharmony_ci /* Add interrupt service routine */ 71618c2ecf20Sopenharmony_ci if (s2io_add_isr(sp) != 0) { 71628c2ecf20Sopenharmony_ci if (sp->config.intr_type == MSI_X) 71638c2ecf20Sopenharmony_ci s2io_rem_isr(sp); 71648c2ecf20Sopenharmony_ci ret = -ENODEV; 71658c2ecf20Sopenharmony_ci goto err_out; 71668c2ecf20Sopenharmony_ci } 71678c2ecf20Sopenharmony_ci 71688c2ecf20Sopenharmony_ci timer_setup(&sp->alarm_timer, s2io_alarm_handle, 0); 71698c2ecf20Sopenharmony_ci mod_timer(&sp->alarm_timer, jiffies + HZ / 2); 71708c2ecf20Sopenharmony_ci 71718c2ecf20Sopenharmony_ci set_bit(__S2IO_STATE_CARD_UP, &sp->state); 71728c2ecf20Sopenharmony_ci 71738c2ecf20Sopenharmony_ci /* Enable select interrupts */ 71748c2ecf20Sopenharmony_ci en_dis_err_alarms(sp, ENA_ALL_INTRS, ENABLE_INTRS); 71758c2ecf20Sopenharmony_ci if (sp->config.intr_type != INTA) { 71768c2ecf20Sopenharmony_ci interruptible = TX_TRAFFIC_INTR | TX_PIC_INTR; 71778c2ecf20Sopenharmony_ci en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS); 71788c2ecf20Sopenharmony_ci } else { 71798c2ecf20Sopenharmony_ci interruptible = TX_TRAFFIC_INTR | RX_TRAFFIC_INTR; 71808c2ecf20Sopenharmony_ci interruptible |= TX_PIC_INTR; 71818c2ecf20Sopenharmony_ci en_dis_able_nic_intrs(sp, interruptible, ENABLE_INTRS); 71828c2ecf20Sopenharmony_ci } 71838c2ecf20Sopenharmony_ci 71848c2ecf20Sopenharmony_ci return 0; 71858c2ecf20Sopenharmony_ci 71868c2ecf20Sopenharmony_cierr_out: 71878c2ecf20Sopenharmony_ci if (config->napi) { 71888c2ecf20Sopenharmony_ci if (config->intr_type == MSI_X) { 71898c2ecf20Sopenharmony_ci for (i = 0; i < sp->config.rx_ring_num; i++) 71908c2ecf20Sopenharmony_ci napi_disable(&sp->mac_control.rings[i].napi); 71918c2ecf20Sopenharmony_ci } else { 71928c2ecf20Sopenharmony_ci napi_disable(&sp->napi); 71938c2ecf20Sopenharmony_ci } 71948c2ecf20Sopenharmony_ci } 71958c2ecf20Sopenharmony_cierr_fill_buff: 71968c2ecf20Sopenharmony_ci s2io_reset(sp); 71978c2ecf20Sopenharmony_ci free_rx_buffers(sp); 71988c2ecf20Sopenharmony_ci return ret; 71998c2ecf20Sopenharmony_ci} 72008c2ecf20Sopenharmony_ci 72018c2ecf20Sopenharmony_ci/** 72028c2ecf20Sopenharmony_ci * s2io_restart_nic - Resets the NIC. 72038c2ecf20Sopenharmony_ci * @work : work struct containing a pointer to the device private structure 72048c2ecf20Sopenharmony_ci * Description: 72058c2ecf20Sopenharmony_ci * This function is scheduled to be run by the s2io_tx_watchdog 72068c2ecf20Sopenharmony_ci * function after 0.5 secs to reset the NIC. The idea is to reduce 72078c2ecf20Sopenharmony_ci * the run time of the watch dog routine which is run holding a 72088c2ecf20Sopenharmony_ci * spin lock. 72098c2ecf20Sopenharmony_ci */ 72108c2ecf20Sopenharmony_ci 72118c2ecf20Sopenharmony_cistatic void s2io_restart_nic(struct work_struct *work) 72128c2ecf20Sopenharmony_ci{ 72138c2ecf20Sopenharmony_ci struct s2io_nic *sp = container_of(work, struct s2io_nic, rst_timer_task); 72148c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 72158c2ecf20Sopenharmony_ci 72168c2ecf20Sopenharmony_ci rtnl_lock(); 72178c2ecf20Sopenharmony_ci 72188c2ecf20Sopenharmony_ci if (!netif_running(dev)) 72198c2ecf20Sopenharmony_ci goto out_unlock; 72208c2ecf20Sopenharmony_ci 72218c2ecf20Sopenharmony_ci s2io_card_down(sp); 72228c2ecf20Sopenharmony_ci if (s2io_card_up(sp)) { 72238c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n", dev->name); 72248c2ecf20Sopenharmony_ci } 72258c2ecf20Sopenharmony_ci s2io_wake_all_tx_queue(sp); 72268c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n", dev->name); 72278c2ecf20Sopenharmony_ciout_unlock: 72288c2ecf20Sopenharmony_ci rtnl_unlock(); 72298c2ecf20Sopenharmony_ci} 72308c2ecf20Sopenharmony_ci 72318c2ecf20Sopenharmony_ci/** 72328c2ecf20Sopenharmony_ci * s2io_tx_watchdog - Watchdog for transmit side. 72338c2ecf20Sopenharmony_ci * @dev : Pointer to net device structure 72348c2ecf20Sopenharmony_ci * @txqueue: index of the hanging queue 72358c2ecf20Sopenharmony_ci * Description: 72368c2ecf20Sopenharmony_ci * This function is triggered if the Tx Queue is stopped 72378c2ecf20Sopenharmony_ci * for a pre-defined amount of time when the Interface is still up. 72388c2ecf20Sopenharmony_ci * If the Interface is jammed in such a situation, the hardware is 72398c2ecf20Sopenharmony_ci * reset (by s2io_close) and restarted again (by s2io_open) to 72408c2ecf20Sopenharmony_ci * overcome any problem that might have been caused in the hardware. 72418c2ecf20Sopenharmony_ci * Return value: 72428c2ecf20Sopenharmony_ci * void 72438c2ecf20Sopenharmony_ci */ 72448c2ecf20Sopenharmony_ci 72458c2ecf20Sopenharmony_cistatic void s2io_tx_watchdog(struct net_device *dev, unsigned int txqueue) 72468c2ecf20Sopenharmony_ci{ 72478c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 72488c2ecf20Sopenharmony_ci struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; 72498c2ecf20Sopenharmony_ci 72508c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev)) { 72518c2ecf20Sopenharmony_ci swstats->watchdog_timer_cnt++; 72528c2ecf20Sopenharmony_ci schedule_work(&sp->rst_timer_task); 72538c2ecf20Sopenharmony_ci swstats->soft_reset_cnt++; 72548c2ecf20Sopenharmony_ci } 72558c2ecf20Sopenharmony_ci} 72568c2ecf20Sopenharmony_ci 72578c2ecf20Sopenharmony_ci/** 72588c2ecf20Sopenharmony_ci * rx_osm_handler - To perform some OS related operations on SKB. 72598c2ecf20Sopenharmony_ci * @ring_data : the ring from which this RxD was extracted. 72608c2ecf20Sopenharmony_ci * @rxdp: descriptor 72618c2ecf20Sopenharmony_ci * Description: 72628c2ecf20Sopenharmony_ci * This function is called by the Rx interrupt serivce routine to perform 72638c2ecf20Sopenharmony_ci * some OS related operations on the SKB before passing it to the upper 72648c2ecf20Sopenharmony_ci * layers. It mainly checks if the checksum is OK, if so adds it to the 72658c2ecf20Sopenharmony_ci * SKBs cksum variable, increments the Rx packet count and passes the SKB 72668c2ecf20Sopenharmony_ci * to the upper layer. If the checksum is wrong, it increments the Rx 72678c2ecf20Sopenharmony_ci * packet error count, frees the SKB and returns error. 72688c2ecf20Sopenharmony_ci * Return value: 72698c2ecf20Sopenharmony_ci * SUCCESS on success and -1 on failure. 72708c2ecf20Sopenharmony_ci */ 72718c2ecf20Sopenharmony_cistatic int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) 72728c2ecf20Sopenharmony_ci{ 72738c2ecf20Sopenharmony_ci struct s2io_nic *sp = ring_data->nic; 72748c2ecf20Sopenharmony_ci struct net_device *dev = ring_data->dev; 72758c2ecf20Sopenharmony_ci struct sk_buff *skb = (struct sk_buff *) 72768c2ecf20Sopenharmony_ci ((unsigned long)rxdp->Host_Control); 72778c2ecf20Sopenharmony_ci int ring_no = ring_data->ring_no; 72788c2ecf20Sopenharmony_ci u16 l3_csum, l4_csum; 72798c2ecf20Sopenharmony_ci unsigned long long err = rxdp->Control_1 & RXD_T_CODE; 72808c2ecf20Sopenharmony_ci struct lro *lro; 72818c2ecf20Sopenharmony_ci u8 err_mask; 72828c2ecf20Sopenharmony_ci struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; 72838c2ecf20Sopenharmony_ci 72848c2ecf20Sopenharmony_ci skb->dev = dev; 72858c2ecf20Sopenharmony_ci 72868c2ecf20Sopenharmony_ci if (err) { 72878c2ecf20Sopenharmony_ci /* Check for parity error */ 72888c2ecf20Sopenharmony_ci if (err & 0x1) 72898c2ecf20Sopenharmony_ci swstats->parity_err_cnt++; 72908c2ecf20Sopenharmony_ci 72918c2ecf20Sopenharmony_ci err_mask = err >> 48; 72928c2ecf20Sopenharmony_ci switch (err_mask) { 72938c2ecf20Sopenharmony_ci case 1: 72948c2ecf20Sopenharmony_ci swstats->rx_parity_err_cnt++; 72958c2ecf20Sopenharmony_ci break; 72968c2ecf20Sopenharmony_ci 72978c2ecf20Sopenharmony_ci case 2: 72988c2ecf20Sopenharmony_ci swstats->rx_abort_cnt++; 72998c2ecf20Sopenharmony_ci break; 73008c2ecf20Sopenharmony_ci 73018c2ecf20Sopenharmony_ci case 3: 73028c2ecf20Sopenharmony_ci swstats->rx_parity_abort_cnt++; 73038c2ecf20Sopenharmony_ci break; 73048c2ecf20Sopenharmony_ci 73058c2ecf20Sopenharmony_ci case 4: 73068c2ecf20Sopenharmony_ci swstats->rx_rda_fail_cnt++; 73078c2ecf20Sopenharmony_ci break; 73088c2ecf20Sopenharmony_ci 73098c2ecf20Sopenharmony_ci case 5: 73108c2ecf20Sopenharmony_ci swstats->rx_unkn_prot_cnt++; 73118c2ecf20Sopenharmony_ci break; 73128c2ecf20Sopenharmony_ci 73138c2ecf20Sopenharmony_ci case 6: 73148c2ecf20Sopenharmony_ci swstats->rx_fcs_err_cnt++; 73158c2ecf20Sopenharmony_ci break; 73168c2ecf20Sopenharmony_ci 73178c2ecf20Sopenharmony_ci case 7: 73188c2ecf20Sopenharmony_ci swstats->rx_buf_size_err_cnt++; 73198c2ecf20Sopenharmony_ci break; 73208c2ecf20Sopenharmony_ci 73218c2ecf20Sopenharmony_ci case 8: 73228c2ecf20Sopenharmony_ci swstats->rx_rxd_corrupt_cnt++; 73238c2ecf20Sopenharmony_ci break; 73248c2ecf20Sopenharmony_ci 73258c2ecf20Sopenharmony_ci case 15: 73268c2ecf20Sopenharmony_ci swstats->rx_unkn_err_cnt++; 73278c2ecf20Sopenharmony_ci break; 73288c2ecf20Sopenharmony_ci } 73298c2ecf20Sopenharmony_ci /* 73308c2ecf20Sopenharmony_ci * Drop the packet if bad transfer code. Exception being 73318c2ecf20Sopenharmony_ci * 0x5, which could be due to unsupported IPv6 extension header. 73328c2ecf20Sopenharmony_ci * In this case, we let stack handle the packet. 73338c2ecf20Sopenharmony_ci * Note that in this case, since checksum will be incorrect, 73348c2ecf20Sopenharmony_ci * stack will validate the same. 73358c2ecf20Sopenharmony_ci */ 73368c2ecf20Sopenharmony_ci if (err_mask != 0x5) { 73378c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n", 73388c2ecf20Sopenharmony_ci dev->name, err_mask); 73398c2ecf20Sopenharmony_ci dev->stats.rx_crc_errors++; 73408c2ecf20Sopenharmony_ci swstats->mem_freed 73418c2ecf20Sopenharmony_ci += skb->truesize; 73428c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 73438c2ecf20Sopenharmony_ci ring_data->rx_bufs_left -= 1; 73448c2ecf20Sopenharmony_ci rxdp->Host_Control = 0; 73458c2ecf20Sopenharmony_ci return 0; 73468c2ecf20Sopenharmony_ci } 73478c2ecf20Sopenharmony_ci } 73488c2ecf20Sopenharmony_ci 73498c2ecf20Sopenharmony_ci rxdp->Host_Control = 0; 73508c2ecf20Sopenharmony_ci if (sp->rxd_mode == RXD_MODE_1) { 73518c2ecf20Sopenharmony_ci int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2); 73528c2ecf20Sopenharmony_ci 73538c2ecf20Sopenharmony_ci skb_put(skb, len); 73548c2ecf20Sopenharmony_ci } else if (sp->rxd_mode == RXD_MODE_3B) { 73558c2ecf20Sopenharmony_ci int get_block = ring_data->rx_curr_get_info.block_index; 73568c2ecf20Sopenharmony_ci int get_off = ring_data->rx_curr_get_info.offset; 73578c2ecf20Sopenharmony_ci int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2); 73588c2ecf20Sopenharmony_ci int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2); 73598c2ecf20Sopenharmony_ci unsigned char *buff = skb_push(skb, buf0_len); 73608c2ecf20Sopenharmony_ci 73618c2ecf20Sopenharmony_ci struct buffAdd *ba = &ring_data->ba[get_block][get_off]; 73628c2ecf20Sopenharmony_ci memcpy(buff, ba->ba_0, buf0_len); 73638c2ecf20Sopenharmony_ci skb_put(skb, buf2_len); 73648c2ecf20Sopenharmony_ci } 73658c2ecf20Sopenharmony_ci 73668c2ecf20Sopenharmony_ci if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && 73678c2ecf20Sopenharmony_ci ((!ring_data->lro) || 73688c2ecf20Sopenharmony_ci (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG))) && 73698c2ecf20Sopenharmony_ci (dev->features & NETIF_F_RXCSUM)) { 73708c2ecf20Sopenharmony_ci l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); 73718c2ecf20Sopenharmony_ci l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); 73728c2ecf20Sopenharmony_ci if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) { 73738c2ecf20Sopenharmony_ci /* 73748c2ecf20Sopenharmony_ci * NIC verifies if the Checksum of the received 73758c2ecf20Sopenharmony_ci * frame is Ok or not and accordingly returns 73768c2ecf20Sopenharmony_ci * a flag in the RxD. 73778c2ecf20Sopenharmony_ci */ 73788c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 73798c2ecf20Sopenharmony_ci if (ring_data->lro) { 73808c2ecf20Sopenharmony_ci u32 tcp_len = 0; 73818c2ecf20Sopenharmony_ci u8 *tcp; 73828c2ecf20Sopenharmony_ci int ret = 0; 73838c2ecf20Sopenharmony_ci 73848c2ecf20Sopenharmony_ci ret = s2io_club_tcp_session(ring_data, 73858c2ecf20Sopenharmony_ci skb->data, &tcp, 73868c2ecf20Sopenharmony_ci &tcp_len, &lro, 73878c2ecf20Sopenharmony_ci rxdp, sp); 73888c2ecf20Sopenharmony_ci switch (ret) { 73898c2ecf20Sopenharmony_ci case 3: /* Begin anew */ 73908c2ecf20Sopenharmony_ci lro->parent = skb; 73918c2ecf20Sopenharmony_ci goto aggregate; 73928c2ecf20Sopenharmony_ci case 1: /* Aggregate */ 73938c2ecf20Sopenharmony_ci lro_append_pkt(sp, lro, skb, tcp_len); 73948c2ecf20Sopenharmony_ci goto aggregate; 73958c2ecf20Sopenharmony_ci case 4: /* Flush session */ 73968c2ecf20Sopenharmony_ci lro_append_pkt(sp, lro, skb, tcp_len); 73978c2ecf20Sopenharmony_ci queue_rx_frame(lro->parent, 73988c2ecf20Sopenharmony_ci lro->vlan_tag); 73998c2ecf20Sopenharmony_ci clear_lro_session(lro); 74008c2ecf20Sopenharmony_ci swstats->flush_max_pkts++; 74018c2ecf20Sopenharmony_ci goto aggregate; 74028c2ecf20Sopenharmony_ci case 2: /* Flush both */ 74038c2ecf20Sopenharmony_ci lro->parent->data_len = lro->frags_len; 74048c2ecf20Sopenharmony_ci swstats->sending_both++; 74058c2ecf20Sopenharmony_ci queue_rx_frame(lro->parent, 74068c2ecf20Sopenharmony_ci lro->vlan_tag); 74078c2ecf20Sopenharmony_ci clear_lro_session(lro); 74088c2ecf20Sopenharmony_ci goto send_up; 74098c2ecf20Sopenharmony_ci case 0: /* sessions exceeded */ 74108c2ecf20Sopenharmony_ci case -1: /* non-TCP or not L2 aggregatable */ 74118c2ecf20Sopenharmony_ci case 5: /* 74128c2ecf20Sopenharmony_ci * First pkt in session not 74138c2ecf20Sopenharmony_ci * L3/L4 aggregatable 74148c2ecf20Sopenharmony_ci */ 74158c2ecf20Sopenharmony_ci break; 74168c2ecf20Sopenharmony_ci default: 74178c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 74188c2ecf20Sopenharmony_ci "%s: Samadhana!!\n", 74198c2ecf20Sopenharmony_ci __func__); 74208c2ecf20Sopenharmony_ci BUG(); 74218c2ecf20Sopenharmony_ci } 74228c2ecf20Sopenharmony_ci } 74238c2ecf20Sopenharmony_ci } else { 74248c2ecf20Sopenharmony_ci /* 74258c2ecf20Sopenharmony_ci * Packet with erroneous checksum, let the 74268c2ecf20Sopenharmony_ci * upper layers deal with it. 74278c2ecf20Sopenharmony_ci */ 74288c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 74298c2ecf20Sopenharmony_ci } 74308c2ecf20Sopenharmony_ci } else 74318c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 74328c2ecf20Sopenharmony_ci 74338c2ecf20Sopenharmony_ci swstats->mem_freed += skb->truesize; 74348c2ecf20Sopenharmony_cisend_up: 74358c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, ring_no); 74368c2ecf20Sopenharmony_ci queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2)); 74378c2ecf20Sopenharmony_ciaggregate: 74388c2ecf20Sopenharmony_ci sp->mac_control.rings[ring_no].rx_bufs_left -= 1; 74398c2ecf20Sopenharmony_ci return SUCCESS; 74408c2ecf20Sopenharmony_ci} 74418c2ecf20Sopenharmony_ci 74428c2ecf20Sopenharmony_ci/** 74438c2ecf20Sopenharmony_ci * s2io_link - stops/starts the Tx queue. 74448c2ecf20Sopenharmony_ci * @sp : private member of the device structure, which is a pointer to the 74458c2ecf20Sopenharmony_ci * s2io_nic structure. 74468c2ecf20Sopenharmony_ci * @link : inidicates whether link is UP/DOWN. 74478c2ecf20Sopenharmony_ci * Description: 74488c2ecf20Sopenharmony_ci * This function stops/starts the Tx queue depending on whether the link 74498c2ecf20Sopenharmony_ci * status of the NIC is is down or up. This is called by the Alarm 74508c2ecf20Sopenharmony_ci * interrupt handler whenever a link change interrupt comes up. 74518c2ecf20Sopenharmony_ci * Return value: 74528c2ecf20Sopenharmony_ci * void. 74538c2ecf20Sopenharmony_ci */ 74548c2ecf20Sopenharmony_ci 74558c2ecf20Sopenharmony_cistatic void s2io_link(struct s2io_nic *sp, int link) 74568c2ecf20Sopenharmony_ci{ 74578c2ecf20Sopenharmony_ci struct net_device *dev = sp->dev; 74588c2ecf20Sopenharmony_ci struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; 74598c2ecf20Sopenharmony_ci 74608c2ecf20Sopenharmony_ci if (link != sp->last_link_state) { 74618c2ecf20Sopenharmony_ci init_tti(sp, link); 74628c2ecf20Sopenharmony_ci if (link == LINK_DOWN) { 74638c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name); 74648c2ecf20Sopenharmony_ci s2io_stop_all_tx_queue(sp); 74658c2ecf20Sopenharmony_ci netif_carrier_off(dev); 74668c2ecf20Sopenharmony_ci if (swstats->link_up_cnt) 74678c2ecf20Sopenharmony_ci swstats->link_up_time = 74688c2ecf20Sopenharmony_ci jiffies - sp->start_time; 74698c2ecf20Sopenharmony_ci swstats->link_down_cnt++; 74708c2ecf20Sopenharmony_ci } else { 74718c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name); 74728c2ecf20Sopenharmony_ci if (swstats->link_down_cnt) 74738c2ecf20Sopenharmony_ci swstats->link_down_time = 74748c2ecf20Sopenharmony_ci jiffies - sp->start_time; 74758c2ecf20Sopenharmony_ci swstats->link_up_cnt++; 74768c2ecf20Sopenharmony_ci netif_carrier_on(dev); 74778c2ecf20Sopenharmony_ci s2io_wake_all_tx_queue(sp); 74788c2ecf20Sopenharmony_ci } 74798c2ecf20Sopenharmony_ci } 74808c2ecf20Sopenharmony_ci sp->last_link_state = link; 74818c2ecf20Sopenharmony_ci sp->start_time = jiffies; 74828c2ecf20Sopenharmony_ci} 74838c2ecf20Sopenharmony_ci 74848c2ecf20Sopenharmony_ci/** 74858c2ecf20Sopenharmony_ci * s2io_init_pci -Initialization of PCI and PCI-X configuration registers . 74868c2ecf20Sopenharmony_ci * @sp : private member of the device structure, which is a pointer to the 74878c2ecf20Sopenharmony_ci * s2io_nic structure. 74888c2ecf20Sopenharmony_ci * Description: 74898c2ecf20Sopenharmony_ci * This function initializes a few of the PCI and PCI-X configuration registers 74908c2ecf20Sopenharmony_ci * with recommended values. 74918c2ecf20Sopenharmony_ci * Return value: 74928c2ecf20Sopenharmony_ci * void 74938c2ecf20Sopenharmony_ci */ 74948c2ecf20Sopenharmony_ci 74958c2ecf20Sopenharmony_cistatic void s2io_init_pci(struct s2io_nic *sp) 74968c2ecf20Sopenharmony_ci{ 74978c2ecf20Sopenharmony_ci u16 pci_cmd = 0, pcix_cmd = 0; 74988c2ecf20Sopenharmony_ci 74998c2ecf20Sopenharmony_ci /* Enable Data Parity Error Recovery in PCI-X command register. */ 75008c2ecf20Sopenharmony_ci pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, 75018c2ecf20Sopenharmony_ci &(pcix_cmd)); 75028c2ecf20Sopenharmony_ci pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, 75038c2ecf20Sopenharmony_ci (pcix_cmd | 1)); 75048c2ecf20Sopenharmony_ci pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, 75058c2ecf20Sopenharmony_ci &(pcix_cmd)); 75068c2ecf20Sopenharmony_ci 75078c2ecf20Sopenharmony_ci /* Set the PErr Response bit in PCI command register. */ 75088c2ecf20Sopenharmony_ci pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd); 75098c2ecf20Sopenharmony_ci pci_write_config_word(sp->pdev, PCI_COMMAND, 75108c2ecf20Sopenharmony_ci (pci_cmd | PCI_COMMAND_PARITY)); 75118c2ecf20Sopenharmony_ci pci_read_config_word(sp->pdev, PCI_COMMAND, &pci_cmd); 75128c2ecf20Sopenharmony_ci} 75138c2ecf20Sopenharmony_ci 75148c2ecf20Sopenharmony_cistatic int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type, 75158c2ecf20Sopenharmony_ci u8 *dev_multiq) 75168c2ecf20Sopenharmony_ci{ 75178c2ecf20Sopenharmony_ci int i; 75188c2ecf20Sopenharmony_ci 75198c2ecf20Sopenharmony_ci if ((tx_fifo_num > MAX_TX_FIFOS) || (tx_fifo_num < 1)) { 75208c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Requested number of tx fifos " 75218c2ecf20Sopenharmony_ci "(%d) not supported\n", tx_fifo_num); 75228c2ecf20Sopenharmony_ci 75238c2ecf20Sopenharmony_ci if (tx_fifo_num < 1) 75248c2ecf20Sopenharmony_ci tx_fifo_num = 1; 75258c2ecf20Sopenharmony_ci else 75268c2ecf20Sopenharmony_ci tx_fifo_num = MAX_TX_FIFOS; 75278c2ecf20Sopenharmony_ci 75288c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Default to %d tx fifos\n", tx_fifo_num); 75298c2ecf20Sopenharmony_ci } 75308c2ecf20Sopenharmony_ci 75318c2ecf20Sopenharmony_ci if (multiq) 75328c2ecf20Sopenharmony_ci *dev_multiq = multiq; 75338c2ecf20Sopenharmony_ci 75348c2ecf20Sopenharmony_ci if (tx_steering_type && (1 == tx_fifo_num)) { 75358c2ecf20Sopenharmony_ci if (tx_steering_type != TX_DEFAULT_STEERING) 75368c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 75378c2ecf20Sopenharmony_ci "Tx steering is not supported with " 75388c2ecf20Sopenharmony_ci "one fifo. Disabling Tx steering.\n"); 75398c2ecf20Sopenharmony_ci tx_steering_type = NO_STEERING; 75408c2ecf20Sopenharmony_ci } 75418c2ecf20Sopenharmony_ci 75428c2ecf20Sopenharmony_ci if ((tx_steering_type < NO_STEERING) || 75438c2ecf20Sopenharmony_ci (tx_steering_type > TX_DEFAULT_STEERING)) { 75448c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 75458c2ecf20Sopenharmony_ci "Requested transmit steering not supported\n"); 75468c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Disabling transmit steering\n"); 75478c2ecf20Sopenharmony_ci tx_steering_type = NO_STEERING; 75488c2ecf20Sopenharmony_ci } 75498c2ecf20Sopenharmony_ci 75508c2ecf20Sopenharmony_ci if (rx_ring_num > MAX_RX_RINGS) { 75518c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 75528c2ecf20Sopenharmony_ci "Requested number of rx rings not supported\n"); 75538c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Default to %d rx rings\n", 75548c2ecf20Sopenharmony_ci MAX_RX_RINGS); 75558c2ecf20Sopenharmony_ci rx_ring_num = MAX_RX_RINGS; 75568c2ecf20Sopenharmony_ci } 75578c2ecf20Sopenharmony_ci 75588c2ecf20Sopenharmony_ci if ((*dev_intr_type != INTA) && (*dev_intr_type != MSI_X)) { 75598c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Wrong intr_type requested. " 75608c2ecf20Sopenharmony_ci "Defaulting to INTA\n"); 75618c2ecf20Sopenharmony_ci *dev_intr_type = INTA; 75628c2ecf20Sopenharmony_ci } 75638c2ecf20Sopenharmony_ci 75648c2ecf20Sopenharmony_ci if ((*dev_intr_type == MSI_X) && 75658c2ecf20Sopenharmony_ci ((pdev->device != PCI_DEVICE_ID_HERC_WIN) && 75668c2ecf20Sopenharmony_ci (pdev->device != PCI_DEVICE_ID_HERC_UNI))) { 75678c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. " 75688c2ecf20Sopenharmony_ci "Defaulting to INTA\n"); 75698c2ecf20Sopenharmony_ci *dev_intr_type = INTA; 75708c2ecf20Sopenharmony_ci } 75718c2ecf20Sopenharmony_ci 75728c2ecf20Sopenharmony_ci if ((rx_ring_mode != 1) && (rx_ring_mode != 2)) { 75738c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Requested ring mode not supported\n"); 75748c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Defaulting to 1-buffer mode\n"); 75758c2ecf20Sopenharmony_ci rx_ring_mode = 1; 75768c2ecf20Sopenharmony_ci } 75778c2ecf20Sopenharmony_ci 75788c2ecf20Sopenharmony_ci for (i = 0; i < MAX_RX_RINGS; i++) 75798c2ecf20Sopenharmony_ci if (rx_ring_sz[i] > MAX_RX_BLOCKS_PER_RING) { 75808c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Requested rx ring size not " 75818c2ecf20Sopenharmony_ci "supported\nDefaulting to %d\n", 75828c2ecf20Sopenharmony_ci MAX_RX_BLOCKS_PER_RING); 75838c2ecf20Sopenharmony_ci rx_ring_sz[i] = MAX_RX_BLOCKS_PER_RING; 75848c2ecf20Sopenharmony_ci } 75858c2ecf20Sopenharmony_ci 75868c2ecf20Sopenharmony_ci return SUCCESS; 75878c2ecf20Sopenharmony_ci} 75888c2ecf20Sopenharmony_ci 75898c2ecf20Sopenharmony_ci/** 75908c2ecf20Sopenharmony_ci * rts_ds_steer - Receive traffic steering based on IPv4 or IPv6 TOS or Traffic class respectively. 75918c2ecf20Sopenharmony_ci * @nic: device private variable 75928c2ecf20Sopenharmony_ci * @ds_codepoint: data 75938c2ecf20Sopenharmony_ci * @ring: ring index 75948c2ecf20Sopenharmony_ci * Description: The function configures the receive steering to 75958c2ecf20Sopenharmony_ci * desired receive ring. 75968c2ecf20Sopenharmony_ci * Return Value: SUCCESS on success and 75978c2ecf20Sopenharmony_ci * '-1' on failure (endian settings incorrect). 75988c2ecf20Sopenharmony_ci */ 75998c2ecf20Sopenharmony_cistatic int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring) 76008c2ecf20Sopenharmony_ci{ 76018c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = nic->bar0; 76028c2ecf20Sopenharmony_ci register u64 val64 = 0; 76038c2ecf20Sopenharmony_ci 76048c2ecf20Sopenharmony_ci if (ds_codepoint > 63) 76058c2ecf20Sopenharmony_ci return FAILURE; 76068c2ecf20Sopenharmony_ci 76078c2ecf20Sopenharmony_ci val64 = RTS_DS_MEM_DATA(ring); 76088c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_ds_mem_data); 76098c2ecf20Sopenharmony_ci 76108c2ecf20Sopenharmony_ci val64 = RTS_DS_MEM_CTRL_WE | 76118c2ecf20Sopenharmony_ci RTS_DS_MEM_CTRL_STROBE_NEW_CMD | 76128c2ecf20Sopenharmony_ci RTS_DS_MEM_CTRL_OFFSET(ds_codepoint); 76138c2ecf20Sopenharmony_ci 76148c2ecf20Sopenharmony_ci writeq(val64, &bar0->rts_ds_mem_ctrl); 76158c2ecf20Sopenharmony_ci 76168c2ecf20Sopenharmony_ci return wait_for_cmd_complete(&bar0->rts_ds_mem_ctrl, 76178c2ecf20Sopenharmony_ci RTS_DS_MEM_CTRL_STROBE_CMD_BEING_EXECUTED, 76188c2ecf20Sopenharmony_ci S2IO_BIT_RESET); 76198c2ecf20Sopenharmony_ci} 76208c2ecf20Sopenharmony_ci 76218c2ecf20Sopenharmony_cistatic const struct net_device_ops s2io_netdev_ops = { 76228c2ecf20Sopenharmony_ci .ndo_open = s2io_open, 76238c2ecf20Sopenharmony_ci .ndo_stop = s2io_close, 76248c2ecf20Sopenharmony_ci .ndo_get_stats = s2io_get_stats, 76258c2ecf20Sopenharmony_ci .ndo_start_xmit = s2io_xmit, 76268c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 76278c2ecf20Sopenharmony_ci .ndo_set_rx_mode = s2io_set_multicast, 76288c2ecf20Sopenharmony_ci .ndo_do_ioctl = s2io_ioctl, 76298c2ecf20Sopenharmony_ci .ndo_set_mac_address = s2io_set_mac_addr, 76308c2ecf20Sopenharmony_ci .ndo_change_mtu = s2io_change_mtu, 76318c2ecf20Sopenharmony_ci .ndo_set_features = s2io_set_features, 76328c2ecf20Sopenharmony_ci .ndo_tx_timeout = s2io_tx_watchdog, 76338c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 76348c2ecf20Sopenharmony_ci .ndo_poll_controller = s2io_netpoll, 76358c2ecf20Sopenharmony_ci#endif 76368c2ecf20Sopenharmony_ci}; 76378c2ecf20Sopenharmony_ci 76388c2ecf20Sopenharmony_ci/** 76398c2ecf20Sopenharmony_ci * s2io_init_nic - Initialization of the adapter . 76408c2ecf20Sopenharmony_ci * @pdev : structure containing the PCI related information of the device. 76418c2ecf20Sopenharmony_ci * @pre: List of PCI devices supported by the driver listed in s2io_tbl. 76428c2ecf20Sopenharmony_ci * Description: 76438c2ecf20Sopenharmony_ci * The function initializes an adapter identified by the pci_dec structure. 76448c2ecf20Sopenharmony_ci * All OS related initialization including memory and device structure and 76458c2ecf20Sopenharmony_ci * initlaization of the device private variable is done. Also the swapper 76468c2ecf20Sopenharmony_ci * control register is initialized to enable read and write into the I/O 76478c2ecf20Sopenharmony_ci * registers of the device. 76488c2ecf20Sopenharmony_ci * Return value: 76498c2ecf20Sopenharmony_ci * returns 0 on success and negative on failure. 76508c2ecf20Sopenharmony_ci */ 76518c2ecf20Sopenharmony_ci 76528c2ecf20Sopenharmony_cistatic int 76538c2ecf20Sopenharmony_cis2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) 76548c2ecf20Sopenharmony_ci{ 76558c2ecf20Sopenharmony_ci struct s2io_nic *sp; 76568c2ecf20Sopenharmony_ci struct net_device *dev; 76578c2ecf20Sopenharmony_ci int i, j, ret; 76588c2ecf20Sopenharmony_ci int dma_flag = false; 76598c2ecf20Sopenharmony_ci u32 mac_up, mac_down; 76608c2ecf20Sopenharmony_ci u64 val64 = 0, tmp64 = 0; 76618c2ecf20Sopenharmony_ci struct XENA_dev_config __iomem *bar0 = NULL; 76628c2ecf20Sopenharmony_ci u16 subid; 76638c2ecf20Sopenharmony_ci struct config_param *config; 76648c2ecf20Sopenharmony_ci struct mac_info *mac_control; 76658c2ecf20Sopenharmony_ci int mode; 76668c2ecf20Sopenharmony_ci u8 dev_intr_type = intr_type; 76678c2ecf20Sopenharmony_ci u8 dev_multiq = 0; 76688c2ecf20Sopenharmony_ci 76698c2ecf20Sopenharmony_ci ret = s2io_verify_parm(pdev, &dev_intr_type, &dev_multiq); 76708c2ecf20Sopenharmony_ci if (ret) 76718c2ecf20Sopenharmony_ci return ret; 76728c2ecf20Sopenharmony_ci 76738c2ecf20Sopenharmony_ci ret = pci_enable_device(pdev); 76748c2ecf20Sopenharmony_ci if (ret) { 76758c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 76768c2ecf20Sopenharmony_ci "%s: pci_enable_device failed\n", __func__); 76778c2ecf20Sopenharmony_ci return ret; 76788c2ecf20Sopenharmony_ci } 76798c2ecf20Sopenharmony_ci 76808c2ecf20Sopenharmony_ci if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { 76818c2ecf20Sopenharmony_ci DBG_PRINT(INIT_DBG, "%s: Using 64bit DMA\n", __func__); 76828c2ecf20Sopenharmony_ci dma_flag = true; 76838c2ecf20Sopenharmony_ci if (dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64))) { 76848c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 76858c2ecf20Sopenharmony_ci "Unable to obtain 64bit DMA for coherent allocations\n"); 76868c2ecf20Sopenharmony_ci pci_disable_device(pdev); 76878c2ecf20Sopenharmony_ci return -ENOMEM; 76888c2ecf20Sopenharmony_ci } 76898c2ecf20Sopenharmony_ci } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { 76908c2ecf20Sopenharmony_ci DBG_PRINT(INIT_DBG, "%s: Using 32bit DMA\n", __func__); 76918c2ecf20Sopenharmony_ci } else { 76928c2ecf20Sopenharmony_ci pci_disable_device(pdev); 76938c2ecf20Sopenharmony_ci return -ENOMEM; 76948c2ecf20Sopenharmony_ci } 76958c2ecf20Sopenharmony_ci ret = pci_request_regions(pdev, s2io_driver_name); 76968c2ecf20Sopenharmony_ci if (ret) { 76978c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Request Regions failed - %x\n", 76988c2ecf20Sopenharmony_ci __func__, ret); 76998c2ecf20Sopenharmony_ci pci_disable_device(pdev); 77008c2ecf20Sopenharmony_ci return -ENODEV; 77018c2ecf20Sopenharmony_ci } 77028c2ecf20Sopenharmony_ci if (dev_multiq) 77038c2ecf20Sopenharmony_ci dev = alloc_etherdev_mq(sizeof(struct s2io_nic), tx_fifo_num); 77048c2ecf20Sopenharmony_ci else 77058c2ecf20Sopenharmony_ci dev = alloc_etherdev(sizeof(struct s2io_nic)); 77068c2ecf20Sopenharmony_ci if (dev == NULL) { 77078c2ecf20Sopenharmony_ci pci_disable_device(pdev); 77088c2ecf20Sopenharmony_ci pci_release_regions(pdev); 77098c2ecf20Sopenharmony_ci return -ENODEV; 77108c2ecf20Sopenharmony_ci } 77118c2ecf20Sopenharmony_ci 77128c2ecf20Sopenharmony_ci pci_set_master(pdev); 77138c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, dev); 77148c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 77158c2ecf20Sopenharmony_ci 77168c2ecf20Sopenharmony_ci /* Private member variable initialized to s2io NIC structure */ 77178c2ecf20Sopenharmony_ci sp = netdev_priv(dev); 77188c2ecf20Sopenharmony_ci sp->dev = dev; 77198c2ecf20Sopenharmony_ci sp->pdev = pdev; 77208c2ecf20Sopenharmony_ci sp->high_dma_flag = dma_flag; 77218c2ecf20Sopenharmony_ci sp->device_enabled_once = false; 77228c2ecf20Sopenharmony_ci if (rx_ring_mode == 1) 77238c2ecf20Sopenharmony_ci sp->rxd_mode = RXD_MODE_1; 77248c2ecf20Sopenharmony_ci if (rx_ring_mode == 2) 77258c2ecf20Sopenharmony_ci sp->rxd_mode = RXD_MODE_3B; 77268c2ecf20Sopenharmony_ci 77278c2ecf20Sopenharmony_ci sp->config.intr_type = dev_intr_type; 77288c2ecf20Sopenharmony_ci 77298c2ecf20Sopenharmony_ci if ((pdev->device == PCI_DEVICE_ID_HERC_WIN) || 77308c2ecf20Sopenharmony_ci (pdev->device == PCI_DEVICE_ID_HERC_UNI)) 77318c2ecf20Sopenharmony_ci sp->device_type = XFRAME_II_DEVICE; 77328c2ecf20Sopenharmony_ci else 77338c2ecf20Sopenharmony_ci sp->device_type = XFRAME_I_DEVICE; 77348c2ecf20Sopenharmony_ci 77358c2ecf20Sopenharmony_ci 77368c2ecf20Sopenharmony_ci /* Initialize some PCI/PCI-X fields of the NIC. */ 77378c2ecf20Sopenharmony_ci s2io_init_pci(sp); 77388c2ecf20Sopenharmony_ci 77398c2ecf20Sopenharmony_ci /* 77408c2ecf20Sopenharmony_ci * Setting the device configuration parameters. 77418c2ecf20Sopenharmony_ci * Most of these parameters can be specified by the user during 77428c2ecf20Sopenharmony_ci * module insertion as they are module loadable parameters. If 77438c2ecf20Sopenharmony_ci * these parameters are not not specified during load time, they 77448c2ecf20Sopenharmony_ci * are initialized with default values. 77458c2ecf20Sopenharmony_ci */ 77468c2ecf20Sopenharmony_ci config = &sp->config; 77478c2ecf20Sopenharmony_ci mac_control = &sp->mac_control; 77488c2ecf20Sopenharmony_ci 77498c2ecf20Sopenharmony_ci config->napi = napi; 77508c2ecf20Sopenharmony_ci config->tx_steering_type = tx_steering_type; 77518c2ecf20Sopenharmony_ci 77528c2ecf20Sopenharmony_ci /* Tx side parameters. */ 77538c2ecf20Sopenharmony_ci if (config->tx_steering_type == TX_PRIORITY_STEERING) 77548c2ecf20Sopenharmony_ci config->tx_fifo_num = MAX_TX_FIFOS; 77558c2ecf20Sopenharmony_ci else 77568c2ecf20Sopenharmony_ci config->tx_fifo_num = tx_fifo_num; 77578c2ecf20Sopenharmony_ci 77588c2ecf20Sopenharmony_ci /* Initialize the fifos used for tx steering */ 77598c2ecf20Sopenharmony_ci if (config->tx_fifo_num < 5) { 77608c2ecf20Sopenharmony_ci if (config->tx_fifo_num == 1) 77618c2ecf20Sopenharmony_ci sp->total_tcp_fifos = 1; 77628c2ecf20Sopenharmony_ci else 77638c2ecf20Sopenharmony_ci sp->total_tcp_fifos = config->tx_fifo_num - 1; 77648c2ecf20Sopenharmony_ci sp->udp_fifo_idx = config->tx_fifo_num - 1; 77658c2ecf20Sopenharmony_ci sp->total_udp_fifos = 1; 77668c2ecf20Sopenharmony_ci sp->other_fifo_idx = sp->total_tcp_fifos - 1; 77678c2ecf20Sopenharmony_ci } else { 77688c2ecf20Sopenharmony_ci sp->total_tcp_fifos = (tx_fifo_num - FIFO_UDP_MAX_NUM - 77698c2ecf20Sopenharmony_ci FIFO_OTHER_MAX_NUM); 77708c2ecf20Sopenharmony_ci sp->udp_fifo_idx = sp->total_tcp_fifos; 77718c2ecf20Sopenharmony_ci sp->total_udp_fifos = FIFO_UDP_MAX_NUM; 77728c2ecf20Sopenharmony_ci sp->other_fifo_idx = sp->udp_fifo_idx + FIFO_UDP_MAX_NUM; 77738c2ecf20Sopenharmony_ci } 77748c2ecf20Sopenharmony_ci 77758c2ecf20Sopenharmony_ci config->multiq = dev_multiq; 77768c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) { 77778c2ecf20Sopenharmony_ci struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; 77788c2ecf20Sopenharmony_ci 77798c2ecf20Sopenharmony_ci tx_cfg->fifo_len = tx_fifo_len[i]; 77808c2ecf20Sopenharmony_ci tx_cfg->fifo_priority = i; 77818c2ecf20Sopenharmony_ci } 77828c2ecf20Sopenharmony_ci 77838c2ecf20Sopenharmony_ci /* mapping the QoS priority to the configured fifos */ 77848c2ecf20Sopenharmony_ci for (i = 0; i < MAX_TX_FIFOS; i++) 77858c2ecf20Sopenharmony_ci config->fifo_mapping[i] = fifo_map[config->tx_fifo_num - 1][i]; 77868c2ecf20Sopenharmony_ci 77878c2ecf20Sopenharmony_ci /* map the hashing selector table to the configured fifos */ 77888c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) 77898c2ecf20Sopenharmony_ci sp->fifo_selector[i] = fifo_selector[i]; 77908c2ecf20Sopenharmony_ci 77918c2ecf20Sopenharmony_ci 77928c2ecf20Sopenharmony_ci config->tx_intr_type = TXD_INT_TYPE_UTILZ; 77938c2ecf20Sopenharmony_ci for (i = 0; i < config->tx_fifo_num; i++) { 77948c2ecf20Sopenharmony_ci struct tx_fifo_config *tx_cfg = &config->tx_cfg[i]; 77958c2ecf20Sopenharmony_ci 77968c2ecf20Sopenharmony_ci tx_cfg->f_no_snoop = (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER); 77978c2ecf20Sopenharmony_ci if (tx_cfg->fifo_len < 65) { 77988c2ecf20Sopenharmony_ci config->tx_intr_type = TXD_INT_TYPE_PER_LIST; 77998c2ecf20Sopenharmony_ci break; 78008c2ecf20Sopenharmony_ci } 78018c2ecf20Sopenharmony_ci } 78028c2ecf20Sopenharmony_ci /* + 2 because one Txd for skb->data and one Txd for UFO */ 78038c2ecf20Sopenharmony_ci config->max_txds = MAX_SKB_FRAGS + 2; 78048c2ecf20Sopenharmony_ci 78058c2ecf20Sopenharmony_ci /* Rx side parameters. */ 78068c2ecf20Sopenharmony_ci config->rx_ring_num = rx_ring_num; 78078c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num; i++) { 78088c2ecf20Sopenharmony_ci struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; 78098c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 78108c2ecf20Sopenharmony_ci 78118c2ecf20Sopenharmony_ci rx_cfg->num_rxd = rx_ring_sz[i] * (rxd_count[sp->rxd_mode] + 1); 78128c2ecf20Sopenharmony_ci rx_cfg->ring_priority = i; 78138c2ecf20Sopenharmony_ci ring->rx_bufs_left = 0; 78148c2ecf20Sopenharmony_ci ring->rxd_mode = sp->rxd_mode; 78158c2ecf20Sopenharmony_ci ring->rxd_count = rxd_count[sp->rxd_mode]; 78168c2ecf20Sopenharmony_ci ring->pdev = sp->pdev; 78178c2ecf20Sopenharmony_ci ring->dev = sp->dev; 78188c2ecf20Sopenharmony_ci } 78198c2ecf20Sopenharmony_ci 78208c2ecf20Sopenharmony_ci for (i = 0; i < rx_ring_num; i++) { 78218c2ecf20Sopenharmony_ci struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; 78228c2ecf20Sopenharmony_ci 78238c2ecf20Sopenharmony_ci rx_cfg->ring_org = RING_ORG_BUFF1; 78248c2ecf20Sopenharmony_ci rx_cfg->f_no_snoop = (NO_SNOOP_RXD | NO_SNOOP_RXD_BUFFER); 78258c2ecf20Sopenharmony_ci } 78268c2ecf20Sopenharmony_ci 78278c2ecf20Sopenharmony_ci /* Setting Mac Control parameters */ 78288c2ecf20Sopenharmony_ci mac_control->rmac_pause_time = rmac_pause_time; 78298c2ecf20Sopenharmony_ci mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3; 78308c2ecf20Sopenharmony_ci mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7; 78318c2ecf20Sopenharmony_ci 78328c2ecf20Sopenharmony_ci 78338c2ecf20Sopenharmony_ci /* initialize the shared memory used by the NIC and the host */ 78348c2ecf20Sopenharmony_ci if (init_shared_mem(sp)) { 78358c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", dev->name); 78368c2ecf20Sopenharmony_ci ret = -ENOMEM; 78378c2ecf20Sopenharmony_ci goto mem_alloc_failed; 78388c2ecf20Sopenharmony_ci } 78398c2ecf20Sopenharmony_ci 78408c2ecf20Sopenharmony_ci sp->bar0 = pci_ioremap_bar(pdev, 0); 78418c2ecf20Sopenharmony_ci if (!sp->bar0) { 78428c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n", 78438c2ecf20Sopenharmony_ci dev->name); 78448c2ecf20Sopenharmony_ci ret = -ENOMEM; 78458c2ecf20Sopenharmony_ci goto bar0_remap_failed; 78468c2ecf20Sopenharmony_ci } 78478c2ecf20Sopenharmony_ci 78488c2ecf20Sopenharmony_ci sp->bar1 = pci_ioremap_bar(pdev, 2); 78498c2ecf20Sopenharmony_ci if (!sp->bar1) { 78508c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n", 78518c2ecf20Sopenharmony_ci dev->name); 78528c2ecf20Sopenharmony_ci ret = -ENOMEM; 78538c2ecf20Sopenharmony_ci goto bar1_remap_failed; 78548c2ecf20Sopenharmony_ci } 78558c2ecf20Sopenharmony_ci 78568c2ecf20Sopenharmony_ci /* Initializing the BAR1 address as the start of the FIFO pointer. */ 78578c2ecf20Sopenharmony_ci for (j = 0; j < MAX_TX_FIFOS; j++) { 78588c2ecf20Sopenharmony_ci mac_control->tx_FIFO_start[j] = sp->bar1 + (j * 0x00020000); 78598c2ecf20Sopenharmony_ci } 78608c2ecf20Sopenharmony_ci 78618c2ecf20Sopenharmony_ci /* Driver entry points */ 78628c2ecf20Sopenharmony_ci dev->netdev_ops = &s2io_netdev_ops; 78638c2ecf20Sopenharmony_ci dev->ethtool_ops = &netdev_ethtool_ops; 78648c2ecf20Sopenharmony_ci dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | 78658c2ecf20Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO6 | 78668c2ecf20Sopenharmony_ci NETIF_F_RXCSUM | NETIF_F_LRO; 78678c2ecf20Sopenharmony_ci dev->features |= dev->hw_features | 78688c2ecf20Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; 78698c2ecf20Sopenharmony_ci if (sp->high_dma_flag == true) 78708c2ecf20Sopenharmony_ci dev->features |= NETIF_F_HIGHDMA; 78718c2ecf20Sopenharmony_ci dev->watchdog_timeo = WATCH_DOG_TIMEOUT; 78728c2ecf20Sopenharmony_ci INIT_WORK(&sp->rst_timer_task, s2io_restart_nic); 78738c2ecf20Sopenharmony_ci INIT_WORK(&sp->set_link_task, s2io_set_link); 78748c2ecf20Sopenharmony_ci 78758c2ecf20Sopenharmony_ci pci_save_state(sp->pdev); 78768c2ecf20Sopenharmony_ci 78778c2ecf20Sopenharmony_ci /* Setting swapper control on the NIC, for proper reset operation */ 78788c2ecf20Sopenharmony_ci if (s2io_set_swapper(sp)) { 78798c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: swapper settings are wrong\n", 78808c2ecf20Sopenharmony_ci dev->name); 78818c2ecf20Sopenharmony_ci ret = -EAGAIN; 78828c2ecf20Sopenharmony_ci goto set_swap_failed; 78838c2ecf20Sopenharmony_ci } 78848c2ecf20Sopenharmony_ci 78858c2ecf20Sopenharmony_ci /* Verify if the Herc works on the slot its placed into */ 78868c2ecf20Sopenharmony_ci if (sp->device_type & XFRAME_II_DEVICE) { 78878c2ecf20Sopenharmony_ci mode = s2io_verify_pci_mode(sp); 78888c2ecf20Sopenharmony_ci if (mode < 0) { 78898c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Unsupported PCI bus mode\n", 78908c2ecf20Sopenharmony_ci __func__); 78918c2ecf20Sopenharmony_ci ret = -EBADSLT; 78928c2ecf20Sopenharmony_ci goto set_swap_failed; 78938c2ecf20Sopenharmony_ci } 78948c2ecf20Sopenharmony_ci } 78958c2ecf20Sopenharmony_ci 78968c2ecf20Sopenharmony_ci if (sp->config.intr_type == MSI_X) { 78978c2ecf20Sopenharmony_ci sp->num_entries = config->rx_ring_num + 1; 78988c2ecf20Sopenharmony_ci ret = s2io_enable_msi_x(sp); 78998c2ecf20Sopenharmony_ci 79008c2ecf20Sopenharmony_ci if (!ret) { 79018c2ecf20Sopenharmony_ci ret = s2io_test_msi(sp); 79028c2ecf20Sopenharmony_ci /* rollback MSI-X, will re-enable during add_isr() */ 79038c2ecf20Sopenharmony_ci remove_msix_isr(sp); 79048c2ecf20Sopenharmony_ci } 79058c2ecf20Sopenharmony_ci if (ret) { 79068c2ecf20Sopenharmony_ci 79078c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 79088c2ecf20Sopenharmony_ci "MSI-X requested but failed to enable\n"); 79098c2ecf20Sopenharmony_ci sp->config.intr_type = INTA; 79108c2ecf20Sopenharmony_ci } 79118c2ecf20Sopenharmony_ci } 79128c2ecf20Sopenharmony_ci 79138c2ecf20Sopenharmony_ci if (config->intr_type == MSI_X) { 79148c2ecf20Sopenharmony_ci for (i = 0; i < config->rx_ring_num ; i++) { 79158c2ecf20Sopenharmony_ci struct ring_info *ring = &mac_control->rings[i]; 79168c2ecf20Sopenharmony_ci 79178c2ecf20Sopenharmony_ci netif_napi_add(dev, &ring->napi, s2io_poll_msix, 64); 79188c2ecf20Sopenharmony_ci } 79198c2ecf20Sopenharmony_ci } else { 79208c2ecf20Sopenharmony_ci netif_napi_add(dev, &sp->napi, s2io_poll_inta, 64); 79218c2ecf20Sopenharmony_ci } 79228c2ecf20Sopenharmony_ci 79238c2ecf20Sopenharmony_ci /* Not needed for Herc */ 79248c2ecf20Sopenharmony_ci if (sp->device_type & XFRAME_I_DEVICE) { 79258c2ecf20Sopenharmony_ci /* 79268c2ecf20Sopenharmony_ci * Fix for all "FFs" MAC address problems observed on 79278c2ecf20Sopenharmony_ci * Alpha platforms 79288c2ecf20Sopenharmony_ci */ 79298c2ecf20Sopenharmony_ci fix_mac_address(sp); 79308c2ecf20Sopenharmony_ci s2io_reset(sp); 79318c2ecf20Sopenharmony_ci } 79328c2ecf20Sopenharmony_ci 79338c2ecf20Sopenharmony_ci /* 79348c2ecf20Sopenharmony_ci * MAC address initialization. 79358c2ecf20Sopenharmony_ci * For now only one mac address will be read and used. 79368c2ecf20Sopenharmony_ci */ 79378c2ecf20Sopenharmony_ci bar0 = sp->bar0; 79388c2ecf20Sopenharmony_ci val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | 79398c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_OFFSET(0 + S2IO_MAC_ADDR_START_OFFSET); 79408c2ecf20Sopenharmony_ci writeq(val64, &bar0->rmac_addr_cmd_mem); 79418c2ecf20Sopenharmony_ci wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem, 79428c2ecf20Sopenharmony_ci RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING, 79438c2ecf20Sopenharmony_ci S2IO_BIT_RESET); 79448c2ecf20Sopenharmony_ci tmp64 = readq(&bar0->rmac_addr_data0_mem); 79458c2ecf20Sopenharmony_ci mac_down = (u32)tmp64; 79468c2ecf20Sopenharmony_ci mac_up = (u32) (tmp64 >> 32); 79478c2ecf20Sopenharmony_ci 79488c2ecf20Sopenharmony_ci sp->def_mac_addr[0].mac_addr[3] = (u8) (mac_up); 79498c2ecf20Sopenharmony_ci sp->def_mac_addr[0].mac_addr[2] = (u8) (mac_up >> 8); 79508c2ecf20Sopenharmony_ci sp->def_mac_addr[0].mac_addr[1] = (u8) (mac_up >> 16); 79518c2ecf20Sopenharmony_ci sp->def_mac_addr[0].mac_addr[0] = (u8) (mac_up >> 24); 79528c2ecf20Sopenharmony_ci sp->def_mac_addr[0].mac_addr[5] = (u8) (mac_down >> 16); 79538c2ecf20Sopenharmony_ci sp->def_mac_addr[0].mac_addr[4] = (u8) (mac_down >> 24); 79548c2ecf20Sopenharmony_ci 79558c2ecf20Sopenharmony_ci /* Set the factory defined MAC address initially */ 79568c2ecf20Sopenharmony_ci dev->addr_len = ETH_ALEN; 79578c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, sp->def_mac_addr, ETH_ALEN); 79588c2ecf20Sopenharmony_ci 79598c2ecf20Sopenharmony_ci /* initialize number of multicast & unicast MAC entries variables */ 79608c2ecf20Sopenharmony_ci if (sp->device_type == XFRAME_I_DEVICE) { 79618c2ecf20Sopenharmony_ci config->max_mc_addr = S2IO_XENA_MAX_MC_ADDRESSES; 79628c2ecf20Sopenharmony_ci config->max_mac_addr = S2IO_XENA_MAX_MAC_ADDRESSES; 79638c2ecf20Sopenharmony_ci config->mc_start_offset = S2IO_XENA_MC_ADDR_START_OFFSET; 79648c2ecf20Sopenharmony_ci } else if (sp->device_type == XFRAME_II_DEVICE) { 79658c2ecf20Sopenharmony_ci config->max_mc_addr = S2IO_HERC_MAX_MC_ADDRESSES; 79668c2ecf20Sopenharmony_ci config->max_mac_addr = S2IO_HERC_MAX_MAC_ADDRESSES; 79678c2ecf20Sopenharmony_ci config->mc_start_offset = S2IO_HERC_MC_ADDR_START_OFFSET; 79688c2ecf20Sopenharmony_ci } 79698c2ecf20Sopenharmony_ci 79708c2ecf20Sopenharmony_ci /* MTU range: 46 - 9600 */ 79718c2ecf20Sopenharmony_ci dev->min_mtu = MIN_MTU; 79728c2ecf20Sopenharmony_ci dev->max_mtu = S2IO_JUMBO_SIZE; 79738c2ecf20Sopenharmony_ci 79748c2ecf20Sopenharmony_ci /* store mac addresses from CAM to s2io_nic structure */ 79758c2ecf20Sopenharmony_ci do_s2io_store_unicast_mc(sp); 79768c2ecf20Sopenharmony_ci 79778c2ecf20Sopenharmony_ci /* Configure MSIX vector for number of rings configured plus one */ 79788c2ecf20Sopenharmony_ci if ((sp->device_type == XFRAME_II_DEVICE) && 79798c2ecf20Sopenharmony_ci (config->intr_type == MSI_X)) 79808c2ecf20Sopenharmony_ci sp->num_entries = config->rx_ring_num + 1; 79818c2ecf20Sopenharmony_ci 79828c2ecf20Sopenharmony_ci /* Store the values of the MSIX table in the s2io_nic structure */ 79838c2ecf20Sopenharmony_ci store_xmsi_data(sp); 79848c2ecf20Sopenharmony_ci /* reset Nic and bring it to known state */ 79858c2ecf20Sopenharmony_ci s2io_reset(sp); 79868c2ecf20Sopenharmony_ci 79878c2ecf20Sopenharmony_ci /* 79888c2ecf20Sopenharmony_ci * Initialize link state flags 79898c2ecf20Sopenharmony_ci * and the card state parameter 79908c2ecf20Sopenharmony_ci */ 79918c2ecf20Sopenharmony_ci sp->state = 0; 79928c2ecf20Sopenharmony_ci 79938c2ecf20Sopenharmony_ci /* Initialize spinlocks */ 79948c2ecf20Sopenharmony_ci for (i = 0; i < sp->config.tx_fifo_num; i++) { 79958c2ecf20Sopenharmony_ci struct fifo_info *fifo = &mac_control->fifos[i]; 79968c2ecf20Sopenharmony_ci 79978c2ecf20Sopenharmony_ci spin_lock_init(&fifo->tx_lock); 79988c2ecf20Sopenharmony_ci } 79998c2ecf20Sopenharmony_ci 80008c2ecf20Sopenharmony_ci /* 80018c2ecf20Sopenharmony_ci * SXE-002: Configure link and activity LED to init state 80028c2ecf20Sopenharmony_ci * on driver load. 80038c2ecf20Sopenharmony_ci */ 80048c2ecf20Sopenharmony_ci subid = sp->pdev->subsystem_device; 80058c2ecf20Sopenharmony_ci if ((subid & 0xFF) >= 0x07) { 80068c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_control); 80078c2ecf20Sopenharmony_ci val64 |= 0x0000800000000000ULL; 80088c2ecf20Sopenharmony_ci writeq(val64, &bar0->gpio_control); 80098c2ecf20Sopenharmony_ci val64 = 0x0411040400000000ULL; 80108c2ecf20Sopenharmony_ci writeq(val64, (void __iomem *)bar0 + 0x2700); 80118c2ecf20Sopenharmony_ci val64 = readq(&bar0->gpio_control); 80128c2ecf20Sopenharmony_ci } 80138c2ecf20Sopenharmony_ci 80148c2ecf20Sopenharmony_ci sp->rx_csum = 1; /* Rx chksum verify enabled by default */ 80158c2ecf20Sopenharmony_ci 80168c2ecf20Sopenharmony_ci if (register_netdev(dev)) { 80178c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Device registration failed\n"); 80188c2ecf20Sopenharmony_ci ret = -ENODEV; 80198c2ecf20Sopenharmony_ci goto register_failed; 80208c2ecf20Sopenharmony_ci } 80218c2ecf20Sopenharmony_ci s2io_vpd_read(sp); 80228c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2010 Exar Corp.\n"); 80238c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n", dev->name, 80248c2ecf20Sopenharmony_ci sp->product_name, pdev->revision); 80258c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, 80268c2ecf20Sopenharmony_ci s2io_driver_version); 80278c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: MAC Address: %pM\n", dev->name, dev->dev_addr); 80288c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Serial number: %s\n", sp->serial_num); 80298c2ecf20Sopenharmony_ci if (sp->device_type & XFRAME_II_DEVICE) { 80308c2ecf20Sopenharmony_ci mode = s2io_print_pci_mode(sp); 80318c2ecf20Sopenharmony_ci if (mode < 0) { 80328c2ecf20Sopenharmony_ci ret = -EBADSLT; 80338c2ecf20Sopenharmony_ci unregister_netdev(dev); 80348c2ecf20Sopenharmony_ci goto set_swap_failed; 80358c2ecf20Sopenharmony_ci } 80368c2ecf20Sopenharmony_ci } 80378c2ecf20Sopenharmony_ci switch (sp->rxd_mode) { 80388c2ecf20Sopenharmony_ci case RXD_MODE_1: 80398c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: 1-Buffer receive mode enabled\n", 80408c2ecf20Sopenharmony_ci dev->name); 80418c2ecf20Sopenharmony_ci break; 80428c2ecf20Sopenharmony_ci case RXD_MODE_3B: 80438c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: 2-Buffer receive mode enabled\n", 80448c2ecf20Sopenharmony_ci dev->name); 80458c2ecf20Sopenharmony_ci break; 80468c2ecf20Sopenharmony_ci } 80478c2ecf20Sopenharmony_ci 80488c2ecf20Sopenharmony_ci switch (sp->config.napi) { 80498c2ecf20Sopenharmony_ci case 0: 80508c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: NAPI disabled\n", dev->name); 80518c2ecf20Sopenharmony_ci break; 80528c2ecf20Sopenharmony_ci case 1: 80538c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name); 80548c2ecf20Sopenharmony_ci break; 80558c2ecf20Sopenharmony_ci } 80568c2ecf20Sopenharmony_ci 80578c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name, 80588c2ecf20Sopenharmony_ci sp->config.tx_fifo_num); 80598c2ecf20Sopenharmony_ci 80608c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Using %d Rx ring(s)\n", dev->name, 80618c2ecf20Sopenharmony_ci sp->config.rx_ring_num); 80628c2ecf20Sopenharmony_ci 80638c2ecf20Sopenharmony_ci switch (sp->config.intr_type) { 80648c2ecf20Sopenharmony_ci case INTA: 80658c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name); 80668c2ecf20Sopenharmony_ci break; 80678c2ecf20Sopenharmony_ci case MSI_X: 80688c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name); 80698c2ecf20Sopenharmony_ci break; 80708c2ecf20Sopenharmony_ci } 80718c2ecf20Sopenharmony_ci if (sp->config.multiq) { 80728c2ecf20Sopenharmony_ci for (i = 0; i < sp->config.tx_fifo_num; i++) { 80738c2ecf20Sopenharmony_ci struct fifo_info *fifo = &mac_control->fifos[i]; 80748c2ecf20Sopenharmony_ci 80758c2ecf20Sopenharmony_ci fifo->multiq = config->multiq; 80768c2ecf20Sopenharmony_ci } 80778c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n", 80788c2ecf20Sopenharmony_ci dev->name); 80798c2ecf20Sopenharmony_ci } else 80808c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Multiqueue support disabled\n", 80818c2ecf20Sopenharmony_ci dev->name); 80828c2ecf20Sopenharmony_ci 80838c2ecf20Sopenharmony_ci switch (sp->config.tx_steering_type) { 80848c2ecf20Sopenharmony_ci case NO_STEERING: 80858c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: No steering enabled for transmit\n", 80868c2ecf20Sopenharmony_ci dev->name); 80878c2ecf20Sopenharmony_ci break; 80888c2ecf20Sopenharmony_ci case TX_PRIORITY_STEERING: 80898c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 80908c2ecf20Sopenharmony_ci "%s: Priority steering enabled for transmit\n", 80918c2ecf20Sopenharmony_ci dev->name); 80928c2ecf20Sopenharmony_ci break; 80938c2ecf20Sopenharmony_ci case TX_DEFAULT_STEERING: 80948c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, 80958c2ecf20Sopenharmony_ci "%s: Default steering enabled for transmit\n", 80968c2ecf20Sopenharmony_ci dev->name); 80978c2ecf20Sopenharmony_ci } 80988c2ecf20Sopenharmony_ci 80998c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n", 81008c2ecf20Sopenharmony_ci dev->name); 81018c2ecf20Sopenharmony_ci /* Initialize device name */ 81028c2ecf20Sopenharmony_ci snprintf(sp->name, sizeof(sp->name), "%s Neterion %s", dev->name, 81038c2ecf20Sopenharmony_ci sp->product_name); 81048c2ecf20Sopenharmony_ci 81058c2ecf20Sopenharmony_ci if (vlan_tag_strip) 81068c2ecf20Sopenharmony_ci sp->vlan_strip_flag = 1; 81078c2ecf20Sopenharmony_ci else 81088c2ecf20Sopenharmony_ci sp->vlan_strip_flag = 0; 81098c2ecf20Sopenharmony_ci 81108c2ecf20Sopenharmony_ci /* 81118c2ecf20Sopenharmony_ci * Make Link state as off at this point, when the Link change 81128c2ecf20Sopenharmony_ci * interrupt comes the state will be automatically changed to 81138c2ecf20Sopenharmony_ci * the right state. 81148c2ecf20Sopenharmony_ci */ 81158c2ecf20Sopenharmony_ci netif_carrier_off(dev); 81168c2ecf20Sopenharmony_ci 81178c2ecf20Sopenharmony_ci return 0; 81188c2ecf20Sopenharmony_ci 81198c2ecf20Sopenharmony_ciregister_failed: 81208c2ecf20Sopenharmony_ciset_swap_failed: 81218c2ecf20Sopenharmony_ci iounmap(sp->bar1); 81228c2ecf20Sopenharmony_cibar1_remap_failed: 81238c2ecf20Sopenharmony_ci iounmap(sp->bar0); 81248c2ecf20Sopenharmony_cibar0_remap_failed: 81258c2ecf20Sopenharmony_cimem_alloc_failed: 81268c2ecf20Sopenharmony_ci free_shared_mem(sp); 81278c2ecf20Sopenharmony_ci pci_disable_device(pdev); 81288c2ecf20Sopenharmony_ci pci_release_regions(pdev); 81298c2ecf20Sopenharmony_ci free_netdev(dev); 81308c2ecf20Sopenharmony_ci 81318c2ecf20Sopenharmony_ci return ret; 81328c2ecf20Sopenharmony_ci} 81338c2ecf20Sopenharmony_ci 81348c2ecf20Sopenharmony_ci/** 81358c2ecf20Sopenharmony_ci * s2io_rem_nic - Free the PCI device 81368c2ecf20Sopenharmony_ci * @pdev: structure containing the PCI related information of the device. 81378c2ecf20Sopenharmony_ci * Description: This function is called by the Pci subsystem to release a 81388c2ecf20Sopenharmony_ci * PCI device and free up all resource held up by the device. This could 81398c2ecf20Sopenharmony_ci * be in response to a Hot plug event or when the driver is to be removed 81408c2ecf20Sopenharmony_ci * from memory. 81418c2ecf20Sopenharmony_ci */ 81428c2ecf20Sopenharmony_ci 81438c2ecf20Sopenharmony_cistatic void s2io_rem_nic(struct pci_dev *pdev) 81448c2ecf20Sopenharmony_ci{ 81458c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 81468c2ecf20Sopenharmony_ci struct s2io_nic *sp; 81478c2ecf20Sopenharmony_ci 81488c2ecf20Sopenharmony_ci if (dev == NULL) { 81498c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n"); 81508c2ecf20Sopenharmony_ci return; 81518c2ecf20Sopenharmony_ci } 81528c2ecf20Sopenharmony_ci 81538c2ecf20Sopenharmony_ci sp = netdev_priv(dev); 81548c2ecf20Sopenharmony_ci 81558c2ecf20Sopenharmony_ci cancel_work_sync(&sp->rst_timer_task); 81568c2ecf20Sopenharmony_ci cancel_work_sync(&sp->set_link_task); 81578c2ecf20Sopenharmony_ci 81588c2ecf20Sopenharmony_ci unregister_netdev(dev); 81598c2ecf20Sopenharmony_ci 81608c2ecf20Sopenharmony_ci free_shared_mem(sp); 81618c2ecf20Sopenharmony_ci iounmap(sp->bar0); 81628c2ecf20Sopenharmony_ci iounmap(sp->bar1); 81638c2ecf20Sopenharmony_ci pci_release_regions(pdev); 81648c2ecf20Sopenharmony_ci free_netdev(dev); 81658c2ecf20Sopenharmony_ci pci_disable_device(pdev); 81668c2ecf20Sopenharmony_ci} 81678c2ecf20Sopenharmony_ci 81688c2ecf20Sopenharmony_cimodule_pci_driver(s2io_driver); 81698c2ecf20Sopenharmony_ci 81708c2ecf20Sopenharmony_cistatic int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, 81718c2ecf20Sopenharmony_ci struct tcphdr **tcp, struct RxD_t *rxdp, 81728c2ecf20Sopenharmony_ci struct s2io_nic *sp) 81738c2ecf20Sopenharmony_ci{ 81748c2ecf20Sopenharmony_ci int ip_off; 81758c2ecf20Sopenharmony_ci u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len; 81768c2ecf20Sopenharmony_ci 81778c2ecf20Sopenharmony_ci if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) { 81788c2ecf20Sopenharmony_ci DBG_PRINT(INIT_DBG, 81798c2ecf20Sopenharmony_ci "%s: Non-TCP frames not supported for LRO\n", 81808c2ecf20Sopenharmony_ci __func__); 81818c2ecf20Sopenharmony_ci return -1; 81828c2ecf20Sopenharmony_ci } 81838c2ecf20Sopenharmony_ci 81848c2ecf20Sopenharmony_ci /* Checking for DIX type or DIX type with VLAN */ 81858c2ecf20Sopenharmony_ci if ((l2_type == 0) || (l2_type == 4)) { 81868c2ecf20Sopenharmony_ci ip_off = HEADER_ETHERNET_II_802_3_SIZE; 81878c2ecf20Sopenharmony_ci /* 81888c2ecf20Sopenharmony_ci * If vlan stripping is disabled and the frame is VLAN tagged, 81898c2ecf20Sopenharmony_ci * shift the offset by the VLAN header size bytes. 81908c2ecf20Sopenharmony_ci */ 81918c2ecf20Sopenharmony_ci if ((!sp->vlan_strip_flag) && 81928c2ecf20Sopenharmony_ci (rxdp->Control_1 & RXD_FRAME_VLAN_TAG)) 81938c2ecf20Sopenharmony_ci ip_off += HEADER_VLAN_SIZE; 81948c2ecf20Sopenharmony_ci } else { 81958c2ecf20Sopenharmony_ci /* LLC, SNAP etc are considered non-mergeable */ 81968c2ecf20Sopenharmony_ci return -1; 81978c2ecf20Sopenharmony_ci } 81988c2ecf20Sopenharmony_ci 81998c2ecf20Sopenharmony_ci *ip = (struct iphdr *)(buffer + ip_off); 82008c2ecf20Sopenharmony_ci ip_len = (u8)((*ip)->ihl); 82018c2ecf20Sopenharmony_ci ip_len <<= 2; 82028c2ecf20Sopenharmony_ci *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len); 82038c2ecf20Sopenharmony_ci 82048c2ecf20Sopenharmony_ci return 0; 82058c2ecf20Sopenharmony_ci} 82068c2ecf20Sopenharmony_ci 82078c2ecf20Sopenharmony_cistatic int check_for_socket_match(struct lro *lro, struct iphdr *ip, 82088c2ecf20Sopenharmony_ci struct tcphdr *tcp) 82098c2ecf20Sopenharmony_ci{ 82108c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); 82118c2ecf20Sopenharmony_ci if ((lro->iph->saddr != ip->saddr) || 82128c2ecf20Sopenharmony_ci (lro->iph->daddr != ip->daddr) || 82138c2ecf20Sopenharmony_ci (lro->tcph->source != tcp->source) || 82148c2ecf20Sopenharmony_ci (lro->tcph->dest != tcp->dest)) 82158c2ecf20Sopenharmony_ci return -1; 82168c2ecf20Sopenharmony_ci return 0; 82178c2ecf20Sopenharmony_ci} 82188c2ecf20Sopenharmony_ci 82198c2ecf20Sopenharmony_cistatic inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp) 82208c2ecf20Sopenharmony_ci{ 82218c2ecf20Sopenharmony_ci return ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2); 82228c2ecf20Sopenharmony_ci} 82238c2ecf20Sopenharmony_ci 82248c2ecf20Sopenharmony_cistatic void initiate_new_session(struct lro *lro, u8 *l2h, 82258c2ecf20Sopenharmony_ci struct iphdr *ip, struct tcphdr *tcp, 82268c2ecf20Sopenharmony_ci u32 tcp_pyld_len, u16 vlan_tag) 82278c2ecf20Sopenharmony_ci{ 82288c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); 82298c2ecf20Sopenharmony_ci lro->l2h = l2h; 82308c2ecf20Sopenharmony_ci lro->iph = ip; 82318c2ecf20Sopenharmony_ci lro->tcph = tcp; 82328c2ecf20Sopenharmony_ci lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq); 82338c2ecf20Sopenharmony_ci lro->tcp_ack = tcp->ack_seq; 82348c2ecf20Sopenharmony_ci lro->sg_num = 1; 82358c2ecf20Sopenharmony_ci lro->total_len = ntohs(ip->tot_len); 82368c2ecf20Sopenharmony_ci lro->frags_len = 0; 82378c2ecf20Sopenharmony_ci lro->vlan_tag = vlan_tag; 82388c2ecf20Sopenharmony_ci /* 82398c2ecf20Sopenharmony_ci * Check if we saw TCP timestamp. 82408c2ecf20Sopenharmony_ci * Other consistency checks have already been done. 82418c2ecf20Sopenharmony_ci */ 82428c2ecf20Sopenharmony_ci if (tcp->doff == 8) { 82438c2ecf20Sopenharmony_ci __be32 *ptr; 82448c2ecf20Sopenharmony_ci ptr = (__be32 *)(tcp+1); 82458c2ecf20Sopenharmony_ci lro->saw_ts = 1; 82468c2ecf20Sopenharmony_ci lro->cur_tsval = ntohl(*(ptr+1)); 82478c2ecf20Sopenharmony_ci lro->cur_tsecr = *(ptr+2); 82488c2ecf20Sopenharmony_ci } 82498c2ecf20Sopenharmony_ci lro->in_use = 1; 82508c2ecf20Sopenharmony_ci} 82518c2ecf20Sopenharmony_ci 82528c2ecf20Sopenharmony_cistatic void update_L3L4_header(struct s2io_nic *sp, struct lro *lro) 82538c2ecf20Sopenharmony_ci{ 82548c2ecf20Sopenharmony_ci struct iphdr *ip = lro->iph; 82558c2ecf20Sopenharmony_ci struct tcphdr *tcp = lro->tcph; 82568c2ecf20Sopenharmony_ci struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; 82578c2ecf20Sopenharmony_ci 82588c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); 82598c2ecf20Sopenharmony_ci 82608c2ecf20Sopenharmony_ci /* Update L3 header */ 82618c2ecf20Sopenharmony_ci csum_replace2(&ip->check, ip->tot_len, htons(lro->total_len)); 82628c2ecf20Sopenharmony_ci ip->tot_len = htons(lro->total_len); 82638c2ecf20Sopenharmony_ci 82648c2ecf20Sopenharmony_ci /* Update L4 header */ 82658c2ecf20Sopenharmony_ci tcp->ack_seq = lro->tcp_ack; 82668c2ecf20Sopenharmony_ci tcp->window = lro->window; 82678c2ecf20Sopenharmony_ci 82688c2ecf20Sopenharmony_ci /* Update tsecr field if this session has timestamps enabled */ 82698c2ecf20Sopenharmony_ci if (lro->saw_ts) { 82708c2ecf20Sopenharmony_ci __be32 *ptr = (__be32 *)(tcp + 1); 82718c2ecf20Sopenharmony_ci *(ptr+2) = lro->cur_tsecr; 82728c2ecf20Sopenharmony_ci } 82738c2ecf20Sopenharmony_ci 82748c2ecf20Sopenharmony_ci /* Update counters required for calculation of 82758c2ecf20Sopenharmony_ci * average no. of packets aggregated. 82768c2ecf20Sopenharmony_ci */ 82778c2ecf20Sopenharmony_ci swstats->sum_avg_pkts_aggregated += lro->sg_num; 82788c2ecf20Sopenharmony_ci swstats->num_aggregations++; 82798c2ecf20Sopenharmony_ci} 82808c2ecf20Sopenharmony_ci 82818c2ecf20Sopenharmony_cistatic void aggregate_new_rx(struct lro *lro, struct iphdr *ip, 82828c2ecf20Sopenharmony_ci struct tcphdr *tcp, u32 l4_pyld) 82838c2ecf20Sopenharmony_ci{ 82848c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); 82858c2ecf20Sopenharmony_ci lro->total_len += l4_pyld; 82868c2ecf20Sopenharmony_ci lro->frags_len += l4_pyld; 82878c2ecf20Sopenharmony_ci lro->tcp_next_seq += l4_pyld; 82888c2ecf20Sopenharmony_ci lro->sg_num++; 82898c2ecf20Sopenharmony_ci 82908c2ecf20Sopenharmony_ci /* Update ack seq no. and window ad(from this pkt) in LRO object */ 82918c2ecf20Sopenharmony_ci lro->tcp_ack = tcp->ack_seq; 82928c2ecf20Sopenharmony_ci lro->window = tcp->window; 82938c2ecf20Sopenharmony_ci 82948c2ecf20Sopenharmony_ci if (lro->saw_ts) { 82958c2ecf20Sopenharmony_ci __be32 *ptr; 82968c2ecf20Sopenharmony_ci /* Update tsecr and tsval from this packet */ 82978c2ecf20Sopenharmony_ci ptr = (__be32 *)(tcp+1); 82988c2ecf20Sopenharmony_ci lro->cur_tsval = ntohl(*(ptr+1)); 82998c2ecf20Sopenharmony_ci lro->cur_tsecr = *(ptr + 2); 83008c2ecf20Sopenharmony_ci } 83018c2ecf20Sopenharmony_ci} 83028c2ecf20Sopenharmony_ci 83038c2ecf20Sopenharmony_cistatic int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip, 83048c2ecf20Sopenharmony_ci struct tcphdr *tcp, u32 tcp_pyld_len) 83058c2ecf20Sopenharmony_ci{ 83068c2ecf20Sopenharmony_ci u8 *ptr; 83078c2ecf20Sopenharmony_ci 83088c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__); 83098c2ecf20Sopenharmony_ci 83108c2ecf20Sopenharmony_ci if (!tcp_pyld_len) { 83118c2ecf20Sopenharmony_ci /* Runt frame or a pure ack */ 83128c2ecf20Sopenharmony_ci return -1; 83138c2ecf20Sopenharmony_ci } 83148c2ecf20Sopenharmony_ci 83158c2ecf20Sopenharmony_ci if (ip->ihl != 5) /* IP has options */ 83168c2ecf20Sopenharmony_ci return -1; 83178c2ecf20Sopenharmony_ci 83188c2ecf20Sopenharmony_ci /* If we see CE codepoint in IP header, packet is not mergeable */ 83198c2ecf20Sopenharmony_ci if (INET_ECN_is_ce(ipv4_get_dsfield(ip))) 83208c2ecf20Sopenharmony_ci return -1; 83218c2ecf20Sopenharmony_ci 83228c2ecf20Sopenharmony_ci /* If we see ECE or CWR flags in TCP header, packet is not mergeable */ 83238c2ecf20Sopenharmony_ci if (tcp->urg || tcp->psh || tcp->rst || 83248c2ecf20Sopenharmony_ci tcp->syn || tcp->fin || 83258c2ecf20Sopenharmony_ci tcp->ece || tcp->cwr || !tcp->ack) { 83268c2ecf20Sopenharmony_ci /* 83278c2ecf20Sopenharmony_ci * Currently recognize only the ack control word and 83288c2ecf20Sopenharmony_ci * any other control field being set would result in 83298c2ecf20Sopenharmony_ci * flushing the LRO session 83308c2ecf20Sopenharmony_ci */ 83318c2ecf20Sopenharmony_ci return -1; 83328c2ecf20Sopenharmony_ci } 83338c2ecf20Sopenharmony_ci 83348c2ecf20Sopenharmony_ci /* 83358c2ecf20Sopenharmony_ci * Allow only one TCP timestamp option. Don't aggregate if 83368c2ecf20Sopenharmony_ci * any other options are detected. 83378c2ecf20Sopenharmony_ci */ 83388c2ecf20Sopenharmony_ci if (tcp->doff != 5 && tcp->doff != 8) 83398c2ecf20Sopenharmony_ci return -1; 83408c2ecf20Sopenharmony_ci 83418c2ecf20Sopenharmony_ci if (tcp->doff == 8) { 83428c2ecf20Sopenharmony_ci ptr = (u8 *)(tcp + 1); 83438c2ecf20Sopenharmony_ci while (*ptr == TCPOPT_NOP) 83448c2ecf20Sopenharmony_ci ptr++; 83458c2ecf20Sopenharmony_ci if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP) 83468c2ecf20Sopenharmony_ci return -1; 83478c2ecf20Sopenharmony_ci 83488c2ecf20Sopenharmony_ci /* Ensure timestamp value increases monotonically */ 83498c2ecf20Sopenharmony_ci if (l_lro) 83508c2ecf20Sopenharmony_ci if (l_lro->cur_tsval > ntohl(*((__be32 *)(ptr+2)))) 83518c2ecf20Sopenharmony_ci return -1; 83528c2ecf20Sopenharmony_ci 83538c2ecf20Sopenharmony_ci /* timestamp echo reply should be non-zero */ 83548c2ecf20Sopenharmony_ci if (*((__be32 *)(ptr+6)) == 0) 83558c2ecf20Sopenharmony_ci return -1; 83568c2ecf20Sopenharmony_ci } 83578c2ecf20Sopenharmony_ci 83588c2ecf20Sopenharmony_ci return 0; 83598c2ecf20Sopenharmony_ci} 83608c2ecf20Sopenharmony_ci 83618c2ecf20Sopenharmony_cistatic int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, 83628c2ecf20Sopenharmony_ci u8 **tcp, u32 *tcp_len, struct lro **lro, 83638c2ecf20Sopenharmony_ci struct RxD_t *rxdp, struct s2io_nic *sp) 83648c2ecf20Sopenharmony_ci{ 83658c2ecf20Sopenharmony_ci struct iphdr *ip; 83668c2ecf20Sopenharmony_ci struct tcphdr *tcph; 83678c2ecf20Sopenharmony_ci int ret = 0, i; 83688c2ecf20Sopenharmony_ci u16 vlan_tag = 0; 83698c2ecf20Sopenharmony_ci struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; 83708c2ecf20Sopenharmony_ci 83718c2ecf20Sopenharmony_ci ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp, 83728c2ecf20Sopenharmony_ci rxdp, sp); 83738c2ecf20Sopenharmony_ci if (ret) 83748c2ecf20Sopenharmony_ci return ret; 83758c2ecf20Sopenharmony_ci 83768c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "IP Saddr: %x Daddr: %x\n", ip->saddr, ip->daddr); 83778c2ecf20Sopenharmony_ci 83788c2ecf20Sopenharmony_ci vlan_tag = RXD_GET_VLAN_TAG(rxdp->Control_2); 83798c2ecf20Sopenharmony_ci tcph = (struct tcphdr *)*tcp; 83808c2ecf20Sopenharmony_ci *tcp_len = get_l4_pyld_length(ip, tcph); 83818c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LRO_SESSIONS; i++) { 83828c2ecf20Sopenharmony_ci struct lro *l_lro = &ring_data->lro0_n[i]; 83838c2ecf20Sopenharmony_ci if (l_lro->in_use) { 83848c2ecf20Sopenharmony_ci if (check_for_socket_match(l_lro, ip, tcph)) 83858c2ecf20Sopenharmony_ci continue; 83868c2ecf20Sopenharmony_ci /* Sock pair matched */ 83878c2ecf20Sopenharmony_ci *lro = l_lro; 83888c2ecf20Sopenharmony_ci 83898c2ecf20Sopenharmony_ci if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) { 83908c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: Out of sequence. " 83918c2ecf20Sopenharmony_ci "expected 0x%x, actual 0x%x\n", 83928c2ecf20Sopenharmony_ci __func__, 83938c2ecf20Sopenharmony_ci (*lro)->tcp_next_seq, 83948c2ecf20Sopenharmony_ci ntohl(tcph->seq)); 83958c2ecf20Sopenharmony_ci 83968c2ecf20Sopenharmony_ci swstats->outof_sequence_pkts++; 83978c2ecf20Sopenharmony_ci ret = 2; 83988c2ecf20Sopenharmony_ci break; 83998c2ecf20Sopenharmony_ci } 84008c2ecf20Sopenharmony_ci 84018c2ecf20Sopenharmony_ci if (!verify_l3_l4_lro_capable(l_lro, ip, tcph, 84028c2ecf20Sopenharmony_ci *tcp_len)) 84038c2ecf20Sopenharmony_ci ret = 1; /* Aggregate */ 84048c2ecf20Sopenharmony_ci else 84058c2ecf20Sopenharmony_ci ret = 2; /* Flush both */ 84068c2ecf20Sopenharmony_ci break; 84078c2ecf20Sopenharmony_ci } 84088c2ecf20Sopenharmony_ci } 84098c2ecf20Sopenharmony_ci 84108c2ecf20Sopenharmony_ci if (ret == 0) { 84118c2ecf20Sopenharmony_ci /* Before searching for available LRO objects, 84128c2ecf20Sopenharmony_ci * check if the pkt is L3/L4 aggregatable. If not 84138c2ecf20Sopenharmony_ci * don't create new LRO session. Just send this 84148c2ecf20Sopenharmony_ci * packet up. 84158c2ecf20Sopenharmony_ci */ 84168c2ecf20Sopenharmony_ci if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) 84178c2ecf20Sopenharmony_ci return 5; 84188c2ecf20Sopenharmony_ci 84198c2ecf20Sopenharmony_ci for (i = 0; i < MAX_LRO_SESSIONS; i++) { 84208c2ecf20Sopenharmony_ci struct lro *l_lro = &ring_data->lro0_n[i]; 84218c2ecf20Sopenharmony_ci if (!(l_lro->in_use)) { 84228c2ecf20Sopenharmony_ci *lro = l_lro; 84238c2ecf20Sopenharmony_ci ret = 3; /* Begin anew */ 84248c2ecf20Sopenharmony_ci break; 84258c2ecf20Sopenharmony_ci } 84268c2ecf20Sopenharmony_ci } 84278c2ecf20Sopenharmony_ci } 84288c2ecf20Sopenharmony_ci 84298c2ecf20Sopenharmony_ci if (ret == 0) { /* sessions exceeded */ 84308c2ecf20Sopenharmony_ci DBG_PRINT(INFO_DBG, "%s: All LRO sessions already in use\n", 84318c2ecf20Sopenharmony_ci __func__); 84328c2ecf20Sopenharmony_ci *lro = NULL; 84338c2ecf20Sopenharmony_ci return ret; 84348c2ecf20Sopenharmony_ci } 84358c2ecf20Sopenharmony_ci 84368c2ecf20Sopenharmony_ci switch (ret) { 84378c2ecf20Sopenharmony_ci case 3: 84388c2ecf20Sopenharmony_ci initiate_new_session(*lro, buffer, ip, tcph, *tcp_len, 84398c2ecf20Sopenharmony_ci vlan_tag); 84408c2ecf20Sopenharmony_ci break; 84418c2ecf20Sopenharmony_ci case 2: 84428c2ecf20Sopenharmony_ci update_L3L4_header(sp, *lro); 84438c2ecf20Sopenharmony_ci break; 84448c2ecf20Sopenharmony_ci case 1: 84458c2ecf20Sopenharmony_ci aggregate_new_rx(*lro, ip, tcph, *tcp_len); 84468c2ecf20Sopenharmony_ci if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) { 84478c2ecf20Sopenharmony_ci update_L3L4_header(sp, *lro); 84488c2ecf20Sopenharmony_ci ret = 4; /* Flush the LRO */ 84498c2ecf20Sopenharmony_ci } 84508c2ecf20Sopenharmony_ci break; 84518c2ecf20Sopenharmony_ci default: 84528c2ecf20Sopenharmony_ci DBG_PRINT(ERR_DBG, "%s: Don't know, can't say!!\n", __func__); 84538c2ecf20Sopenharmony_ci break; 84548c2ecf20Sopenharmony_ci } 84558c2ecf20Sopenharmony_ci 84568c2ecf20Sopenharmony_ci return ret; 84578c2ecf20Sopenharmony_ci} 84588c2ecf20Sopenharmony_ci 84598c2ecf20Sopenharmony_cistatic void clear_lro_session(struct lro *lro) 84608c2ecf20Sopenharmony_ci{ 84618c2ecf20Sopenharmony_ci static u16 lro_struct_size = sizeof(struct lro); 84628c2ecf20Sopenharmony_ci 84638c2ecf20Sopenharmony_ci memset(lro, 0, lro_struct_size); 84648c2ecf20Sopenharmony_ci} 84658c2ecf20Sopenharmony_ci 84668c2ecf20Sopenharmony_cistatic void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag) 84678c2ecf20Sopenharmony_ci{ 84688c2ecf20Sopenharmony_ci struct net_device *dev = skb->dev; 84698c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(dev); 84708c2ecf20Sopenharmony_ci 84718c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, dev); 84728c2ecf20Sopenharmony_ci if (vlan_tag && sp->vlan_strip_flag) 84738c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlan_tag); 84748c2ecf20Sopenharmony_ci if (sp->config.napi) 84758c2ecf20Sopenharmony_ci netif_receive_skb(skb); 84768c2ecf20Sopenharmony_ci else 84778c2ecf20Sopenharmony_ci netif_rx(skb); 84788c2ecf20Sopenharmony_ci} 84798c2ecf20Sopenharmony_ci 84808c2ecf20Sopenharmony_cistatic void lro_append_pkt(struct s2io_nic *sp, struct lro *lro, 84818c2ecf20Sopenharmony_ci struct sk_buff *skb, u32 tcp_len) 84828c2ecf20Sopenharmony_ci{ 84838c2ecf20Sopenharmony_ci struct sk_buff *first = lro->parent; 84848c2ecf20Sopenharmony_ci struct swStat *swstats = &sp->mac_control.stats_info->sw_stat; 84858c2ecf20Sopenharmony_ci 84868c2ecf20Sopenharmony_ci first->len += tcp_len; 84878c2ecf20Sopenharmony_ci first->data_len = lro->frags_len; 84888c2ecf20Sopenharmony_ci skb_pull(skb, (skb->len - tcp_len)); 84898c2ecf20Sopenharmony_ci if (skb_shinfo(first)->frag_list) 84908c2ecf20Sopenharmony_ci lro->last_frag->next = skb; 84918c2ecf20Sopenharmony_ci else 84928c2ecf20Sopenharmony_ci skb_shinfo(first)->frag_list = skb; 84938c2ecf20Sopenharmony_ci first->truesize += skb->truesize; 84948c2ecf20Sopenharmony_ci lro->last_frag = skb; 84958c2ecf20Sopenharmony_ci swstats->clubbed_frms_cnt++; 84968c2ecf20Sopenharmony_ci} 84978c2ecf20Sopenharmony_ci 84988c2ecf20Sopenharmony_ci/** 84998c2ecf20Sopenharmony_ci * s2io_io_error_detected - called when PCI error is detected 85008c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 85018c2ecf20Sopenharmony_ci * @state: The current pci connection state 85028c2ecf20Sopenharmony_ci * 85038c2ecf20Sopenharmony_ci * This function is called after a PCI bus error affecting 85048c2ecf20Sopenharmony_ci * this device has been detected. 85058c2ecf20Sopenharmony_ci */ 85068c2ecf20Sopenharmony_cistatic pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, 85078c2ecf20Sopenharmony_ci pci_channel_state_t state) 85088c2ecf20Sopenharmony_ci{ 85098c2ecf20Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 85108c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(netdev); 85118c2ecf20Sopenharmony_ci 85128c2ecf20Sopenharmony_ci netif_device_detach(netdev); 85138c2ecf20Sopenharmony_ci 85148c2ecf20Sopenharmony_ci if (state == pci_channel_io_perm_failure) 85158c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 85168c2ecf20Sopenharmony_ci 85178c2ecf20Sopenharmony_ci if (netif_running(netdev)) { 85188c2ecf20Sopenharmony_ci /* Bring down the card, while avoiding PCI I/O */ 85198c2ecf20Sopenharmony_ci do_s2io_card_down(sp, 0); 85208c2ecf20Sopenharmony_ci } 85218c2ecf20Sopenharmony_ci pci_disable_device(pdev); 85228c2ecf20Sopenharmony_ci 85238c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 85248c2ecf20Sopenharmony_ci} 85258c2ecf20Sopenharmony_ci 85268c2ecf20Sopenharmony_ci/** 85278c2ecf20Sopenharmony_ci * s2io_io_slot_reset - called after the pci bus has been reset. 85288c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 85298c2ecf20Sopenharmony_ci * 85308c2ecf20Sopenharmony_ci * Restart the card from scratch, as if from a cold-boot. 85318c2ecf20Sopenharmony_ci * At this point, the card has exprienced a hard reset, 85328c2ecf20Sopenharmony_ci * followed by fixups by BIOS, and has its config space 85338c2ecf20Sopenharmony_ci * set up identically to what it was at cold boot. 85348c2ecf20Sopenharmony_ci */ 85358c2ecf20Sopenharmony_cistatic pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev) 85368c2ecf20Sopenharmony_ci{ 85378c2ecf20Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 85388c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(netdev); 85398c2ecf20Sopenharmony_ci 85408c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 85418c2ecf20Sopenharmony_ci pr_err("Cannot re-enable PCI device after reset.\n"); 85428c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 85438c2ecf20Sopenharmony_ci } 85448c2ecf20Sopenharmony_ci 85458c2ecf20Sopenharmony_ci pci_set_master(pdev); 85468c2ecf20Sopenharmony_ci s2io_reset(sp); 85478c2ecf20Sopenharmony_ci 85488c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_RECOVERED; 85498c2ecf20Sopenharmony_ci} 85508c2ecf20Sopenharmony_ci 85518c2ecf20Sopenharmony_ci/** 85528c2ecf20Sopenharmony_ci * s2io_io_resume - called when traffic can start flowing again. 85538c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 85548c2ecf20Sopenharmony_ci * 85558c2ecf20Sopenharmony_ci * This callback is called when the error recovery driver tells 85568c2ecf20Sopenharmony_ci * us that its OK to resume normal operation. 85578c2ecf20Sopenharmony_ci */ 85588c2ecf20Sopenharmony_cistatic void s2io_io_resume(struct pci_dev *pdev) 85598c2ecf20Sopenharmony_ci{ 85608c2ecf20Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 85618c2ecf20Sopenharmony_ci struct s2io_nic *sp = netdev_priv(netdev); 85628c2ecf20Sopenharmony_ci 85638c2ecf20Sopenharmony_ci if (netif_running(netdev)) { 85648c2ecf20Sopenharmony_ci if (s2io_card_up(sp)) { 85658c2ecf20Sopenharmony_ci pr_err("Can't bring device back up after reset.\n"); 85668c2ecf20Sopenharmony_ci return; 85678c2ecf20Sopenharmony_ci } 85688c2ecf20Sopenharmony_ci 85698c2ecf20Sopenharmony_ci if (do_s2io_prog_unicast(netdev, netdev->dev_addr) == FAILURE) { 85708c2ecf20Sopenharmony_ci s2io_card_down(sp); 85718c2ecf20Sopenharmony_ci pr_err("Can't restore mac addr after reset.\n"); 85728c2ecf20Sopenharmony_ci return; 85738c2ecf20Sopenharmony_ci } 85748c2ecf20Sopenharmony_ci } 85758c2ecf20Sopenharmony_ci 85768c2ecf20Sopenharmony_ci netif_device_attach(netdev); 85778c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(netdev); 85788c2ecf20Sopenharmony_ci} 8579