Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/net/ethernet/neterion/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 238 kB image not shown  

Quelle  s2io.c   Sprache: C

 
/************************************************************************
 * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC
 * Copyright(c) 2002-2010 Exar Corp.
 *
 * This software may be used and distributed according to the terms of
 * the GNU General Public License (GPL), incorporated herein by reference.
 * Drivers based on or derived from this code fall under the GPL and must
 * retain the authorship, copyright and license notice.  This file is not
 * a complete program and may only be used when the entire operating
 * system is licensed under the GPL.
 * See the file COPYING in this distribution for more information.
 *
 * Credits:
 * Jeff Garzik : For pointing out the improper error condition
 *   check in the s2io_xmit routine and also some
 *   issues in the Tx watch dog function. Also for
 *   patiently answering all those innumerable
 *   questions regaring the 2.6 porting issues.
 * Stephen Hemminger : Providing proper 2.6 porting mechanism for some
 *   macros available only in 2.6 Kernel.
 * Francois Romieu : For pointing out all code part that were
 *   deprecated and also styling related comments.
 * Grant Grundler : For helping me get rid of some Architecture
 *   dependent code.
 * Christopher Hellwig : Some more 2.6 specific issues in the driver.
 *
 * The module loadable parameters that are supported by the driver and a brief
 * explanation of all the variables.
 *
 * rx_ring_num : This can be used to program the number of receive rings used
 * in the driver.
 * rx_ring_sz: This defines the number of receive blocks each ring can have.
 *     This is also an array of size 8.
 * rx_ring_mode: This defines the operation mode of all 8 rings. The valid
 * values are 1, 2.
 * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver.
 * tx_fifo_len: This too is an array of 8. Each element defines the number of
 * Tx descriptors that can be associated with each corresponding FIFO.
 * intr_type: This defines the type of interrupt. The values can be 0(INTA),
 *     2(MSI_X). Default value is '2(MSI_X)'
 * lro_max_pkts: This parameter defines maximum number of packets can be
 *     aggregated as a single large packet
 * napi: This parameter used to enable/disable NAPI (polling Rx)
 *     Possible values '1' for enable and '0' for disable. Default is '1'
 * vlan_tag_strip: This can be used to enable or disable vlan stripping.
 *                 Possible values '1' for enable , '0' for disable.
 *                 Default is '2' - which means disable in promisc mode
 *                 and enable in non-promiscuous mode.
 * multiq: This parameter used to enable/disable MULTIQUEUE support.
 *      Possible values '1' for enable and '0' for disable. Default is '0'
 ************************************************************************/


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/mdio.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/stddef.h>
#include <linux/ioctl.h>
#include <linux/timex.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/slab.h>
#include <linux/prefetch.h>
#include <net/tcp.h>
#include <net/checksum.h>

#include <asm/div64.h>
#include <asm/irq.h>

/* local include */
#include "s2io.h"
#include "s2io-regs.h"

#define DRV_VERSION "2.0.26.28"

/* S2io Driver name & version. */
static const char s2io_driver_name[] = "Neterion";
static const char s2io_driver_version[] = DRV_VERSION;

static const int rxd_size[2] = {32, 48};
static const int rxd_count[2] = {127, 85};

static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
{
 int ret;

 ret = ((!(rxdp->Control_1 & RXD_OWN_XENA)) &&
        (GET_RXD_MARKER(rxdp->Control_2) != THE_RXD_MARK));

 return ret;
}

/*
 * Cards with following subsystem_id have a link state indication
 * problem, 600B, 600C, 600D, 640B, 640C and 640D.
 * macro below identifies these cards given the subsystem_id.
 */

#define CARDS_WITH_FAULTY_LINK_INDICATORS(dev_type, subid)  \
 (dev_type == XFRAME_I_DEVICE) ?     \
 ((((subid >= 0x600B) && (subid <= 0x600D)) ||   \
   ((subid >= 0x640B) && (subid <= 0x640D))) ? 1 : 0) : 0

#define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \
          ADAPTER_STATUS_RMAC_LOCAL_FAULT)))

static inline int is_s2io_card_up(const struct s2io_nic *sp)
{
 return test_bit(__S2IO_STATE_CARD_UP, &sp->state);
}

/* Ethtool related variables and Macros. */
static const char s2io_gstrings[][ETH_GSTRING_LEN] = {
 "Register test\t(offline)",
 "Eeprom test\t(offline)",
 "Link test\t(online)",
 "RLDRAM test\t(offline)",
 "BIST Test\t(offline)"
};

static const char ethtool_xena_stats_keys[][ETH_GSTRING_LEN] = {
 {"tmac_frms"},
 {"tmac_data_octets"},
 {"tmac_drop_frms"},
 {"tmac_mcst_frms"},
 {"tmac_bcst_frms"},
 {"tmac_pause_ctrl_frms"},
 {"tmac_ttl_octets"},
 {"tmac_ucst_frms"},
 {"tmac_nucst_frms"},
 {"tmac_any_err_frms"},
 {"tmac_ttl_less_fb_octets"},
 {"tmac_vld_ip_octets"},
 {"tmac_vld_ip"},
 {"tmac_drop_ip"},
 {"tmac_icmp"},
 {"tmac_rst_tcp"},
 {"tmac_tcp"},
 {"tmac_udp"},
 {"rmac_vld_frms"},
 {"rmac_data_octets"},
 {"rmac_fcs_err_frms"},
 {"rmac_drop_frms"},
 {"rmac_vld_mcst_frms"},
 {"rmac_vld_bcst_frms"},
 {"rmac_in_rng_len_err_frms"},
 {"rmac_out_rng_len_err_frms"},
 {"rmac_long_frms"},
 {"rmac_pause_ctrl_frms"},
 {"rmac_unsup_ctrl_frms"},
 {"rmac_ttl_octets"},
 {"rmac_accepted_ucst_frms"},
 {"rmac_accepted_nucst_frms"},
 {"rmac_discarded_frms"},
 {"rmac_drop_events"},
 {"rmac_ttl_less_fb_octets"},
 {"rmac_ttl_frms"},
 {"rmac_usized_frms"},
 {"rmac_osized_frms"},
 {"rmac_frag_frms"},
 {"rmac_jabber_frms"},
 {"rmac_ttl_64_frms"},
 {"rmac_ttl_65_127_frms"},
 {"rmac_ttl_128_255_frms"},
 {"rmac_ttl_256_511_frms"},
 {"rmac_ttl_512_1023_frms"},
 {"rmac_ttl_1024_1518_frms"},
 {"rmac_ip"},
 {"rmac_ip_octets"},
 {"rmac_hdr_err_ip"},
 {"rmac_drop_ip"},
 {"rmac_icmp"},
 {"rmac_tcp"},
 {"rmac_udp"},
 {"rmac_err_drp_udp"},
 {"rmac_xgmii_err_sym"},
 {"rmac_frms_q0"},
 {"rmac_frms_q1"},
 {"rmac_frms_q2"},
 {"rmac_frms_q3"},
 {"rmac_frms_q4"},
 {"rmac_frms_q5"},
 {"rmac_frms_q6"},
 {"rmac_frms_q7"},
 {"rmac_full_q0"},
 {"rmac_full_q1"},
 {"rmac_full_q2"},
 {"rmac_full_q3"},
 {"rmac_full_q4"},
 {"rmac_full_q5"},
 {"rmac_full_q6"},
 {"rmac_full_q7"},
 {"rmac_pause_cnt"},
 {"rmac_xgmii_data_err_cnt"},
 {"rmac_xgmii_ctrl_err_cnt"},
 {"rmac_accepted_ip"},
 {"rmac_err_tcp"},
 {"rd_req_cnt"},
 {"new_rd_req_cnt"},
 {"new_rd_req_rtry_cnt"},
 {"rd_rtry_cnt"},
 {"wr_rtry_rd_ack_cnt"},
 {"wr_req_cnt"},
 {"new_wr_req_cnt"},
 {"new_wr_req_rtry_cnt"},
 {"wr_rtry_cnt"},
 {"wr_disc_cnt"},
 {"rd_rtry_wr_ack_cnt"},
 {"txp_wr_cnt"},
 {"txd_rd_cnt"},
 {"txd_wr_cnt"},
 {"rxd_rd_cnt"},
 {"rxd_wr_cnt"},
 {"txf_rd_cnt"},
 {"rxf_wr_cnt"}
};

static const char ethtool_enhanced_stats_keys[][ETH_GSTRING_LEN] = {
 {"rmac_ttl_1519_4095_frms"},
 {"rmac_ttl_4096_8191_frms"},
 {"rmac_ttl_8192_max_frms"},
 {"rmac_ttl_gt_max_frms"},
 {"rmac_osized_alt_frms"},
 {"rmac_jabber_alt_frms"},
 {"rmac_gt_max_alt_frms"},
 {"rmac_vlan_frms"},
 {"rmac_len_discard"},
 {"rmac_fcs_discard"},
 {"rmac_pf_discard"},
 {"rmac_da_discard"},
 {"rmac_red_discard"},
 {"rmac_rts_discard"},
 {"rmac_ingm_full_discard"},
 {"link_fault_cnt"}
};

static const char ethtool_driver_stats_keys[][ETH_GSTRING_LEN] = {
 {"\n DRIVER STATISTICS"},
 {"single_bit_ecc_errs"},
 {"double_bit_ecc_errs"},
 {"parity_err_cnt"},
 {"serious_err_cnt"},
 {"soft_reset_cnt"},
 {"fifo_full_cnt"},
 {"ring_0_full_cnt"},
 {"ring_1_full_cnt"},
 {"ring_2_full_cnt"},
 {"ring_3_full_cnt"},
 {"ring_4_full_cnt"},
 {"ring_5_full_cnt"},
 {"ring_6_full_cnt"},
 {"ring_7_full_cnt"},
 {"alarm_transceiver_temp_high"},
 {"alarm_transceiver_temp_low"},
 {"alarm_laser_bias_current_high"},
 {"alarm_laser_bias_current_low"},
 {"alarm_laser_output_power_high"},
 {"alarm_laser_output_power_low"},
 {"warn_transceiver_temp_high"},
 {"warn_transceiver_temp_low"},
 {"warn_laser_bias_current_high"},
 {"warn_laser_bias_current_low"},
 {"warn_laser_output_power_high"},
 {"warn_laser_output_power_low"},
 {"lro_aggregated_pkts"},
 {"lro_flush_both_count"},
 {"lro_out_of_sequence_pkts"},
 {"lro_flush_due_to_max_pkts"},
 {"lro_avg_aggr_pkts"},
 {"mem_alloc_fail_cnt"},
 {"pci_map_fail_cnt"},
 {"watchdog_timer_cnt"},
 {"mem_allocated"},
 {"mem_freed"},
 {"link_up_cnt"},
 {"link_down_cnt"},
 {"link_up_time"},
 {"link_down_time"},
 {"tx_tcode_buf_abort_cnt"},
 {"tx_tcode_desc_abort_cnt"},
 {"tx_tcode_parity_err_cnt"},
 {"tx_tcode_link_loss_cnt"},
 {"tx_tcode_list_proc_err_cnt"},
 {"rx_tcode_parity_err_cnt"},
 {"rx_tcode_abort_cnt"},
 {"rx_tcode_parity_abort_cnt"},
 {"rx_tcode_rda_fail_cnt"},
 {"rx_tcode_unkn_prot_cnt"},
 {"rx_tcode_fcs_err_cnt"},
 {"rx_tcode_buf_size_err_cnt"},
 {"rx_tcode_rxd_corrupt_cnt"},
 {"rx_tcode_unkn_err_cnt"},
 {"tda_err_cnt"},
 {"pfc_err_cnt"},
 {"pcc_err_cnt"},
 {"tti_err_cnt"},
 {"tpa_err_cnt"},
 {"sm_err_cnt"},
 {"lso_err_cnt"},
 {"mac_tmac_err_cnt"},
 {"mac_rmac_err_cnt"},
 {"xgxs_txgxs_err_cnt"},
 {"xgxs_rxgxs_err_cnt"},
 {"rc_err_cnt"},
 {"prc_pcix_err_cnt"},
 {"rpa_err_cnt"},
 {"rda_err_cnt"},
 {"rti_err_cnt"},
 {"mc_err_cnt"}
};

