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), &reg, 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, &ethtool_xena_stats_keys, stat_size);
65448c2ecf20Sopenharmony_ci		if (sp->device_type == XFRAME_II_DEVICE) {
65458c2ecf20Sopenharmony_ci			memcpy(data + stat_size,
65468c2ecf20Sopenharmony_ci			       &ethtool_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, &ethtool_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