#define S2IO_XENA_STAT_LEN ARRAY_SIZE(ethtool_xena_stats_keys)
#define S2IO_ENHANCED_STAT_LEN ARRAY_SIZE(ethtool_enhanced_stats_keys)
#define S2IO_DRIVER_STAT_LEN ARRAY_SIZE(ethtool_driver_stats_keys)

#define XFRAME_I_STAT_LEN (S2IO_XENA_STAT_LEN + S2IO_DRIVER_STAT_LEN)
#define XFRAME_II_STAT_LEN (XFRAME_I_STAT_LEN + S2IO_ENHANCED_STAT_LEN)

#define XFRAME_I_STAT_STRINGS_LEN (XFRAME_I_STAT_LEN * ETH_GSTRING_LEN)
#define XFRAME_II_STAT_STRINGS_LEN (XFRAME_II_STAT_LEN * ETH_GSTRING_LEN)

#define S2IO_TEST_LEN ARRAY_SIZE(s2io_gstrings)
#define S2IO_STRINGS_LEN (S2IO_TEST_LEN * ETH_GSTRING_LEN)

/* copy mac addr to def_mac_addr array */
static void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr)
{
 sp->def_mac_addr[offset].mac_addr[5] = (u8) (mac_addr);
 sp->def_mac_addr[offset].mac_addr[4] = (u8) (mac_addr >> 8);
 sp->def_mac_addr[offset].mac_addr[3] = (u8) (mac_addr >> 16);
 sp->def_mac_addr[offset].mac_addr[2] = (u8) (mac_addr >> 24);
 sp->def_mac_addr[offset].mac_addr[1] = (u8) (mac_addr >> 32);
 sp->def_mac_addr[offset].mac_addr[0] = (u8) (mac_addr >> 40);
}

/*
 * Constants to be programmed into the Xena's registers, to configure
 * the XAUI.
 */


#define END_SIGN 0x0
static const u64 herc_act_dtx_cfg[] = {
 /* Set address */
 0x8000051536750000ULL, 0x80000515367500E0ULL,
 /* Write data */
 0x8000051536750004ULL, 0x80000515367500E4ULL,
 /* Set address */
 0x80010515003F0000ULL, 0x80010515003F00E0ULL,
 /* Write data */
 0x80010515003F0004ULL, 0x80010515003F00E4ULL,
 /* Set address */
 0x801205150D440000ULL, 0x801205150D4400E0ULL,
 /* Write data */
 0x801205150D440004ULL, 0x801205150D4400E4ULL,
 /* Set address */
 0x80020515F2100000ULL, 0x80020515F21000E0ULL,
 /* Write data */
 0x80020515F2100004ULL, 0x80020515F21000E4ULL,
 /* Done */
 END_SIGN
};

static const u64 xena_dtx_cfg[] = {
 /* Set address */
 0x8000051500000000ULL, 0x80000515000000E0ULL,
 /* Write data */
 0x80000515D9350004ULL, 0x80000515D93500E4ULL,
 /* Set address */
 0x8001051500000000ULL, 0x80010515000000E0ULL,
 /* Write data */
 0x80010515001E0004ULL, 0x80010515001E00E4ULL,
 /* Set address */
 0x8002051500000000ULL, 0x80020515000000E0ULL,
 /* Write data */
 0x80020515F2100004ULL, 0x80020515F21000E4ULL,
 END_SIGN
};

/*
 * Constants for Fixing the MacAddress problem seen mostly on
 * Alpha machines.
 */

static const u64 fix_mac[] = {
 0x0060000000000000ULL, 0x0060600000000000ULL,
 0x0040600000000000ULL, 0x0000600000000000ULL,
 0x0020600000000000ULL, 0x0060600000000000ULL,
 0x0020600000000000ULL, 0x0060600000000000ULL,
 0x0020600000000000ULL, 0x0060600000000000ULL,
 0x0020600000000000ULL, 0x0060600000000000ULL,
 0x0020600000000000ULL, 0x0060600000000000ULL,
 0x0020600000000000ULL, 0x0060600000000000ULL,
 0x0020600000000000ULL, 0x0060600000000000ULL,
 0x0020600000000000ULL, 0x0060600000000000ULL,
 0x0020600000000000ULL, 0x0060600000000000ULL,
 0x0020600000000000ULL, 0x0060600000000000ULL,
 0x0020600000000000ULL, 0x0000600000000000ULL,
 0x0040600000000000ULL, 0x0060600000000000ULL,
 END_SIGN
};

MODULE_DESCRIPTION("Neterion 10GbE driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);


/* Module Loadable parameters. */
S2IO_PARM_INT(tx_fifo_num, FIFO_DEFAULT_NUM);
S2IO_PARM_INT(rx_ring_num, 1);
S2IO_PARM_INT(multiq, 0);
S2IO_PARM_INT(rx_ring_mode, 1);
S2IO_PARM_INT(use_continuous_tx_intrs, 1);
S2IO_PARM_INT(rmac_pause_time, 0x100);
S2IO_PARM_INT(mc_pause_threshold_q0q3, 187);
S2IO_PARM_INT(mc_pause_threshold_q4q7, 187);
S2IO_PARM_INT(shared_splits, 0);
S2IO_PARM_INT(tmac_util_period, 5);
S2IO_PARM_INT(rmac_util_period, 5);
S2IO_PARM_INT(l3l4hdr_size, 128);
/* 0 is no steering, 1 is Priority steering, 2 is Default steering */
S2IO_PARM_INT(tx_steering_type, TX_DEFAULT_STEERING);
/* Frequency of Rx desc syncs expressed as power of 2 */
S2IO_PARM_INT(rxsync_frequency, 3);
/* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
S2IO_PARM_INT(intr_type, 2);
/* Large receive offload feature */

/* Max pkts to be aggregated by LRO at one time. If not specified,
 * aggregation happens until we hit max IP pkt size(64K)
 */

S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
S2IO_PARM_INT(indicate_max_pkts, 0);

S2IO_PARM_INT(napi, 1);
S2IO_PARM_INT(vlan_tag_strip, NO_STRIP_IN_PROMISC);

static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
{DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
static unsigned int rx_ring_sz[MAX_RX_RINGS] =
{[0 ...(MAX_RX_RINGS - 1)] = SMALL_BLK_CNT};
static unsigned int rts_frm_len[MAX_RX_RINGS] =
{[0 ...(MAX_RX_RINGS - 1)] = 0 };

module_param_array(tx_fifo_len, uint, NULL, 0);
module_param_array(rx_ring_sz, uint, NULL, 0);
module_param_array(rts_frm_len, uint, NULL, 0);

/*
 * S2IO device table.
 * This table lists all the devices that this driver supports.
 */

static const struct pci_device_id s2io_tbl[] = {
 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN,
  PCI_ANY_ID, PCI_ANY_ID},
 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI,
  PCI_ANY_ID, PCI_ANY_ID},
 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_WIN,
  PCI_ANY_ID, PCI_ANY_ID},
 {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_HERC_UNI,
  PCI_ANY_ID, PCI_ANY_ID},
 {0,}
};

MODULE_DEVICE_TABLE(pci, s2io_tbl);

static const struct pci_error_handlers s2io_err_handler = {
 .error_detected = s2io_io_error_detected,
 .slot_reset = s2io_io_slot_reset,
 .resume = s2io_io_resume,
};

static struct pci_driver s2io_driver = {
 .name = "S2IO",
 .id_table = s2io_tbl,
 .probe = s2io_init_nic,
 .remove = s2io_rem_nic,
 .err_handler = &s2io_err_handler,
};

/* A simplifier macro used both by init and free shared_mem Fns(). */
#define TXD_MEM_PAGE_CNT(len, per_each) DIV_ROUND_UP(len, per_each)

/* netqueue manipulation helper functions */
static inline void s2io_stop_all_tx_queue(struct s2io_nic *sp)
{
 if (!sp->config.multiq) {
  int i;

  for (i = 0; i < sp->config.tx_fifo_num; i++)
   sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_STOP;
 }
 netif_tx_stop_all_queues(sp->dev);
}

static inline void s2io_stop_tx_queue(struct s2io_nic *sp, int fifo_no)
{
 if (!sp->config.multiq)
  sp->mac_control.fifos[fifo_no].queue_state =
   FIFO_QUEUE_STOP;

 netif_tx_stop_all_queues(sp->dev);
}

static inline void s2io_start_all_tx_queue(struct s2io_nic *sp)
{
 if (!sp->config.multiq) {
  int i;

  for (i = 0; i < sp->config.tx_fifo_num; i++)
   sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START;
 }
 netif_tx_start_all_queues(sp->dev);
}

static inline void s2io_wake_all_tx_queue(struct s2io_nic *sp)
{
 if (!sp->config.multiq) {
  int i;

  for (i = 0; i < sp->config.tx_fifo_num; i++)
   sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START;
 }
 netif_tx_wake_all_queues(sp->dev);
}

static inline void s2io_wake_tx_queue(
 struct fifo_info *fifo, int cnt, u8 multiq)
{

 if (multiq) {
  if (cnt && __netif_subqueue_stopped(fifo->dev, fifo->fifo_no))
   netif_wake_subqueue(fifo->dev, fifo->fifo_no);
 } else if (cnt && (fifo->queue_state == FIFO_QUEUE_STOP)) {
  if (netif_queue_stopped(fifo->dev)) {
   fifo->queue_state = FIFO_QUEUE_START;
   netif_wake_queue(fifo->dev);
  }
 }
}

/**
 * init_shared_mem - Allocation and Initialization of Memory
 * @nic: Device private variable.
 * Description: The function allocates all the memory areas shared
 * between the NIC and the driver. This includes Tx descriptors,
 * Rx descriptors and the statistics block.
 */


static int init_shared_mem(struct s2io_nic *nic)
{
 u32 size;
 void *tmp_v_addr, *tmp_v_addr_next;
 dma_addr_t tmp_p_addr, tmp_p_addr_next;
 struct RxD_block *pre_rxd_blk = NULL;
 int i, j, blk_cnt;
 int lst_size, lst_per_page;
 struct net_device *dev = nic->dev;
 unsigned long tmp;
 struct buffAdd *ba;
 struct config_param *config = &nic->config;
 struct mac_info *mac_control = &nic->mac_control;
 unsigned long long mem_allocated = 0;

 /* Allocation and initialization of TXDLs in FIFOs */
 size = 0;
 for (i = 0; i < config->tx_fifo_num; i++) {
  struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];

  size += tx_cfg->fifo_len;
 }
 if (size > MAX_AVAILABLE_TXDS) {
  DBG_PRINT(ERR_DBG,
     "Too many TxDs requested: %d, max supported: %d\n",
     size, MAX_AVAILABLE_TXDS);
  return -EINVAL;
 }

 size = 0;
 for (i = 0; i < config->tx_fifo_num; i++) {
  struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];

  size = tx_cfg->fifo_len;
  /*
 * Legal values are from 2 to 8192
 */

  if (size < 2) {
   DBG_PRINT(ERR_DBG, "Fifo %d: Invalid length (%d) - "
      "Valid lengths are 2 through 8192\n",
      i, size);
   return -EINVAL;
  }
 }

 lst_size = (sizeof(struct TxD) * config->max_txds);
 lst_per_page = PAGE_SIZE / lst_size;

 for (i = 0; i < config->tx_fifo_num; i++) {
  struct fifo_info *fifo = &mac_control->fifos[i];
  struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];
  int fifo_len = tx_cfg->fifo_len;
  int list_holder_size = fifo_len * sizeof(struct list_info_hold);

  fifo->list_info = kzalloc(list_holder_size, GFP_KERNEL);
  if (!fifo->list_info) {
   DBG_PRINT(INFO_DBG, "Malloc failed for list_info\n");
   return -ENOMEM;
  }
  mem_allocated += list_holder_size;
 }
 for (i = 0; i < config->tx_fifo_num; i++) {
  int page_num = TXD_MEM_PAGE_CNT(config->tx_cfg[i].fifo_len,
      lst_per_page);
  struct fifo_info *fifo = &mac_control->fifos[i];
  struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];

  fifo->tx_curr_put_info.offset = 0;
  fifo->tx_curr_put_info.fifo_len = tx_cfg->fifo_len - 1;
  fifo->tx_curr_get_info.offset = 0;
  fifo->tx_curr_get_info.fifo_len = tx_cfg->fifo_len - 1;
  fifo->fifo_no = i;
  fifo->nic = nic;
  fifo->max_txds = MAX_SKB_FRAGS + 2;
  fifo->dev = dev;

  for (j = 0; j < page_num; j++) {
   int k = 0;
   dma_addr_t tmp_p;
   void *tmp_v;
   tmp_v = dma_alloc_coherent(&nic->pdev->dev, PAGE_SIZE,
         &tmp_p, GFP_KERNEL);
   if (!tmp_v) {
    DBG_PRINT(INFO_DBG,
       "dma_alloc_coherent failed for TxDL\n");
    return -ENOMEM;
   }
   /* If we got a zero DMA address(can happen on
 * certain platforms like PPC), reallocate.
 * Store virtual address of page we don't want,
 * to be freed later.
 */

   if (!tmp_p) {
    mac_control->zerodma_virt_addr = tmp_v;
    DBG_PRINT(INIT_DBG,
       "%s: Zero DMA address for TxDL. "
       "Virtual address %p\n",
       dev->name, tmp_v);
    tmp_v = dma_alloc_coherent(&nic->pdev->dev,
          PAGE_SIZE, &tmp_p,
          GFP_KERNEL);
    if (!tmp_v) {
     DBG_PRINT(INFO_DBG,
        "dma_alloc_coherent failed for TxDL\n");
     return -ENOMEM;
    }
    mem_allocated += PAGE_SIZE;
   }
   while (k < lst_per_page) {
    int l = (j * lst_per_page) + k;
    if (l == tx_cfg->fifo_len)
     break;
    fifo->list_info[l].list_virt_addr =
     tmp_v + (k * lst_size);
    fifo->list_info[l].list_phy_addr =
     tmp_p + (k * lst_size);
    k++;
   }
  }
 }

 for (i = 0; i < config->tx_fifo_num; i++) {
  struct fifo_info *fifo = &mac_control->fifos[i];
  struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];

  size = tx_cfg->fifo_len;
  fifo->ufo_in_band_v = kcalloc(size, sizeof(u64), GFP_KERNEL);
  if (!fifo->ufo_in_band_v)
   return -ENOMEM;
  mem_allocated += (size * sizeof(u64));
 }

 /* Allocation and initialization of RXDs in Rings */
 size = 0;
 for (i = 0; i < config->rx_ring_num; i++) {
  struct rx_ring_config *rx_cfg = &config->rx_cfg[i];
  struct ring_info *ring = &mac_control->rings[i];

  if (rx_cfg->num_rxd % (rxd_count[nic->rxd_mode] + 1)) {
   DBG_PRINT(ERR_DBG, "%s: Ring%d RxD count is not a "
      "multiple of RxDs per Block\n",
      dev->name, i);
   return FAILURE;
  }
  size += rx_cfg->num_rxd;
  ring->block_count = rx_cfg->num_rxd /
   (rxd_count[nic->rxd_mode] + 1);
  ring->pkt_cnt = rx_cfg->num_rxd - ring->block_count;
 }
 if (nic->rxd_mode == RXD_MODE_1)
  size = (size * (sizeof(struct RxD1)));
 else
  size = (size * (sizeof(struct RxD3)));

 for (i = 0; i < config->rx_ring_num; i++) {
  struct rx_ring_config *rx_cfg = &config->rx_cfg[i];
  struct ring_info *ring = &mac_control->rings[i];

  ring->rx_curr_get_info.block_index = 0;
  ring->rx_curr_get_info.offset = 0;
  ring->rx_curr_get_info.ring_len = rx_cfg->num_rxd - 1;
  ring->rx_curr_put_info.block_index = 0;
  ring->rx_curr_put_info.offset = 0;
  ring->rx_curr_put_info.ring_len = rx_cfg->num_rxd - 1;
  ring->nic = nic;
  ring->ring_no = i;

  blk_cnt = rx_cfg->num_rxd / (rxd_count[nic->rxd_mode] + 1);
  /*  Allocating all the Rx blocks */
  for (j = 0; j < blk_cnt; j++) {
   struct rx_block_info *rx_blocks;
   int l;

   rx_blocks = &ring->rx_blocks[j];
   size = SIZE_OF_BLOCK; /* size is always page size */
   tmp_v_addr = dma_alloc_coherent(&nic->pdev->dev, size,
       &tmp_p_addr, GFP_KERNEL);
   if (tmp_v_addr == NULL) {
    /*
 * In case of failure, free_shared_mem()
 * is called, which should free any
 * memory that was alloced till the
 * failure happened.
 */

    rx_blocks->block_virt_addr = tmp_v_addr;
    return -ENOMEM;
   }
   mem_allocated += size;

   size = sizeof(struct rxd_info) *
    rxd_count[nic->rxd_mode];
   rx_blocks->block_virt_addr = tmp_v_addr;
   rx_blocks->block_dma_addr = tmp_p_addr;
   rx_blocks->rxds = kmalloc(size,  GFP_KERNEL);
   if (!rx_blocks->rxds)
    return -ENOMEM;
   mem_allocated += size;
   for (l = 0; l < rxd_count[nic->rxd_mode]; l++) {
    rx_blocks->rxds[l].virt_addr =
     rx_blocks->block_virt_addr +
     (rxd_size[nic->rxd_mode] * l);
    rx_blocks->rxds[l].dma_addr =
     rx_blocks->block_dma_addr +
     (rxd_size[nic->rxd_mode] * l);
   }
  }
  /* Interlinking all Rx Blocks */
  for (j = 0; j < blk_cnt; j++) {
   int next = (j + 1) % blk_cnt;
   tmp_v_addr = ring->rx_blocks[j].block_virt_addr;
   tmp_v_addr_next = ring->rx_blocks[next].block_virt_addr;
   tmp_p_addr = ring->rx_blocks[j].block_dma_addr;
   tmp_p_addr_next = ring->rx_blocks[next].block_dma_addr;

   pre_rxd_blk = tmp_v_addr;
   pre_rxd_blk->reserved_2_pNext_RxD_block =
    (unsigned long)tmp_v_addr_next;
   pre_rxd_blk->pNext_RxD_Blk_physical =
    (u64)tmp_p_addr_next;
  }
 }
 if (nic->rxd_mode == RXD_MODE_3B) {
  /*
 * Allocation of Storages for buffer addresses in 2BUFF mode
 * and the buffers as well.
 */

  for (i = 0; i < config->rx_ring_num; i++) {
   struct rx_ring_config *rx_cfg = &config->rx_cfg[i];
   struct ring_info *ring = &mac_control->rings[i];

   blk_cnt = rx_cfg->num_rxd /
    (rxd_count[nic->rxd_mode] + 1);
   size = sizeof(struct buffAdd *) * blk_cnt;
   ring->ba = kmalloc(size, GFP_KERNEL);
   if (!ring->ba)
    return -ENOMEM;
   mem_allocated += size;
   for (j = 0; j < blk_cnt; j++) {
    int k = 0;

    size = sizeof(struct buffAdd) *
     (rxd_count[nic->rxd_mode] + 1);
    ring->ba[j] = kmalloc(size, GFP_KERNEL);
    if (!ring->ba[j])
     return -ENOMEM;
    mem_allocated += size;
    while (k != rxd_count[nic->rxd_mode]) {
     ba = &ring->ba[j][k];
     size = BUF0_LEN + ALIGN_SIZE;
     ba->ba_0_org = kmalloc(size, GFP_KERNEL);
     if (!ba->ba_0_org)
      return -ENOMEM;
     mem_allocated += size;
     tmp = (unsigned long)ba->ba_0_org;
     tmp += ALIGN_SIZE;
     tmp &= ~((unsigned long)ALIGN_SIZE);
     ba->ba_0 = (void *)tmp;

     size = BUF1_LEN + ALIGN_SIZE;
     ba->ba_1_org = kmalloc(size, GFP_KERNEL);
     if (!ba->ba_1_org)
      return -ENOMEM;
     mem_allocated += size;
     tmp = (unsigned long)ba->ba_1_org;
     tmp += ALIGN_SIZE;
     tmp &= ~((unsigned long)ALIGN_SIZE);
     ba->ba_1 = (void *)tmp;
     k++;
    }
   }
  }
 }

 /* Allocation and initialization of Statistics block */
 size = sizeof(struct stat_block);
 mac_control->stats_mem =
  dma_alloc_coherent(&nic->pdev->dev, size,
       &mac_control->stats_mem_phy, GFP_KERNEL);

 if (!mac_control->stats_mem) {
  /*
 * In case of failure, free_shared_mem() is called, which
 * should free any memory that was alloced till the
 * failure happened.
 */

  return -ENOMEM;
 }
 mem_allocated += size;
 mac_control->stats_mem_sz = size;

 tmp_v_addr = mac_control->stats_mem;
 mac_control->stats_info = tmp_v_addr;
 memset(tmp_v_addr, 0, size);
 DBG_PRINT(INIT_DBG, "%s: Ring Mem PHY: 0x%llx\n",
  dev_name(&nic->pdev->dev), (unsigned long long)tmp_p_addr);
 mac_control->stats_info->sw_stat.mem_allocated += mem_allocated;
 return SUCCESS;
}

/**
 * free_shared_mem - Free the allocated Memory
 * @nic:  Device private variable.
 * Description: This function is to free all memory locations allocated by
 * the init_shared_mem() function and return it to the kernel.
 */


static void free_shared_mem(struct s2io_nic *nic)
{
 int i, j, blk_cnt, size;
 void *tmp_v_addr;
 dma_addr_t tmp_p_addr;
 int lst_size, lst_per_page;
 struct net_device *dev;
 int page_num = 0;
 struct config_param *config;
 struct mac_info *mac_control;
 struct stat_block *stats;
 struct swStat *swstats;

 if (!nic)
  return;

 dev = nic->dev;

 config = &nic->config;
 mac_control = &nic->mac_control;
 stats = mac_control->stats_info;
 swstats = &stats->sw_stat;

 lst_size = sizeof(struct TxD) * config->max_txds;
 lst_per_page = PAGE_SIZE / lst_size;

 for (i = 0; i < config->tx_fifo_num; i++) {
  struct fifo_info *fifo = &mac_control->fifos[i];
  struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];

  page_num = TXD_MEM_PAGE_CNT(tx_cfg->fifo_len, lst_per_page);
  for (j = 0; j < page_num; j++) {
   int mem_blks = (j * lst_per_page);
   struct list_info_hold *fli;

   if (!fifo->list_info)
    return;

   fli = &fifo->list_info[mem_blks];
   if (!fli->list_virt_addr)
    break;
   dma_free_coherent(&nic->pdev->dev, PAGE_SIZE,
       fli->list_virt_addr,
       fli->list_phy_addr);
   swstats->mem_freed += PAGE_SIZE;
  }
  /* If we got a zero DMA address during allocation,
 * free the page now
 */

  if (mac_control->zerodma_virt_addr) {
   dma_free_coherent(&nic->pdev->dev, PAGE_SIZE,
       mac_control->zerodma_virt_addr,
       (dma_addr_t)0);
   DBG_PRINT(INIT_DBG,
      "%s: Freeing TxDL with zero DMA address. "
      "Virtual address %p\n",
      dev->name, mac_control->zerodma_virt_addr);
   swstats->mem_freed += PAGE_SIZE;
  }
  kfree(fifo->list_info);
  swstats->mem_freed += tx_cfg->fifo_len *
   sizeof(struct list_info_hold);
 }

 size = SIZE_OF_BLOCK;
 for (i = 0; i < config->rx_ring_num; i++) {
  struct ring_info *ring = &mac_control->rings[i];

  blk_cnt = ring->block_count;
  for (j = 0; j < blk_cnt; j++) {
   tmp_v_addr = ring->rx_blocks[j].block_virt_addr;
   tmp_p_addr = ring->rx_blocks[j].block_dma_addr;
   if (tmp_v_addr == NULL)
    break;
   dma_free_coherent(&nic->pdev->dev, size, tmp_v_addr,
       tmp_p_addr);
   swstats->mem_freed += size;
   kfree(ring->rx_blocks[j].rxds);
   swstats->mem_freed += sizeof(struct rxd_info) *
    rxd_count[nic->rxd_mode];
  }
 }

 if (nic->rxd_mode == RXD_MODE_3B) {
  /* Freeing buffer storage addresses in 2BUFF mode. */
  for (i = 0; i < config->rx_ring_num; i++) {
   struct rx_ring_config *rx_cfg = &config->rx_cfg[i];
   struct ring_info *ring = &mac_control->rings[i];

   blk_cnt = rx_cfg->num_rxd /
    (rxd_count[nic->rxd_mode] + 1);
   for (j = 0; j < blk_cnt; j++) {
    int k = 0;
    if (!ring->ba[j])
     continue;
    while (k != rxd_count[nic->rxd_mode]) {
     struct buffAdd *ba = &ring->ba[j][k];
     kfree(ba->ba_0_org);
     swstats->mem_freed +=
      BUF0_LEN + ALIGN_SIZE;
     kfree(ba->ba_1_org);
     swstats->mem_freed +=
      BUF1_LEN + ALIGN_SIZE;
     k++;
    }
    kfree(ring->ba[j]);
    swstats->mem_freed += sizeof(struct buffAdd) *
     (rxd_count[nic->rxd_mode] + 1);
   }
   kfree(ring->ba);
   swstats->mem_freed += sizeof(struct buffAdd *) *
    blk_cnt;
  }
 }

 for (i = 0; i < nic->config.tx_fifo_num; i++) {
  struct fifo_info *fifo = &mac_control->fifos[i];
  struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];

  if (fifo->ufo_in_band_v) {
   swstats->mem_freed += tx_cfg->fifo_len *
    sizeof(u64);
   kfree(fifo->ufo_in_band_v);
  }
 }

 if (mac_control->stats_mem) {
  swstats->mem_freed += mac_control->stats_mem_sz;
  dma_free_coherent(&nic->pdev->dev, mac_control->stats_mem_sz,
      mac_control->stats_mem,
      mac_control->stats_mem_phy);
 }
}

/*
 * s2io_verify_pci_mode -
 */


static int s2io_verify_pci_mode(struct s2io_nic *nic)
{
 struct XENA_dev_config __iomem *bar0 = nic->bar0;
 register u64 val64 = 0;
 int     mode;

 val64 = readq(&bar0->pci_mode);
 mode = (u8)GET_PCI_MODE(val64);

 if (val64 & PCI_MODE_UNKNOWN_MODE)
  return -1;      /* Unknown PCI mode */
 return mode;
}

#define NEC_VENID   0x1033
#define NEC_DEVID   0x0125
static int s2io_on_nec_bridge(struct pci_dev *s2io_pdev)
{
 struct pci_dev *tdev = NULL;
 for_each_pci_dev(tdev) {
  if (tdev->vendor == NEC_VENID && tdev->device == NEC_DEVID) {
   if (tdev->bus == s2io_pdev->bus->parent) {
    pci_dev_put(tdev);
    return 1;
   }
  }
 }
 return 0;
}

static int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266};
/*
 * s2io_print_pci_mode -
 */

static int s2io_print_pci_mode(struct s2io_nic *nic)
{
 struct XENA_dev_config __iomem *bar0 = nic->bar0;
 register u64 val64 = 0;
 int mode;
 struct config_param *config = &nic->config;
 const char *pcimode;

 val64 = readq(&bar0->pci_mode);
 mode = (u8)GET_PCI_MODE(val64);

 if (val64 & PCI_MODE_UNKNOWN_MODE)
  return -1; /* Unknown PCI mode */

 config->bus_speed = bus_speed[mode];

 if (s2io_on_nec_bridge(nic->pdev)) {
  DBG_PRINT(ERR_DBG, "%s: Device is on PCI-E bus\n",
     nic->dev->name);
  return mode;
 }

 switch (mode) {
 case PCI_MODE_PCI_33:
  pcimode = "33MHz PCI bus";
  break;
 case PCI_MODE_PCI_66:
  pcimode = "66MHz PCI bus";
  break;
 case PCI_MODE_PCIX_M1_66:
  pcimode = "66MHz PCIX(M1) bus";
  break;
 case PCI_MODE_PCIX_M1_100:
  pcimode = "100MHz PCIX(M1) bus";
  break;
 case PCI_MODE_PCIX_M1_133:
  pcimode = "133MHz PCIX(M1) bus";
  break;
 case PCI_MODE_PCIX_M2_66:
  pcimode = "133MHz PCIX(M2) bus";
  break;
 case PCI_MODE_PCIX_M2_100:
  pcimode = "200MHz PCIX(M2) bus";
  break;
 case PCI_MODE_PCIX_M2_133:
  pcimode = "266MHz PCIX(M2) bus";
  break;
 default:
  pcimode = "unsupported bus!";
  mode = -1;
 }

 DBG_PRINT(ERR_DBG, "%s: Device is on %d bit %s\n",
    nic->dev->name, val64 & PCI_MODE_32_BITS ? 32 : 64, pcimode);

 return mode;
}

/**
 *  init_tti - Initialization transmit traffic interrupt scheme
 *  @nic: device private variable
 *  @link: link status (UP/DOWN) used to enable/disable continuous
 *  transmit interrupts
 *  @may_sleep: parameter indicates if sleeping when waiting for
 *  command complete
 *  Description: The function configures transmit traffic interrupts
 *  Return Value:  SUCCESS on success and
 *  '-1' on failure
 */


static int init_tti(struct s2io_nic *nic, int link, bool may_sleep)
{
 struct XENA_dev_config __iomem *bar0 = nic->bar0;
 register u64 val64 = 0;
 int i;
 struct config_param *config = &nic->config;

 for (i = 0; i < config->tx_fifo_num; i++) {
  /*
 * TTI Initialization. Default Tx timer gets us about
 * 250 interrupts per sec. Continuous interrupts are enabled
 * by default.
 */

  if (nic->device_type == XFRAME_II_DEVICE) {
   int count = (nic->config.bus_speed * 125)/2;
   val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
  } else
   val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);

  val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
   TTI_DATA1_MEM_TX_URNG_B(0x10) |
   TTI_DATA1_MEM_TX_URNG_C(0x30) |
   TTI_DATA1_MEM_TX_TIMER_AC_EN;
  if (i == 0)
   if (use_continuous_tx_intrs && (link == LINK_UP))
    val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
  writeq(val64, &bar0->tti_data1_mem);

  if (nic->config.intr_type == MSI_X) {
   val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
    TTI_DATA2_MEM_TX_UFC_B(0x100) |
    TTI_DATA2_MEM_TX_UFC_C(0x200) |
    TTI_DATA2_MEM_TX_UFC_D(0x300);
  } else {
   if ((nic->config.tx_steering_type ==
        TX_DEFAULT_STEERING) &&
       (config->tx_fifo_num > 1) &&
       (i >= nic->udp_fifo_idx) &&
       (i < (nic->udp_fifo_idx +
      nic->total_udp_fifos)))
    val64 = TTI_DATA2_MEM_TX_UFC_A(0x50) |
     TTI_DATA2_MEM_TX_UFC_B(0x80) |
     TTI_DATA2_MEM_TX_UFC_C(0x100) |
     TTI_DATA2_MEM_TX_UFC_D(0x120);
   else
    val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
     TTI_DATA2_MEM_TX_UFC_B(0x20) |
     TTI_DATA2_MEM_TX_UFC_C(0x40) |
     TTI_DATA2_MEM_TX_UFC_D(0x80);
  }

  writeq(val64, &bar0->tti_data2_mem);

  val64 = TTI_CMD_MEM_WE |
   TTI_CMD_MEM_STROBE_NEW_CMD |
   TTI_CMD_MEM_OFFSET(i);
  writeq(val64, &bar0->tti_command_mem);

  if (wait_for_cmd_complete(&bar0->tti_command_mem,
       TTI_CMD_MEM_STROBE_NEW_CMD,
       S2IO_BIT_RESET, may_sleep) != SUCCESS)
   return FAILURE;
 }

 return SUCCESS;
}

/**
 *  init_nic - Initialization of hardware
 *  @nic: device private variable
 *  Description: The function sequentially configures every block
 *  of the H/W from their reset values.
 *  Return Value:  SUCCESS on success and
 *  '-1' on failure (endian settings incorrect).
 */


static int init_nic(struct s2io_nic *nic)
{
 struct XENA_dev_config __iomem *bar0 = nic->bar0;
 struct net_device *dev = nic->dev;
 register u64 val64 = 0;
 void __iomem *add;
 u32 time;
 int i, j;
 int dtx_cnt = 0;
 unsigned long long mem_share;
 int mem_size;
 struct config_param *config = &nic->config;
 struct mac_info *mac_control = &nic->mac_control;

 /* to set the swapper controle on the card */
 if (s2io_set_swapper(nic)) {
  DBG_PRINT(ERR_DBG, "ERROR: Setting Swapper failed\n");
  return -EIO;
 }

 /*
 * Herc requires EOI to be removed from reset before XGXS, so..
 */

 if (nic->device_type & XFRAME_II_DEVICE) {
  val64 = 0xA500000000ULL;
  writeq(val64, &bar0->sw_reset);
  msleep(500);
  val64 = readq(&bar0->sw_reset);
 }

 /* Remove XGXS from reset state */
 val64 = 0;
 writeq(val64, &bar0->sw_reset);
 msleep(500);
 val64 = readq(&bar0->sw_reset);

 /* Ensure that it's safe to access registers by checking
 * RIC_RUNNING bit is reset. Check is valid only for XframeII.
 */

 if (nic->device_type == XFRAME_II_DEVICE) {
  for (i = 0; i < 50; i++) {
   val64 = readq(&bar0->adapter_status);
   if (!(val64 & ADAPTER_STATUS_RIC_RUNNING))
    break;
   msleep(10);
  }
  if (i == 50)
   return -ENODEV;
 }

 /*  Enable Receiving broadcasts */
 add = &bar0->mac_cfg;
 val64 = readq(&bar0->mac_cfg);
 val64 |= MAC_RMAC_BCAST_ENABLE;
 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
 writel((u32)val64, add);
 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
 writel((u32) (val64 >> 32), (add + 4));

 /* Read registers in all blocks */
 val64 = readq(&bar0->mac_int_mask);
 val64 = readq(&bar0->mc_int_mask);
 val64 = readq(&bar0->xgxs_int_mask);

 /*  Set MTU */
 val64 = dev->mtu;
 writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);

 if (nic->device_type & XFRAME_II_DEVICE) {
  while (herc_act_dtx_cfg[dtx_cnt] != END_SIGN) {
   SPECIAL_REG_WRITE(herc_act_dtx_cfg[dtx_cnt],
       &bar0->dtx_control, UF);
   if (dtx_cnt & 0x1)
    msleep(1); /* Necessary!! */
   dtx_cnt++;
  }
 } else {
  while (xena_dtx_cfg[dtx_cnt] != END_SIGN) {
   SPECIAL_REG_WRITE(xena_dtx_cfg[dtx_cnt],
       &bar0->dtx_control, UF);
   val64 = readq(&bar0->dtx_control);
   dtx_cnt++;
  }
 }

 /*  Tx DMA Initialization */
 val64 = 0;
 writeq(val64, &bar0->tx_fifo_partition_0);
 writeq(val64, &bar0->tx_fifo_partition_1);
 writeq(val64, &bar0->tx_fifo_partition_2);
 writeq(val64, &bar0->tx_fifo_partition_3);

 for (i = 0, j = 0; i < config->tx_fifo_num; i++) {
  struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];

  val64 |= vBIT(tx_cfg->fifo_len - 1, ((j * 32) + 19), 13) |
   vBIT(tx_cfg->fifo_priority, ((j * 32) + 5), 3);

  if (i == (config->tx_fifo_num - 1)) {
   if (i % 2 == 0)
    i++;
  }

  switch (i) {
  case 1:
   writeq(val64, &bar0->tx_fifo_partition_0);
   val64 = 0;
   j = 0;
   break;
  case 3:
   writeq(val64, &bar0->tx_fifo_partition_1);
   val64 = 0;
   j = 0;
   break;
  case 5:
   writeq(val64, &bar0->tx_fifo_partition_2);
   val64 = 0;
   j = 0;
   break;
  case 7:
   writeq(val64, &bar0->tx_fifo_partition_3);
   val64 = 0;
   j = 0;
   break;
  default:
   j++;
   break;
  }
 }

 /*
 * Disable 4 PCCs for Xena1, 2 and 3 as per H/W bug
 * SXE-008 TRANSMIT DMA ARBITRATION ISSUE.
 */

 if ((nic->device_type == XFRAME_I_DEVICE) && (nic->pdev->revision < 4))
  writeq(PCC_ENABLE_FOUR, &bar0->pcc_enable);

 val64 = readq(&bar0->tx_fifo_partition_0);
 DBG_PRINT(INIT_DBG, "Fifo partition at: 0x%p is: 0x%llx\n",
    &bar0->tx_fifo_partition_0, (unsigned long long)val64);

 /*
 * Initialization of Tx_PA_CONFIG register to ignore packet
 * integrity checking.
 */

 val64 = readq(&bar0->tx_pa_cfg);
 val64 |= TX_PA_CFG_IGNORE_FRM_ERR |
  TX_PA_CFG_IGNORE_SNAP_OUI |
  TX_PA_CFG_IGNORE_LLC_CTRL |
  TX_PA_CFG_IGNORE_L2_ERR;
 writeq(val64, &bar0->tx_pa_cfg);

 /* Rx DMA initialization. */
 val64 = 0;
 for (i = 0; i < config->rx_ring_num; i++) {
  struct rx_ring_config *rx_cfg = &config->rx_cfg[i];

  val64 |= vBIT(rx_cfg->ring_priority, (5 + (i * 8)), 3);
 }
 writeq(val64, &bar0->rx_queue_priority);

 /*
 * Allocating equal share of memory to all the
 * configured Rings.
 */

 val64 = 0;
 if (nic->device_type & XFRAME_II_DEVICE)
  mem_size = 32;
 else
  mem_size = 64;

 for (i = 0; i < config->rx_ring_num; i++) {
  switch (i) {
  case 0:
   mem_share = (mem_size / config->rx_ring_num +
         mem_size % config->rx_ring_num);
   val64 |= RX_QUEUE_CFG_Q0_SZ(mem_share);
   continue;
  case 1:
   mem_share = (mem_size / config->rx_ring_num);
   val64 |= RX_QUEUE_CFG_Q1_SZ(mem_share);
   continue;
  case 2:
   mem_share = (mem_size / config->rx_ring_num);
   val64 |= RX_QUEUE_CFG_Q2_SZ(mem_share);
   continue;
  case 3:
   mem_share = (mem_size / config->rx_ring_num);
   val64 |= RX_QUEUE_CFG_Q3_SZ(mem_share);
   continue;
  case 4:
   mem_share = (mem_size / config->rx_ring_num);
   val64 |= RX_QUEUE_CFG_Q4_SZ(mem_share);
   continue;
  case 5:
   mem_share = (mem_size / config->rx_ring_num);
   val64 |= RX_QUEUE_CFG_Q5_SZ(mem_share);
   continue;
  case 6:
   mem_share = (mem_size / config->rx_ring_num);
   val64 |= RX_QUEUE_CFG_Q6_SZ(mem_share);
   continue;
  case 7:
   mem_share = (mem_size / config->rx_ring_num);
   val64 |= RX_QUEUE_CFG_Q7_SZ(mem_share);
   continue;
  }
 }
 writeq(val64, &bar0->rx_queue_cfg);

 /*
 * Filling Tx round robin registers
 * as per the number of FIFOs for equal scheduling priority
 */

 switch (config->tx_fifo_num) {
 case 1:
  val64 = 0x0;
  writeq(val64, &bar0->tx_w_round_robin_0);
  writeq(val64, &bar0->tx_w_round_robin_1);
  writeq(val64, &bar0->tx_w_round_robin_2);
  writeq(val64, &bar0->tx_w_round_robin_3);
  writeq(val64, &bar0->tx_w_round_robin_4);
  break;
 case 2:
  val64 = 0x0001000100010001ULL;
  writeq(val64, &bar0->tx_w_round_robin_0);
  writeq(val64, &bar0->tx_w_round_robin_1);
  writeq(val64, &bar0->tx_w_round_robin_2);
  writeq(val64, &bar0->tx_w_round_robin_3);
  val64 = 0x0001000100000000ULL;
  writeq(val64, &bar0->tx_w_round_robin_4);
  break;
 case 3:
  val64 = 0x0001020001020001ULL;
  writeq(val64, &bar0->tx_w_round_robin_0);
  val64 = 0x0200010200010200ULL;
  writeq(val64, &bar0->tx_w_round_robin_1);
  val64 = 0x0102000102000102ULL;
  writeq(val64, &bar0->tx_w_round_robin_2);
  val64 = 0x0001020001020001ULL;
  writeq(val64, &bar0->tx_w_round_robin_3);
  val64 = 0x0200010200000000ULL;
  writeq(val64, &bar0->tx_w_round_robin_4);
  break;
 case 4:
  val64 = 0x0001020300010203ULL;
  writeq(val64, &bar0->tx_w_round_robin_0);
  writeq(val64, &bar0->tx_w_round_robin_1);
  writeq(val64, &bar0->tx_w_round_robin_2);
  writeq(val64, &bar0->tx_w_round_robin_3);
  val64 = 0x0001020300000000ULL;
  writeq(val64, &bar0->tx_w_round_robin_4);
  break;
 case 5:
  val64 = 0x0001020304000102ULL;
  writeq(val64, &bar0->tx_w_round_robin_0);
  val64 = 0x0304000102030400ULL;
  writeq(val64, &bar0->tx_w_round_robin_1);
  val64 = 0x0102030400010203ULL;
  writeq(val64, &bar0->tx_w_round_robin_2);
  val64 = 0x0400010203040001ULL;
  writeq(val64, &bar0->tx_w_round_robin_3);
  val64 = 0x0203040000000000ULL;
  writeq(val64, &bar0->tx_w_round_robin_4);
  break;
 case 6:
  val64 = 0x0001020304050001ULL;
  writeq(val64, &bar0->tx_w_round_robin_0);
  val64 = 0x0203040500010203ULL;
  writeq(val64, &bar0->tx_w_round_robin_1);
  val64 = 0x0405000102030405ULL;
  writeq(val64, &bar0->tx_w_round_robin_2);
  val64 = 0x0001020304050001ULL;
  writeq(val64, &bar0->tx_w_round_robin_3);
  val64 = 0x0203040500000000ULL;
  writeq(val64, &bar0->tx_w_round_robin_4);
  break;
 case 7:
  val64 = 0x0001020304050600ULL;
  writeq(val64, &bar0->tx_w_round_robin_0);
  val64 = 0x0102030405060001ULL;
  writeq(val64, &bar0->tx_w_round_robin_1);
  val64 = 0x0203040506000102ULL;
  writeq(val64, &bar0->tx_w_round_robin_2);
  val64 = 0x0304050600010203ULL;
  writeq(val64, &bar0->tx_w_round_robin_3);
  val64 = 0x0405060000000000ULL;
  writeq(val64, &bar0->tx_w_round_robin_4);
  break;
 case 8:
  val64 = 0x0001020304050607ULL;
  writeq(val64, &bar0->tx_w_round_robin_0);
  writeq(val64, &bar0->tx_w_round_robin_1);
  writeq(val64, &bar0->tx_w_round_robin_2);
  writeq(val64, &bar0->tx_w_round_robin_3);
  val64 = 0x0001020300000000ULL;
  writeq(val64, &bar0->tx_w_round_robin_4);
  break;
 }

 /* Enable all configured Tx FIFO partitions */
 val64 = readq(&bar0->tx_fifo_partition_0);
 val64 |= (TX_FIFO_PARTITION_EN);
 writeq(val64, &bar0->tx_fifo_partition_0);

 /* Filling the Rx round robin registers as per the
 * number of Rings and steering based on QoS with
 * equal priority.
 */

 switch (config->rx_ring_num) {
 case 1:
  val64 = 0x0;
  writeq(val64, &bar0->rx_w_round_robin_0);
  writeq(val64, &bar0->rx_w_round_robin_1);
  writeq(val64, &bar0->rx_w_round_robin_2);
  writeq(val64, &bar0->rx_w_round_robin_3);
  writeq(val64, &bar0->rx_w_round_robin_4);

  val64 = 0x8080808080808080ULL;
  writeq(val64, &bar0->rts_qos_steering);
  break;
 case 2:
  val64 = 0x0001000100010001ULL;
  writeq(val64, &bar0->rx_w_round_robin_0);
  writeq(val64, &bar0->rx_w_round_robin_1);
  writeq(val64, &bar0->rx_w_round_robin_2);
  writeq(val64, &bar0->rx_w_round_robin_3);
  val64 = 0x0001000100000000ULL;
  writeq(val64, &bar0->rx_w_round_robin_4);

  val64 = 0x8080808040404040ULL;
  writeq(val64, &bar0->rts_qos_steering);
  break;
 case 3:
  val64 = 0x0001020001020001ULL;
  writeq(val64, &bar0->rx_w_round_robin_0);
  val64 = 0x0200010200010200ULL;
  writeq(val64, &bar0->rx_w_round_robin_1);
  val64 = 0x0102000102000102ULL;
  writeq(val64, &bar0->rx_w_round_robin_2);
  val64 = 0x0001020001020001ULL;
  writeq(val64, &bar0->rx_w_round_robin_3);
  val64 = 0x0200010200000000ULL;
  writeq(val64, &bar0->rx_w_round_robin_4);

  val64 = 0x8080804040402020ULL;
  writeq(val64, &bar0->rts_qos_steering);
  break;
 case 4:
  val64 = 0x0001020300010203ULL;
  writeq(val64, &bar0->rx_w_round_robin_0);
  writeq(val64, &bar0->rx_w_round_robin_1);
  writeq(val64, &bar0->rx_w_round_robin_2);
  writeq(val64, &bar0->rx_w_round_robin_3);
  val64 = 0x0001020300000000ULL;
  writeq(val64, &bar0->rx_w_round_robin_4);

  val64 = 0x8080404020201010ULL;
  writeq(val64, &bar0->rts_qos_steering);
  break;
 case 5:
  val64 = 0x0001020304000102ULL;
  writeq(val64, &bar0->rx_w_round_robin_0);
  val64 = 0x0304000102030400ULL;
  writeq(val64, &bar0->rx_w_round_robin_1);
  val64 = 0x0102030400010203ULL;
  writeq(val64, &bar0->rx_w_round_robin_2);
  val64 = 0x0400010203040001ULL;
  writeq(val64, &bar0->rx_w_round_robin_3);
  val64 = 0x0203040000000000ULL;
  writeq(val64, &bar0->rx_w_round_robin_4);

  val64 = 0x8080404020201008ULL;
  writeq(val64, &bar0->rts_qos_steering);
  break;
 case 6:
  val64 = 0x0001020304050001ULL;
  writeq(val64, &bar0->rx_w_round_robin_0);
  val64 = 0x0203040500010203ULL;
  writeq(val64, &bar0->rx_w_round_robin_1);
  val64 = 0x0405000102030405ULL;
  writeq(val64, &bar0->rx_w_round_robin_2);
  val64 = 0x0001020304050001ULL;
  writeq(val64, &bar0->rx_w_round_robin_3);
  val64 = 0x0203040500000000ULL;
  writeq(val64, &bar0->rx_w_round_robin_4);

  val64 = 0x8080404020100804ULL;
  writeq(val64, &bar0->rts_qos_steering);
  break;
 case 7:
  val64 = 0x0001020304050600ULL;
  writeq(val64, &bar0->rx_w_round_robin_0);
  val64 = 0x0102030405060001ULL;
  writeq(val64, &bar0->rx_w_round_robin_1);
  val64 = 0x0203040506000102ULL;
  writeq(val64, &bar0->rx_w_round_robin_2);
  val64 = 0x0304050600010203ULL;
  writeq(val64, &bar0->rx_w_round_robin_3);
  val64 = 0x0405060000000000ULL;
  writeq(val64, &bar0->rx_w_round_robin_4);

  val64 = 0x8080402010080402ULL;
  writeq(val64, &bar0->rts_qos_steering);
  break;
 case 8:
  val64 = 0x0001020304050607ULL;
  writeq(val64, &bar0->rx_w_round_robin_0);
  writeq(val64, &bar0->rx_w_round_robin_1);
  writeq(val64, &bar0->rx_w_round_robin_2);
  writeq(val64, &bar0->rx_w_round_robin_3);
  val64 = 0x0001020300000000ULL;
  writeq(val64, &bar0->rx_w_round_robin_4);

  val64 = 0x8040201008040201ULL;
  writeq(val64, &bar0->rts_qos_steering);
  break;
 }

 /* UDP Fix */
 val64 = 0;
 for (i = 0; i < 8; i++)
  writeq(val64, &bar0->rts_frm_len_n[i]);

 /* Set the default rts frame length for the rings configured */
 val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22);
 for (i = 0 ; i < config->rx_ring_num ; i++)
  writeq(val64, &bar0->rts_frm_len_n[i]);

 /* Set the frame length for the configured rings
 * desired by the user
 */

 for (i = 0; i < config->rx_ring_num; i++) {
  /* If rts_frm_len[i] == 0 then it is assumed that user not
 * specified frame length steering.
 * If the user provides the frame length then program
 * the rts_frm_len register for those values or else
 * leave it as it is.
 */

  if (rts_frm_len[i] != 0) {
   writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]),
          &bar0->rts_frm_len_n[i]);
  }
 }

 /* Disable differentiated services steering logic */
 for (i = 0; i < 64; i++) {
  if (rts_ds_steer(nic, i, 0) == FAILURE) {
   DBG_PRINT(ERR_DBG,
      "%s: rts_ds_steer failed on codepoint %d\n",
      dev->name, i);
   return -ENODEV;
  }
 }

 /* Program statistics memory */
 writeq(mac_control->stats_mem_phy, &bar0->stat_addr);

 if (nic->device_type == XFRAME_II_DEVICE) {
  val64 = STAT_BC(0x320);
  writeq(val64, &bar0->stat_byte_cnt);
 }

 /*
 * Initializing the sampling rate for the device to calculate the
 * bandwidth utilization.
 */

 val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) |
  MAC_RX_LINK_UTIL_VAL(rmac_util_period);
 writeq(val64, &bar0->mac_link_util);

 /*
 * Initializing the Transmit and Receive Traffic Interrupt
 * Scheme.
 */


 /* Initialize TTI */
 if (SUCCESS != init_tti(nic, nic->last_link_state, true))
  return -ENODEV;

 /* RTI Initialization */
 if (nic->device_type == XFRAME_II_DEVICE) {
  /*
 * Programmed to generate Apprx 500 Intrs per
 * second
 */

  int count = (nic->config.bus_speed * 125)/4;
  val64 = RTI_DATA1_MEM_RX_TIMER_VAL(count);
 } else
  val64 = RTI_DATA1_MEM_RX_TIMER_VAL(0xFFF);
 val64 |= RTI_DATA1_MEM_RX_URNG_A(0xA) |
  RTI_DATA1_MEM_RX_URNG_B(0x10) |
  RTI_DATA1_MEM_RX_URNG_C(0x30) |
  RTI_DATA1_MEM_RX_TIMER_AC_EN;

 writeq(val64, &bar0->rti_data1_mem);

 val64 = RTI_DATA2_MEM_RX_UFC_A(0x1) |
  RTI_DATA2_MEM_RX_UFC_B(0x2) ;
 if (nic->config.intr_type == MSI_X)
  val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x20) |
     RTI_DATA2_MEM_RX_UFC_D(0x40));
 else
  val64 |= (RTI_DATA2_MEM_RX_UFC_C(0x40) |
     RTI_DATA2_MEM_RX_UFC_D(0x80));
 writeq(val64, &bar0->rti_data2_mem);

 for (i = 0; i < config->rx_ring_num; i++) {
  val64 = RTI_CMD_MEM_WE |
   RTI_CMD_MEM_STROBE_NEW_CMD |
   RTI_CMD_MEM_OFFSET(i);
  writeq(val64, &bar0->rti_command_mem);

  /*
 * Once the operation completes, the Strobe bit of the
 * command register will be reset. We poll for this
 * particular condition. We wait for a maximum of 500ms
 * for the operation to complete, if it's not complete
 * by then we return error.
 */

  time = 0;
  while (true) {
   val64 = readq(&bar0->rti_command_mem);
   if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD))
    break;

   if (time > 10) {
    DBG_PRINT(ERR_DBG, "%s: RTI init failed\n",
       dev->name);
    return -ENODEV;
   }
   time++;
   msleep(50);
  }
 }

 /*
 * Initializing proper values as Pause threshold into all
 * the 8 Queues on Rx side.
 */

 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3);
 writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);

 /* Disable RMAC PAD STRIPPING */
 add = &bar0->mac_cfg;
 val64 = readq(&bar0->mac_cfg);
 val64 &= ~(MAC_CFG_RMAC_STRIP_PAD);
 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
 writel((u32) (val64), add);
 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
 writel((u32) (val64 >> 32), (add + 4));
 val64 = readq(&bar0->mac_cfg);

 /* Enable FCS stripping by adapter */
 add = &bar0->mac_cfg;
 val64 = readq(&bar0->mac_cfg);
 val64 |= MAC_CFG_RMAC_STRIP_FCS;
 if (nic->device_type == XFRAME_II_DEVICE)
  writeq(val64, &bar0->mac_cfg);
 else {
  writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
  writel((u32) (val64), add);
  writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
  writel((u32) (val64 >> 32), (add + 4));
 }

 /*
 * Set the time value to be inserted in the pause frame
 * generated by xena.
 */

 val64 = readq(&bar0->rmac_pause_cfg);
 val64 &= ~(RMAC_PAUSE_HG_PTIME(0xffff));
 val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time);
 writeq(val64, &bar0->rmac_pause_cfg);

 /*
 * Set the Threshold Limit for Generating the pause frame
 * If the amount of data in any Queue exceeds ratio of
 * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256
 * pause frame is generated
 */

 val64 = 0;
 for (i = 0; i < 4; i++) {
  val64 |= (((u64)0xFF00 |
      nic->mac_control.mc_pause_threshold_q0q3)
     << (i * 2 * 8));
 }
 writeq(val64, &bar0->mc_pause_thresh_q0q3);

 val64 = 0;
 for (i = 0; i < 4; i++) {
  val64 |= (((u64)0xFF00 |
      nic->mac_control.mc_pause_threshold_q4q7)
     << (i * 2 * 8));
 }
 writeq(val64, &bar0->mc_pause_thresh_q4q7);

 /*
 * TxDMA will stop Read request if the number of read split has
 * exceeded the limit pointed by shared_splits
 */

 val64 = readq(&bar0->pic_control);
 val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits);
 writeq(val64, &bar0->pic_control);

 if (nic->config.bus_speed == 266) {
  writeq(TXREQTO_VAL(0x7f) | TXREQTO_EN, &bar0->txreqtimeout);
  writeq(0x0, &bar0->read_retry_delay);
  writeq(0x0, &bar0->write_retry_delay);
 }

 /*
 * Programming the Herc to split every write transaction
 * that does not start on an ADB to reduce disconnects.
 */

 if (nic->device_type == XFRAME_II_DEVICE) {
  val64 = FAULT_BEHAVIOUR | EXT_REQ_EN |
   MISC_LINK_STABILITY_PRD(3);
  writeq(val64, &bar0->misc_control);
  val64 = readq(&bar0->pic_control2);
  val64 &= ~(s2BIT(13)|s2BIT(14)|s2BIT(15));
  writeq(val64, &bar0->pic_control2);
 }
 if (strstr(nic->product_name, "CX4")) {
  val64 = TMAC_AVG_IPG(0x17);
  writeq(val64, &bar0->tmac_avg_ipg);
 }

 return SUCCESS;
}
#define LINK_UP_DOWN_INTERRUPT  1
#define MAC_RMAC_ERR_TIMER  2

static int s2io_link_fault_indication(struct s2io_nic *nic)
{
 if (nic->device_type == XFRAME_II_DEVICE)
  return LINK_UP_DOWN_INTERRUPT;
 else
  return MAC_RMAC_ERR_TIMER;
}

/**
 *  do_s2io_write_bits -  update alarm bits in alarm register
 *  @value: alarm bits
 *  @flag: interrupt status
 *  @addr: address value
 *  Description: update alarm bits in alarm register
 *  Return Value:
 *  NONE.
 */

static void do_s2io_write_bits(u64 value, int flag, void __iomem *addr)
{
 u64 temp64;

 temp64 = readq(addr);

 if (flag == ENABLE_INTRS)
  temp64 &= ~((u64)value);
 else
  temp64 |= ((u64)value);
 writeq(temp64, addr);
}

static void en_dis_err_alarms(struct s2io_nic *nic, u16 mask, int flag)
{
 struct XENA_dev_config __iomem *bar0 = nic->bar0;
 register u64 gen_int_mask = 0;
 u64 interruptible;

 writeq(DISABLE_ALL_INTRS, &bar0->general_int_mask);
 if (mask & TX_DMA_INTR) {
  gen_int_mask |= TXDMA_INT_M;

  do_s2io_write_bits(TXDMA_TDA_INT | TXDMA_PFC_INT |
       TXDMA_PCC_INT | TXDMA_TTI_INT |
       TXDMA_LSO_INT | TXDMA_TPA_INT |
       TXDMA_SM_INT, flag, &bar0->txdma_int_mask);

  do_s2io_write_bits(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM |
       PFC_MISC_0_ERR | PFC_MISC_1_ERR |
       PFC_PCIX_ERR | PFC_ECC_SG_ERR, flag,
       &bar0->pfc_err_mask);

  do_s2io_write_bits(TDA_Fn_ECC_DB_ERR | TDA_SM0_ERR_ALARM |
       TDA_SM1_ERR_ALARM | TDA_Fn_ECC_SG_ERR |
       TDA_PCIX_ERR, flag, &bar0->tda_err_mask);

  do_s2io_write_bits(PCC_FB_ECC_DB_ERR | PCC_TXB_ECC_DB_ERR |
       PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM |
       PCC_N_SERR | PCC_6_COF_OV_ERR |
       PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR |
       PCC_7_LSO_OV_ERR | PCC_FB_ECC_SG_ERR |
       PCC_TXB_ECC_SG_ERR,
       flag, &bar0->pcc_err_mask);

  do_s2io_write_bits(TTI_SM_ERR_ALARM | TTI_ECC_SG_ERR |
       TTI_ECC_DB_ERR, flag, &bar0->tti_err_mask);

  do_s2io_write_bits(LSO6_ABORT | LSO7_ABORT |
       LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM |
       LSO6_SEND_OFLOW | LSO7_SEND_OFLOW,
       flag, &bar0->lso_err_mask);

  do_s2io_write_bits(TPA_SM_ERR_ALARM | TPA_TX_FRM_DROP,
       flag, &bar0->tpa_err_mask);

  do_s2io_write_bits(SM_SM_ERR_ALARM, flag, &bar0->sm_err_mask);
 }

 if (mask & TX_MAC_INTR) {
  gen_int_mask |= TXMAC_INT_M;
  do_s2io_write_bits(MAC_INT_STATUS_TMAC_INT, flag,
       &bar0->mac_int_mask);
  do_s2io_write_bits(TMAC_TX_BUF_OVRN | TMAC_TX_SM_ERR |
       TMAC_ECC_SG_ERR | TMAC_ECC_DB_ERR |
       TMAC_DESC_ECC_SG_ERR | TMAC_DESC_ECC_DB_ERR,
       flag, &bar0->mac_tmac_err_mask);
 }

 if (mask & TX_XGXS_INTR) {
  gen_int_mask |= TXXGXS_INT_M;
  do_s2io_write_bits(XGXS_INT_STATUS_TXGXS, flag,
       &bar0->xgxs_int_mask);
  do_s2io_write_bits(TXGXS_ESTORE_UFLOW | TXGXS_TX_SM_ERR |
       TXGXS_ECC_SG_ERR | TXGXS_ECC_DB_ERR,
       flag, &bar0->xgxs_txgxs_err_mask);
 }

 if (mask & RX_DMA_INTR) {
  gen_int_mask |= RXDMA_INT_M;
  do_s2io_write_bits(RXDMA_INT_RC_INT_M | RXDMA_INT_RPA_INT_M |
       RXDMA_INT_RDA_INT_M | RXDMA_INT_RTI_INT_M,
       flag, &bar0->rxdma_int_mask);
  do_s2io_write_bits(RC_PRCn_ECC_DB_ERR | RC_FTC_ECC_DB_ERR |
       RC_PRCn_SM_ERR_ALARM | RC_FTC_SM_ERR_ALARM |
       RC_PRCn_ECC_SG_ERR | RC_FTC_ECC_SG_ERR |
       RC_RDA_FAIL_WR_Rn, flag, &bar0->rc_err_mask);
  do_s2io_write_bits(PRC_PCI_AB_RD_Rn | PRC_PCI_AB_WR_Rn |
       PRC_PCI_AB_F_WR_Rn | PRC_PCI_DP_RD_Rn |
       PRC_PCI_DP_WR_Rn | PRC_PCI_DP_F_WR_Rn, flag,
       &bar0->prc_pcix_err_mask);
  do_s2io_write_bits(RPA_SM_ERR_ALARM | RPA_CREDIT_ERR |
       RPA_ECC_SG_ERR | RPA_ECC_DB_ERR, flag,
       &bar0->rpa_err_mask);
  do_s2io_write_bits(RDA_RXDn_ECC_DB_ERR | RDA_FRM_ECC_DB_N_AERR |
       RDA_SM1_ERR_ALARM | RDA_SM0_ERR_ALARM |
       RDA_RXD_ECC_DB_SERR | RDA_RXDn_ECC_SG_ERR |
       RDA_FRM_ECC_SG_ERR |
       RDA_MISC_ERR|RDA_PCIX_ERR,
       flag, &bar0->rda_err_mask);
  do_s2io_write_bits(RTI_SM_ERR_ALARM |
       RTI_ECC_SG_ERR | RTI_ECC_DB_ERR,
       flag, &bar0->rti_err_mask);
 }

 if (mask & RX_MAC_INTR) {
  gen_int_mask |= RXMAC_INT_M;
  do_s2io_write_bits(MAC_INT_STATUS_RMAC_INT, flag,
       &bar0->mac_int_mask);
  interruptible = (RMAC_RX_BUFF_OVRN | RMAC_RX_SM_ERR |
     RMAC_UNUSED_INT | RMAC_SINGLE_ECC_ERR |
     RMAC_DOUBLE_ECC_ERR);
  if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER)
   interruptible |= RMAC_LINK_STATE_CHANGE_INT;
  do_s2io_write_bits(interruptible,
       flag, &bar0->mac_rmac_err_mask);
 }

 if (mask & RX_XGXS_INTR) {
  gen_int_mask |= RXXGXS_INT_M;
  do_s2io_write_bits(XGXS_INT_STATUS_RXGXS, flag,
       &bar0->xgxs_int_mask);
  do_s2io_write_bits(RXGXS_ESTORE_OFLOW | RXGXS_RX_SM_ERR, flag,
       &bar0->xgxs_rxgxs_err_mask);
 }

 if (mask & MC_INTR) {
  gen_int_mask |= MC_INT_M;
  do_s2io_write_bits(MC_INT_MASK_MC_INT,
       flag, &bar0->mc_int_mask);
  do_s2io_write_bits(MC_ERR_REG_SM_ERR | MC_ERR_REG_ECC_ALL_SNG |
       MC_ERR_REG_ECC_ALL_DBL | PLL_LOCK_N, flag,
       &bar0->mc_err_mask);
 }
 nic->general_int_mask = gen_int_mask;

 /* Remove this line when alarm interrupts are enabled */
 nic->general_int_mask = 0;
}

/**
 *  en_dis_able_nic_intrs - Enable or Disable the interrupts
 *  @nic: device private variable,
 *  @mask: A mask indicating which Intr block must be modified and,
 *  @flag: A flag indicating whether to enable or disable the Intrs.
 *  Description: This function will either disable or enable the interrupts
 *  depending on the flag argument. The mask argument can be used to
 *  enable/disable any Intr block.
 *  Return Value: NONE.
 */


static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
{
 struct XENA_dev_config __iomem *bar0 = nic->bar0;
 register u64 temp64 = 0, intr_mask = 0;

 intr_mask = nic->general_int_mask;

 /*  Top level interrupt classification */
 /*  PIC Interrupts */
 if (mask & TX_PIC_INTR) {
  /*  Enable PIC Intrs in the general intr mask register */
  intr_mask |= TXPIC_INT_M;
  if (flag == ENABLE_INTRS) {
   /*
 * If Hercules adapter enable GPIO otherwise
 * disable all PCIX, Flash, MDIO, IIC and GPIO
 * interrupts for now.
 * TODO
 */

   if (s2io_link_fault_indication(nic) ==
       LINK_UP_DOWN_INTERRUPT) {
    do_s2io_write_bits(PIC_INT_GPIO, flag,
         &bar0->pic_int_mask);
    do_s2io_write_bits(GPIO_INT_MASK_LINK_UP, flag,
         &bar0->gpio_int_mask);
   } else
    writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
  } else if (flag == DISABLE_INTRS) {
   /*
 * Disable PIC Intrs in the general
 * intr mask register
 */

   writeq(DISABLE_ALL_INTRS, &bar0->pic_int_mask);
  }
 }

 /*  Tx traffic interrupts */
 if (mask & TX_TRAFFIC_INTR) {
  intr_mask |= TXTRAFFIC_INT_M;
  if (flag == ENABLE_INTRS) {
   /*
 * Enable all the Tx side interrupts
 * writing 0 Enables all 64 TX interrupt levels
 */

   writeq(0x0, &bar0->tx_traffic_mask);
  } else if (flag == DISABLE_INTRS) {
   /*
 * Disable Tx Traffic Intrs in the general intr mask
 * register.
 */

   writeq(DISABLE_ALL_INTRS, &bar0->tx_traffic_mask);
  }
 }

 /*  Rx traffic interrupts */
 if (mask & RX_TRAFFIC_INTR) {
  intr_mask |= RXTRAFFIC_INT_M;
  if (flag == ENABLE_INTRS) {
   /* writing 0 Enables all 8 RX interrupt levels */
   writeq(0x0, &bar0->rx_traffic_mask);
  } else if (flag == DISABLE_INTRS) {
   /*
 * Disable Rx Traffic Intrs in the general intr mask
 * register.
 */

   writeq(DISABLE_ALL_INTRS, &bar0->rx_traffic_mask);
  }
 }

 temp64 = readq(&bar0->general_int_mask);
 if (flag == ENABLE_INTRS)
  temp64 &= ~((u64)intr_mask);
 else
  temp64 = DISABLE_ALL_INTRS;
 writeq(temp64, &bar0->general_int_mask);

 nic->general_int_mask = readq(&bar0->general_int_mask);
}

/**
 *  verify_pcc_quiescent- Checks for PCC quiescent state
 *  @sp : private member of the device structure, which is a pointer to the
 *  s2io_nic structure.
 *  @flag: boolean controlling function path
 *  Return: 1 If PCC is quiescence
 *          0 If PCC is not quiescence
 */

static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
{
 int ret = 0, herc;
 struct XENA_dev_config __iomem *bar0 = sp->bar0;
 u64 val64 = readq(&bar0->adapter_status);

 herc = (sp->device_type == XFRAME_II_DEVICE);

 if (flag == false) {
  if ((!herc && (sp->pdev->revision >= 4)) || herc) {
   if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
    ret = 1;
  } else {
   if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
    ret = 1;
  }
 } else {
  if ((!herc && (sp->pdev->revision >= 4)) || herc) {
   if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
        ADAPTER_STATUS_RMAC_PCC_IDLE))
    ret = 1;
  } else {
   if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
        ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
    ret = 1;
  }
 }

 return ret;
}
/**
 *  verify_xena_quiescence - Checks whether the H/W is ready
 *  @sp : private member of the device structure, which is a pointer to the
 *  s2io_nic structure.
 *  Description: Returns whether the H/W is ready to go or not. Depending
 *  on whether adapter enable bit was written or not the comparison
 *  differs and the calling function passes the input argument flag to
 *  indicate this.
 *  Return: 1 If xena is quiescence
 *          0 If Xena is not quiescence
 */


static int verify_xena_quiescence(struct s2io_nic *sp)
{
 int  mode;
 struct XENA_dev_config __iomem *bar0 = sp->bar0;
 u64 val64 = readq(&bar0->adapter_status);
 mode = s2io_verify_pci_mode(sp);

 if (!(val64 & ADAPTER_STATUS_TDMA_READY)) {
  DBG_PRINT(ERR_DBG, "TDMA is not ready!\n");
  return 0;
 }
 if (!(val64 & ADAPTER_STATUS_RDMA_READY)) {
  DBG_PRINT(ERR_DBG, "RDMA is not ready!\n");
  return 0;
 }
 if (!(val64 & ADAPTER_STATUS_PFC_READY)) {
  DBG_PRINT(ERR_DBG, "PFC is not ready!\n");
  return 0;
 }
 if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
  DBG_PRINT(ERR_DBG, "TMAC BUF is not empty!\n");
  return 0;
 }
 if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) {
  DBG_PRINT(ERR_DBG, "PIC is not QUIESCENT!\n");
  return 0;
 }
 if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) {
  DBG_PRINT(ERR_DBG, "MC_DRAM is not ready!\n");
  return 0;
 }
 if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) {
  DBG_PRINT(ERR_DBG, "MC_QUEUES is not ready!\n");
  return 0;
 }
 if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) {
  DBG_PRINT(ERR_DBG, "M_PLL is not locked!\n");
  return 0;
 }

 /*
 * In PCI 33 mode, the P_PLL is not used, and therefore,
 * the P_PLL_LOCK bit in the adapter_status register will
 * not be asserted.
 */

 if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) &&
     sp->device_type == XFRAME_II_DEVICE &&
     mode != PCI_MODE_PCI_33) {
  DBG_PRINT(ERR_DBG, "P_PLL is not locked!\n");
  return 0;
 }
 if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
       ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
  DBG_PRINT(ERR_DBG, "RC_PRC is not QUIESCENT!\n");
  return 0;
 }
 return 1;
}

/**
 * fix_mac_address -  Fix for Mac addr problem on Alpha platforms
 * @sp: Pointer to device specifc structure
 * Description :
 * New procedure to clear mac address reading  problems on Alpha platforms
 *
 */


static void fix_mac_address(struct s2io_nic *sp)
{
 struct XENA_dev_config __iomem *bar0 = sp->bar0;
 int i = 0;

 while (fix_mac[i] != END_SIGN) {
  writeq(fix_mac[i++], &bar0->gpio_control);
  udelay(10);
  (void) readq(&bar0->gpio_control);
 }
}

/**
 *  start_nic - Turns the device on
 *  @nic : device private variable.
 *  Description:
 *  This function actually turns the device on. Before this  function is
 *  called,all Registers are configured from their reset states
 *  and shared memory is allocated but the NIC is still quiescent. On
 *  calling this function, the device interrupts are cleared and the NIC is
 *  literally switched on by writing into the adapter control register.
 *  Return Value:
 *  SUCCESS on success and -1 on failure.
 */


static int start_nic(struct s2io_nic *nic)
{
 struct XENA_dev_config __iomem *bar0 = nic->bar0;
 struct net_device *dev = nic->dev;
 register u64 val64 = 0;
 u16 subid, i;
 struct config_param *config = &nic->config;
 struct mac_info *mac_control = &nic->mac_control;

 /*  PRC Initialization and configuration */
 for (i = 0; i < config->rx_ring_num; i++) {
  struct ring_info *ring = &mac_control->rings[i];

  writeq((u64)ring->rx_blocks[0].block_dma_addr,
         &bar0->prc_rxd0_n[i]);

  val64 = readq(&bar0->prc_ctrl_n[i]);
  if (nic->rxd_mode == RXD_MODE_1)
   val64 |= PRC_CTRL_RC_ENABLED;
  else
   val64 |= PRC_CTRL_RC_ENABLED | PRC_CTRL_RING_MODE_3;
  if (nic->device_type == XFRAME_II_DEVICE)
   val64 |= PRC_CTRL_GROUP_READS;
  val64 &= ~PRC_CTRL_RXD_BACKOFF_INTERVAL(0xFFFFFF);
  val64 |= PRC_CTRL_RXD_BACKOFF_INTERVAL(0x1000);
  writeq(val64, &bar0->prc_ctrl_n[i]);
 }

 if (nic->rxd_mode == RXD_MODE_3B) {
  /* Enabling 2 buffer mode by writing into Rx_pa_cfg reg. */
  val64 = readq(&bar0->rx_pa_cfg);
  val64 |= RX_PA_CFG_IGNORE_L2_ERR;
  writeq(val64, &bar0->rx_pa_cfg);
 }

 if (vlan_tag_strip == 0) {
  val64 = readq(&bar0->rx_pa_cfg);
  val64 &= ~RX_PA_CFG_STRIP_VLAN_TAG;
  writeq(val64, &bar0->rx_pa_cfg);
  nic->vlan_strip_flag = 0;
 }

 /*
 * Enabling MC-RLDRAM. After enabling the device, we timeout
 * for around 100ms, which is approximately the time required
 * for the device to be ready for operation.
 */

 val64 = readq(&bar0->mc_rldram_mrs);
 val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE | MC_RLDRAM_MRS_ENABLE;
 SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
 val64 = readq(&bar0->mc_rldram_mrs);

 msleep(100); /* Delay by around 100 ms. */

 /* Enabling ECC Protection. */
 val64 = readq(&bar0->adapter_control);
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=96 H=86 G=90

¤ Dauer der Verarbeitung: 0.24 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.