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

Quelle  bnx2x_main.c   Sprache: C

 
/* bnx2x_main.c: QLogic Everest network driver.
 *
 * Copyright (c) 2007-2013 Broadcom Corporation
 * Copyright (c) 2014 QLogic Corporation
 * All rights reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Maintained by: Ariel Elior <ariel.elior@qlogic.com>
 * Written by: Eliezer Tamir
 * Based on code from Michael Chan's bnx2 driver
 * UDP CSUM errata workaround by Arik Gendelman
 * Slowpath and fastpath rework by Vladislav Zolotarov
 * Statistics and Link management by Yitchak Gertner
 *
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/device.h>  /* for dev_info() */
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/dma-mapping.h>
#include <linux/bitops.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
#include <linux/time.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/if_vlan.h>
#include <linux/crash_dump.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/tcp.h>
#include <net/vxlan.h>
#include <net/checksum.h>
#include <net/ip6_checksum.h>
#include <linux/workqueue.h>
#include <linux/crc32.h>
#include <linux/crc32c.h>
#include <linux/prefetch.h>
#include <linux/zlib.h>
#include <linux/io.h>
#include <linux/semaphore.h>
#include <linux/stringify.h>
#include <linux/vmalloc.h>
#include "bnx2x.h"
#include "bnx2x_init.h"
#include "bnx2x_init_ops.h"
#include "bnx2x_cmn.h"
#include "bnx2x_vfpf.h"
#include "bnx2x_dcb.h"
#include "bnx2x_sp.h"
#include <linux/firmware.h>
#include "bnx2x_fw_file_hdr.h"
/* FW files */
#define FW_FILE_VERSION     \
 __stringify(BCM_5710_FW_MAJOR_VERSION) "." \
 __stringify(BCM_5710_FW_MINOR_VERSION) "." \
 __stringify(BCM_5710_FW_REVISION_VERSION) "." \
 __stringify(BCM_5710_FW_ENGINEERING_VERSION)

#define FW_FILE_VERSION_V15    \
 __stringify(BCM_5710_FW_MAJOR_VERSION) "."      \
 __stringify(BCM_5710_FW_MINOR_VERSION) "." \
 __stringify(BCM_5710_FW_REVISION_VERSION_V15) "." \
 __stringify(BCM_5710_FW_ENGINEERING_VERSION)

#define FW_FILE_NAME_E1  "bnx2x/bnx2x-e1-" FW_FILE_VERSION ".fw"
#define FW_FILE_NAME_E1H "bnx2x/bnx2x-e1h-" FW_FILE_VERSION ".fw"
#define FW_FILE_NAME_E2  "bnx2x/bnx2x-e2-" FW_FILE_VERSION ".fw"
#define FW_FILE_NAME_E1_V15 "bnx2x/bnx2x-e1-" FW_FILE_VERSION_V15 ".fw"
#define FW_FILE_NAME_E1H_V15 "bnx2x/bnx2x-e1h-" FW_FILE_VERSION_V15 ".fw"
#define FW_FILE_NAME_E2_V15 "bnx2x/bnx2x-e2-" FW_FILE_VERSION_V15 ".fw"

/* Time in jiffies before concluding the transmitter is hung */
#define TX_TIMEOUT  (5*HZ)

MODULE_AUTHOR("Eliezer Tamir");
MODULE_DESCRIPTION("QLogic "
     "BCM57710/57711/57711E/"
     "57712/57712_MF/57800/57800_MF/57810/57810_MF/"
     "57840/57840_MF Driver");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(FW_FILE_NAME_E1);
MODULE_FIRMWARE(FW_FILE_NAME_E1H);
MODULE_FIRMWARE(FW_FILE_NAME_E2);
MODULE_FIRMWARE(FW_FILE_NAME_E1_V15);
MODULE_FIRMWARE(FW_FILE_NAME_E1H_V15);
MODULE_FIRMWARE(FW_FILE_NAME_E2_V15);

int bnx2x_num_queues;
module_param_named(num_queues, bnx2x_num_queues, int, 0444);
MODULE_PARM_DESC(num_queues,
   " Set number of queues (default is as a number of CPUs)");

static int disable_tpa;
module_param(disable_tpa, int, 0444);
MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature");

static int int_mode;
module_param(int_mode, int, 0444);
MODULE_PARM_DESC(int_mode, " Force interrupt mode other than MSI-X "
    "(1 INT#x; 2 MSI)");

static int dropless_fc;
module_param(dropless_fc, int, 0444);
MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring");

static int mrrs = -1;
module_param(mrrs, int, 0444);
MODULE_PARM_DESC(mrrs, " Force Max Read Req Size (0..3) (for debug)");

static int debug;
module_param(debug, int, 0444);
MODULE_PARM_DESC(debug, " Default debug msglevel");

static struct workqueue_struct *bnx2x_wq;
struct workqueue_struct *bnx2x_iov_wq;

struct bnx2x_mac_vals {
 u32 xmac_addr;
 u32 xmac_val;
 u32 emac_addr;
 u32 emac_val;
 u32 umac_addr[2];
 u32 umac_val[2];
 u32 bmac_addr;
 u32 bmac_val[2];
};

enum bnx2x_board_type {
 BCM57710 = 0,
 BCM57711,
 BCM57711E,
 BCM57712,
 BCM57712_MF,
 BCM57712_VF,
 BCM57800,
 BCM57800_MF,
 BCM57800_VF,
 BCM57810,
 BCM57810_MF,
 BCM57810_VF,
 BCM57840_4_10,
 BCM57840_2_20,
 BCM57840_MF,
 BCM57840_VF,
 BCM57811,
 BCM57811_MF,
 BCM57840_O,
 BCM57840_MFO,
 BCM57811_VF
};

/* indexed by board_type, above */
static struct {
 char *name;
} board_info[] = {
 [BCM57710] = { "QLogic BCM57710 10 Gigabit PCIe [Everest]" },
 [BCM57711] = { "QLogic BCM57711 10 Gigabit PCIe" },
 [BCM57711E] = { "QLogic BCM57711E 10 Gigabit PCIe" },
 [BCM57712] = { "QLogic BCM57712 10 Gigabit Ethernet" },
 [BCM57712_MF] = { "QLogic BCM57712 10 Gigabit Ethernet Multi Function" },
 [BCM57712_VF] = { "QLogic BCM57712 10 Gigabit Ethernet Virtual Function" },
 [BCM57800] = { "QLogic BCM57800 10 Gigabit Ethernet" },
 [BCM57800_MF] = { "QLogic BCM57800 10 Gigabit Ethernet Multi Function" },
 [BCM57800_VF] = { "QLogic BCM57800 10 Gigabit Ethernet Virtual Function" },
 [BCM57810] = { "QLogic BCM57810 10 Gigabit Ethernet" },
 [BCM57810_MF] = { "QLogic BCM57810 10 Gigabit Ethernet Multi Function" },
 [BCM57810_VF] = { "QLogic BCM57810 10 Gigabit Ethernet Virtual Function" },
 [BCM57840_4_10] = { "QLogic BCM57840 10 Gigabit Ethernet" },
 [BCM57840_2_20] = { "QLogic BCM57840 20 Gigabit Ethernet" },
 [BCM57840_MF] = { "QLogic BCM57840 10/20 Gigabit Ethernet Multi Function" },
 [BCM57840_VF] = { "QLogic BCM57840 10/20 Gigabit Ethernet Virtual Function" },
 [BCM57811] = { "QLogic BCM57811 10 Gigabit Ethernet" },
 [BCM57811_MF] = { "QLogic BCM57811 10 Gigabit Ethernet Multi Function" },
 [BCM57840_O] = { "QLogic BCM57840 10/20 Gigabit Ethernet" },
 [BCM57840_MFO] = { "QLogic BCM57840 10/20 Gigabit Ethernet Multi Function" },
 [BCM57811_VF] = { "QLogic BCM57840 10/20 Gigabit Ethernet Virtual Function" }
};

#ifndef PCI_DEVICE_ID_NX2_57710
#define PCI_DEVICE_ID_NX2_57710  CHIP_NUM_57710
#endif
#ifndef PCI_DEVICE_ID_NX2_57711
#define PCI_DEVICE_ID_NX2_57711  CHIP_NUM_57711
#endif
#ifndef PCI_DEVICE_ID_NX2_57711E
#define PCI_DEVICE_ID_NX2_57711E CHIP_NUM_57711E
#endif
#ifndef PCI_DEVICE_ID_NX2_57712
#define PCI_DEVICE_ID_NX2_57712  CHIP_NUM_57712
#endif
#ifndef PCI_DEVICE_ID_NX2_57712_MF
#define PCI_DEVICE_ID_NX2_57712_MF CHIP_NUM_57712_MF
#endif
#ifndef PCI_DEVICE_ID_NX2_57712_VF
#define PCI_DEVICE_ID_NX2_57712_VF CHIP_NUM_57712_VF
#endif
#ifndef PCI_DEVICE_ID_NX2_57800
#define PCI_DEVICE_ID_NX2_57800  CHIP_NUM_57800
#endif
#ifndef PCI_DEVICE_ID_NX2_57800_MF
#define PCI_DEVICE_ID_NX2_57800_MF CHIP_NUM_57800_MF
#endif
#ifndef PCI_DEVICE_ID_NX2_57800_VF
#define PCI_DEVICE_ID_NX2_57800_VF CHIP_NUM_57800_VF
#endif
#ifndef PCI_DEVICE_ID_NX2_57810
#define PCI_DEVICE_ID_NX2_57810  CHIP_NUM_57810
#endif
#ifndef PCI_DEVICE_ID_NX2_57810_MF
#define PCI_DEVICE_ID_NX2_57810_MF CHIP_NUM_57810_MF
#endif
#ifndef PCI_DEVICE_ID_NX2_57840_O
#define PCI_DEVICE_ID_NX2_57840_O CHIP_NUM_57840_OBSOLETE
#endif
#ifndef PCI_DEVICE_ID_NX2_57810_VF
#define PCI_DEVICE_ID_NX2_57810_VF CHIP_NUM_57810_VF
#endif
#ifndef PCI_DEVICE_ID_NX2_57840_4_10
#define PCI_DEVICE_ID_NX2_57840_4_10 CHIP_NUM_57840_4_10
#endif
#ifndef PCI_DEVICE_ID_NX2_57840_2_20
#define PCI_DEVICE_ID_NX2_57840_2_20 CHIP_NUM_57840_2_20
#endif
#ifndef PCI_DEVICE_ID_NX2_57840_MFO
#define PCI_DEVICE_ID_NX2_57840_MFO CHIP_NUM_57840_MF_OBSOLETE
#endif
#ifndef PCI_DEVICE_ID_NX2_57840_MF
#define PCI_DEVICE_ID_NX2_57840_MF CHIP_NUM_57840_MF
#endif
#ifndef PCI_DEVICE_ID_NX2_57840_VF
#define PCI_DEVICE_ID_NX2_57840_VF CHIP_NUM_57840_VF
#endif
#ifndef PCI_DEVICE_ID_NX2_57811
#define PCI_DEVICE_ID_NX2_57811  CHIP_NUM_57811
#endif
#ifndef PCI_DEVICE_ID_NX2_57811_MF
#define PCI_DEVICE_ID_NX2_57811_MF CHIP_NUM_57811_MF
#endif
#ifndef PCI_DEVICE_ID_NX2_57811_VF
#define PCI_DEVICE_ID_NX2_57811_VF CHIP_NUM_57811_VF
#endif

static const struct pci_device_id bnx2x_pci_tbl[] = {
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57710), BCM57710 },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711), BCM57711 },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57711E), BCM57711E },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712), BCM57712 },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_MF), BCM57712_MF },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57712_VF), BCM57712_VF },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800), BCM57800 },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_MF), BCM57800_MF },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_VF), BCM57800_VF },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810), BCM57810 },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_MF), BCM57810_MF },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_O), BCM57840_O },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_4_10), BCM57840_4_10 },
 { PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_NX2_57840_4_10), BCM57840_4_10 },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_2_20), BCM57840_2_20 },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_VF), BCM57810_VF },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MFO), BCM57840_MFO },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MF), BCM57840_MF },
 { PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_NX2_57840_MF), BCM57840_MF },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_VF), BCM57840_VF },
 { PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_NX2_57840_VF), BCM57840_VF },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811), BCM57811 },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_MF), BCM57811_MF },
 { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_VF), BCM57811_VF },
 { 0 }
};

MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);

const u32 dmae_reg_go_c[] = {
 DMAE_REG_GO_C0, DMAE_REG_GO_C1, DMAE_REG_GO_C2, DMAE_REG_GO_C3,
 DMAE_REG_GO_C4, DMAE_REG_GO_C5, DMAE_REG_GO_C6, DMAE_REG_GO_C7,
 DMAE_REG_GO_C8, DMAE_REG_GO_C9, DMAE_REG_GO_C10, DMAE_REG_GO_C11,
 DMAE_REG_GO_C12, DMAE_REG_GO_C13, DMAE_REG_GO_C14, DMAE_REG_GO_C15
};

/* Global resources for unloading a previously loaded device */
#define BNX2X_PREV_WAIT_NEEDED 1
static DEFINE_SEMAPHORE(bnx2x_prev_sem, 1);
static LIST_HEAD(bnx2x_prev_list);

/* Forward declaration */
static struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
static u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp);
static int bnx2x_set_storm_rx_mode(struct bnx2x *bp);

/****************************************************************************
* General service functions
****************************************************************************/


static int bnx2x_hwtstamp_ioctl(struct bnx2x *bp, struct ifreq *ifr);

static void __storm_memset_dma_mapping(struct bnx2x *bp,
           u32 addr, dma_addr_t mapping)
{
 REG_WR(bp,  addr, U64_LO(mapping));
 REG_WR(bp,  addr + 4, U64_HI(mapping));
}

static void storm_memset_spq_addr(struct bnx2x *bp,
      dma_addr_t mapping, u16 abs_fid)
{
 u32 addr = XSEM_REG_FAST_MEMORY +
   XSTORM_SPQ_PAGE_BASE_OFFSET(abs_fid);

 __storm_memset_dma_mapping(bp, addr, mapping);
}

static void storm_memset_vf_to_pf(struct bnx2x *bp, u16 abs_fid,
      u16 pf_id)
{
 REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_VF_TO_PF_OFFSET(abs_fid),
  pf_id);
 REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_VF_TO_PF_OFFSET(abs_fid),
  pf_id);
 REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_VF_TO_PF_OFFSET(abs_fid),
  pf_id);
 REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_VF_TO_PF_OFFSET(abs_fid),
  pf_id);
}

static void storm_memset_func_en(struct bnx2x *bp, u16 abs_fid,
     u8 enable)
{
 REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNC_EN_OFFSET(abs_fid),
  enable);
 REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNC_EN_OFFSET(abs_fid),
  enable);
 REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNC_EN_OFFSET(abs_fid),
  enable);
 REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(abs_fid),
  enable);
}

static void storm_memset_eq_data(struct bnx2x *bp,
     struct event_ring_data *eq_data,
    u16 pfid)
{
 size_t size = sizeof(struct event_ring_data);

 u32 addr = BAR_CSTRORM_INTMEM + CSTORM_EVENT_RING_DATA_OFFSET(pfid);

 __storm_memset_struct(bp, addr, size, (u32 *)eq_data);
}

static void storm_memset_eq_prod(struct bnx2x *bp, u16 eq_prod,
     u16 pfid)
{
 u32 addr = BAR_CSTRORM_INTMEM + CSTORM_EVENT_RING_PROD_OFFSET(pfid);
 REG_WR16(bp, addr, eq_prod);
}

/* used only at init
 * locking is done by mcp
 */

static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val)
{
 pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
 pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val);
 pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
          PCICFG_VENDOR_ID_OFFSET);
}

static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
{
 u32 val;

 pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
 pci_read_config_dword(bp->pdev, PCICFG_GRC_DATA, &val);
 pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
          PCICFG_VENDOR_ID_OFFSET);

 return val;
}

#define DMAE_DP_SRC_GRC  "grc src_addr [%08x]"
#define DMAE_DP_SRC_PCI  "pci src_addr [%x:%08x]"
#define DMAE_DP_DST_GRC  "grc dst_addr [%08x]"
#define DMAE_DP_DST_PCI  "pci dst_addr [%x:%08x]"
#define DMAE_DP_DST_NONE "dst_addr [none]"

static void bnx2x_dp_dmae(struct bnx2x *bp,
     struct dmae_command *dmae, int msglvl)
{
 u32 src_type = dmae->opcode & DMAE_COMMAND_SRC;
 int i;

 switch (dmae->opcode & DMAE_COMMAND_DST) {
 case DMAE_CMD_DST_PCI:
  if (src_type == DMAE_CMD_SRC_PCI)
   DP(msglvl, "DMAE: opcode 0x%08x\n"
      "src [%x:%08x], len [%d*4], dst [%x:%08x]\n"
      "comp_addr [%x:%08x], comp_val 0x%08x\n",
      dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
      dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
      dmae->comp_addr_hi, dmae->comp_addr_lo,
      dmae->comp_val);
  else
   DP(msglvl, "DMAE: opcode 0x%08x\n"
      "src [%08x], len [%d*4], dst [%x:%08x]\n"
      "comp_addr [%x:%08x], comp_val 0x%08x\n",
      dmae->opcode, dmae->src_addr_lo >> 2,
      dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo,
      dmae->comp_addr_hi, dmae->comp_addr_lo,
      dmae->comp_val);
  break;
 case DMAE_CMD_DST_GRC:
  if (src_type == DMAE_CMD_SRC_PCI)
   DP(msglvl, "DMAE: opcode 0x%08x\n"
      "src [%x:%08x], len [%d*4], dst_addr [%08x]\n"
      "comp_addr [%x:%08x], comp_val 0x%08x\n",
      dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
      dmae->len, dmae->dst_addr_lo >> 2,
      dmae->comp_addr_hi, dmae->comp_addr_lo,
      dmae->comp_val);
  else
   DP(msglvl, "DMAE: opcode 0x%08x\n"
      "src [%08x], len [%d*4], dst [%08x]\n"
      "comp_addr [%x:%08x], comp_val 0x%08x\n",
      dmae->opcode, dmae->src_addr_lo >> 2,
      dmae->len, dmae->dst_addr_lo >> 2,
      dmae->comp_addr_hi, dmae->comp_addr_lo,
      dmae->comp_val);
  break;
 default:
  if (src_type == DMAE_CMD_SRC_PCI)
   DP(msglvl, "DMAE: opcode 0x%08x\n"
      "src_addr [%x:%08x] len [%d * 4] dst_addr [none]\n"
      "comp_addr [%x:%08x] comp_val 0x%08x\n",
      dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
      dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
      dmae->comp_val);
  else
   DP(msglvl, "DMAE: opcode 0x%08x\n"
      "src_addr [%08x] len [%d * 4] dst_addr [none]\n"
      "comp_addr [%x:%08x] comp_val 0x%08x\n",
      dmae->opcode, dmae->src_addr_lo >> 2,
      dmae->len, dmae->comp_addr_hi, dmae->comp_addr_lo,
      dmae->comp_val);
  break;
 }

 for (i = 0; i < (sizeof(struct dmae_command)/4); i++)
  DP(msglvl, "DMAE RAW [%02d]: 0x%08x\n",
     i, *(((u32 *)dmae) + i));
}

/* copy command into DMAE command memory and set DMAE command go */
void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx)
{
 u32 cmd_offset;
 int i;

 cmd_offset = (DMAE_REG_CMD_MEM + sizeof(struct dmae_command) * idx);
 for (i = 0; i < (sizeof(struct dmae_command)/4); i++) {
  REG_WR(bp, cmd_offset + i*4, *(((u32 *)dmae) + i));
 }
 REG_WR(bp, dmae_reg_go_c[idx], 1);
}

u32 bnx2x_dmae_opcode_add_comp(u32 opcode, u8 comp_type)
{
 return opcode | ((comp_type << DMAE_COMMAND_C_DST_SHIFT) |
      DMAE_CMD_C_ENABLE);
}

u32 bnx2x_dmae_opcode_clr_src_reset(u32 opcode)
{
 return opcode & ~DMAE_CMD_SRC_RESET;
}

u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
        bool with_comp, u8 comp_type)
{
 u32 opcode = 0;

 opcode |= ((src_type << DMAE_COMMAND_SRC_SHIFT) |
     (dst_type << DMAE_COMMAND_DST_SHIFT));

 opcode |= (DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET);

 opcode |= (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0);
 opcode |= ((BP_VN(bp) << DMAE_CMD_E1HVN_SHIFT) |
     (BP_VN(bp) << DMAE_COMMAND_DST_VN_SHIFT));
 opcode |= (DMAE_COM_SET_ERR << DMAE_COMMAND_ERR_POLICY_SHIFT);

#ifdef __BIG_ENDIAN
 opcode |= DMAE_CMD_ENDIANITY_B_DW_SWAP;
#else
 opcode |= DMAE_CMD_ENDIANITY_DW_SWAP;
#endif
 if (with_comp)
  opcode = bnx2x_dmae_opcode_add_comp(opcode, comp_type);
 return opcode;
}

void bnx2x_prep_dmae_with_comp(struct bnx2x *bp,
          struct dmae_command *dmae,
          u8 src_type, u8 dst_type)
{
 memset(dmae, 0, sizeof(struct dmae_command));

 /* set the opcode */
 dmae->opcode = bnx2x_dmae_opcode(bp, src_type, dst_type,
      true, DMAE_COMP_PCI);

 /* fill in the completion parameters */
 dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
 dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
 dmae->comp_val = DMAE_COMP_VAL;
}

/* issue a dmae command over the init-channel and wait for completion */
int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, struct dmae_command *dmae,
          u32 *comp)
{
 int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 4000;
 int rc = 0;

 bnx2x_dp_dmae(bp, dmae, BNX2X_MSG_DMAE);

 /* Lock the dmae channel. Disable BHs to prevent a dead-lock
 * as long as this code is called both from syscall context and
 * from ndo_set_rx_mode() flow that may be called from BH.
 */


 spin_lock_bh(&bp->dmae_lock);

 /* reset completion */
 *comp = 0;

 /* post the command on the channel used for initializations */
 bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp));

 /* wait for completion */
 udelay(5);
 while ((*comp & ~DMAE_PCI_ERR_FLAG) != DMAE_COMP_VAL) {

  if (!cnt ||
      (bp->recovery_state != BNX2X_RECOVERY_DONE &&
       bp->recovery_state != BNX2X_RECOVERY_NIC_LOADING)) {
   BNX2X_ERR("DMAE timeout!\n");
   rc = DMAE_TIMEOUT;
   goto unlock;
  }
  cnt--;
  udelay(50);
 }
 if (*comp & DMAE_PCI_ERR_FLAG) {
  BNX2X_ERR("DMAE PCI error!\n");
  rc = DMAE_PCI_ERROR;
 }

unlock:

 spin_unlock_bh(&bp->dmae_lock);

 return rc;
}

void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
        u32 len32)
{
 int rc;
 struct dmae_command dmae;

 if (!bp->dmae_ready) {
  u32 *data = bnx2x_sp(bp, wb_data[0]);

  if (CHIP_IS_E1(bp))
   bnx2x_init_ind_wr(bp, dst_addr, data, len32);
  else
   bnx2x_init_str_wr(bp, dst_addr, data, len32);
  return;
 }

 /* set opcode and fixed command fields */
 bnx2x_prep_dmae_with_comp(bp, &dmae, DMAE_SRC_PCI, DMAE_DST_GRC);

 /* fill in addresses and len */
 dmae.src_addr_lo = U64_LO(dma_addr);
 dmae.src_addr_hi = U64_HI(dma_addr);
 dmae.dst_addr_lo = dst_addr >> 2;
 dmae.dst_addr_hi = 0;
 dmae.len = len32;

 /* issue the command and wait for completion */
 rc = bnx2x_issue_dmae_with_comp(bp, &dmae, bnx2x_sp(bp, wb_comp));
 if (rc) {
  BNX2X_ERR("DMAE returned failure %d\n", rc);
#ifdef BNX2X_STOP_ON_ERROR
  bnx2x_panic();
#endif
 }
}

void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
{
 int rc;
 struct dmae_command dmae;

 if (!bp->dmae_ready) {
  u32 *data = bnx2x_sp(bp, wb_data[0]);
  int i;

  if (CHIP_IS_E1(bp))
   for (i = 0; i < len32; i++)
    data[i] = bnx2x_reg_rd_ind(bp, src_addr + i*4);
  else
   for (i = 0; i < len32; i++)
    data[i] = REG_RD(bp, src_addr + i*4);

  return;
 }

 /* set opcode and fixed command fields */
 bnx2x_prep_dmae_with_comp(bp, &dmae, DMAE_SRC_GRC, DMAE_DST_PCI);

 /* fill in addresses and len */
 dmae.src_addr_lo = src_addr >> 2;
 dmae.src_addr_hi = 0;
 dmae.dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data));
 dmae.dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data));
 dmae.len = len32;

 /* issue the command and wait for completion */
 rc = bnx2x_issue_dmae_with_comp(bp, &dmae, bnx2x_sp(bp, wb_comp));
 if (rc) {
  BNX2X_ERR("DMAE returned failure %d\n", rc);
#ifdef BNX2X_STOP_ON_ERROR
  bnx2x_panic();
#endif
 }
}

static void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
          u32 addr, u32 len)
{
 int dmae_wr_max = DMAE_LEN32_WR_MAX(bp);
 int offset = 0;

 while (len > dmae_wr_max) {
  bnx2x_write_dmae(bp, phys_addr + offset,
     addr + offset, dmae_wr_max);
  offset += dmae_wr_max * 4;
  len -= dmae_wr_max;
 }

 bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len);
}

enum storms {
    XSTORM,
    TSTORM,
    CSTORM,
    USTORM,
    MAX_STORMS
};

#define STORMS_NUM 4
#define REGS_IN_ENTRY 4

static inline int bnx2x_get_assert_list_entry(struct bnx2x *bp,
           enum storms storm,
           int entry)
{
 switch (storm) {
 case XSTORM:
  return XSTORM_ASSERT_LIST_OFFSET(entry);
 case TSTORM:
  return TSTORM_ASSERT_LIST_OFFSET(entry);
 case CSTORM:
  return CSTORM_ASSERT_LIST_OFFSET(entry);
 case USTORM:
  return USTORM_ASSERT_LIST_OFFSET(entry);
 case MAX_STORMS:
 default:
  BNX2X_ERR("unknown storm\n");
 }
 return -EINVAL;
}

static int bnx2x_mc_assert(struct bnx2x *bp)
{
 char last_idx;
 int i, j, rc = 0;
 enum storms storm;
 u32 regs[REGS_IN_ENTRY];
 u32 bar_storm_intmem[STORMS_NUM] = {
  BAR_XSTRORM_INTMEM,
  BAR_TSTRORM_INTMEM,
  BAR_CSTRORM_INTMEM,
  BAR_USTRORM_INTMEM
 };
 u32 storm_assert_list_index[STORMS_NUM] = {
  XSTORM_ASSERT_LIST_INDEX_OFFSET,
  TSTORM_ASSERT_LIST_INDEX_OFFSET,
  CSTORM_ASSERT_LIST_INDEX_OFFSET,
  USTORM_ASSERT_LIST_INDEX_OFFSET
 };
 char *storms_string[STORMS_NUM] = {
  "XSTORM",
  "TSTORM",
  "CSTORM",
  "USTORM"
 };

 for (storm = XSTORM; storm < MAX_STORMS; storm++) {
  last_idx = REG_RD8(bp, bar_storm_intmem[storm] +
       storm_assert_list_index[storm]);
  if (last_idx)
   BNX2X_ERR("%s_ASSERT_LIST_INDEX 0x%x\n",
      storms_string[storm], last_idx);

  /* print the asserts */
  for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) {
   /* read a single assert entry */
   for (j = 0; j < REGS_IN_ENTRY; j++)
    regs[j] = REG_RD(bp, bar_storm_intmem[storm] +
       bnx2x_get_assert_list_entry(bp,
              storm,
              i) +
       sizeof(u32) * j);

   /* log entry if it contains a valid assert */
   if (regs[0] != COMMON_ASM_INVALID_ASSERT_OPCODE) {
    BNX2X_ERR("%s_ASSERT_INDEX 0x%x = 0x%08x 0x%08x 0x%08x 0x%08x\n",
       storms_string[storm], i, regs[3],
       regs[2], regs[1], regs[0]);
    rc++;
   } else {
    break;
   }
  }
 }

 BNX2X_ERR("Chip Revision: %s, FW Version: %d_%d_%d\n",
    CHIP_IS_E1(bp) ? "everest1" :
    CHIP_IS_E1H(bp) ? "everest1h" :
    CHIP_IS_E2(bp) ? "everest2" : "everest3",
    bp->fw_major, bp->fw_minor, bp->fw_rev);

 return rc;
}

#define MCPR_TRACE_BUFFER_SIZE (0x800)
#define SCRATCH_BUFFER_SIZE(bp) \
 (CHIP_IS_E1(bp) ? 0x10000 : (CHIP_IS_E1H(bp) ? 0x20000 : 0x28000))

void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl)
{
 u32 addr, val;
 u32 mark, offset;
 __be32 data[9];
 int word;
 u32 trace_shmem_base;
 if (BP_NOMCP(bp)) {
  BNX2X_ERR("NO MCP - can not dump\n");
  return;
 }
 netdev_printk(lvl, bp->dev, "bc %d.%d.%d\n",
  (bp->common.bc_ver & 0xff0000) >> 16,
  (bp->common.bc_ver & 0xff00) >> 8,
  (bp->common.bc_ver & 0xff));

 if (pci_channel_offline(bp->pdev)) {
  BNX2X_ERR("Cannot dump MCP info while in PCI error\n");
  return;
 }

 val = REG_RD(bp, MCP_REG_MCPR_CPU_PROGRAM_COUNTER);
 if (val == REG_RD(bp, MCP_REG_MCPR_CPU_PROGRAM_COUNTER))
  BNX2X_ERR("%s" "MCP PC at 0x%x\n", lvl, val);

 if (BP_PATH(bp) == 0)
  trace_shmem_base = bp->common.shmem_base;
 else
  trace_shmem_base = SHMEM2_RD(bp, other_shmem_base_addr);

 /* sanity */
 if (trace_shmem_base < MCPR_SCRATCH_BASE(bp) + MCPR_TRACE_BUFFER_SIZE ||
     trace_shmem_base >= MCPR_SCRATCH_BASE(bp) +
    SCRATCH_BUFFER_SIZE(bp)) {
  BNX2X_ERR("Unable to dump trace buffer (mark %x)\n",
     trace_shmem_base);
  return;
 }

 addr = trace_shmem_base - MCPR_TRACE_BUFFER_SIZE;

 /* validate TRCB signature */
 mark = REG_RD(bp, addr);
 if (mark != MFW_TRACE_SIGNATURE) {
  BNX2X_ERR("Trace buffer signature is missing.");
  return ;
 }

 /* read cyclic buffer pointer */
 addr += 4;
 mark = REG_RD(bp, addr);
 mark = MCPR_SCRATCH_BASE(bp) + ((mark + 0x3) & ~0x3) - 0x08000000;
 if (mark >= trace_shmem_base || mark < addr + 4) {
  BNX2X_ERR("Mark doesn't fall inside Trace Buffer\n");
  return;
 }
 printk("%s" "begin fw dump (mark 0x%x)\n", lvl, mark);

 printk("%s", lvl);

 /* dump buffer after the mark */
 for (offset = mark; offset < trace_shmem_base; offset += 0x8*4) {
  for (word = 0; word < 8; word++)
   data[word] = htonl(REG_RD(bp, offset + 4*word));
  data[8] = 0x0;
  pr_cont("%s", (char *)data);
 }

 /* dump buffer before the mark */
 for (offset = addr + 4; offset <= mark; offset += 0x8*4) {
  for (word = 0; word < 8; word++)
   data[word] = htonl(REG_RD(bp, offset + 4*word));
  data[8] = 0x0;
  pr_cont("%s", (char *)data);
 }
 printk("%s" "end of fw dump\n", lvl);
}

static void bnx2x_fw_dump(struct bnx2x *bp)
{
 bnx2x_fw_dump_lvl(bp, KERN_ERR);
}

static void bnx2x_hc_int_disable(struct bnx2x *bp)
{
 int port = BP_PORT(bp);
 u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
 u32 val = REG_RD(bp, addr);

 /* in E1 we must use only PCI configuration space to disable
 * MSI/MSIX capability
 * It's forbidden to disable IGU_PF_CONF_MSI_MSIX_EN in HC block
 */

 if (CHIP_IS_E1(bp)) {
  /* Since IGU_PF_CONF_MSI_MSIX_EN still always on
 * Use mask register to prevent from HC sending interrupts
 * after we exit the function
 */

  REG_WR(bp, HC_REG_INT_MASK + port*4, 0);

  val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
    HC_CONFIG_0_REG_INT_LINE_EN_0 |
    HC_CONFIG_0_REG_ATTN_BIT_EN_0);
 } else
  val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
    HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
    HC_CONFIG_0_REG_INT_LINE_EN_0 |
    HC_CONFIG_0_REG_ATTN_BIT_EN_0);

 DP(NETIF_MSG_IFDOWN,
    "write %x to HC %d (addr 0x%x)\n",
    val, port, addr);

 REG_WR(bp, addr, val);
 if (REG_RD(bp, addr) != val)
  BNX2X_ERR("BUG! Proper val not read from IGU!\n");
}

static void bnx2x_igu_int_disable(struct bnx2x *bp)
{
 u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);

 val &= ~(IGU_PF_CONF_MSI_MSIX_EN |
   IGU_PF_CONF_INT_LINE_EN |
   IGU_PF_CONF_ATTN_BIT_EN);

 DP(NETIF_MSG_IFDOWN, "write %x to IGU\n", val);

 REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
 if (REG_RD(bp, IGU_REG_PF_CONFIGURATION) != val)
  BNX2X_ERR("BUG! Proper val not read from IGU!\n");
}

static void bnx2x_int_disable(struct bnx2x *bp)
{
 if (bp->common.int_block == INT_BLOCK_HC)
  bnx2x_hc_int_disable(bp);
 else
  bnx2x_igu_int_disable(bp);
}

void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
{
 int i;
 u16 j;
 struct hc_sp_status_block_data sp_sb_data;
 int func = BP_FUNC(bp);
#ifdef BNX2X_STOP_ON_ERROR
 u16 start = 0, end = 0;
 u8 cos;
#endif
 if (IS_PF(bp) && disable_int)
  bnx2x_int_disable(bp);

 bp->stats_state = STATS_STATE_DISABLED;
 bp->eth_stats.unrecoverable_error++;
 DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");

 BNX2X_ERR("begin crash dump -----------------\n");

 /* Indices */
 /* Common */
 if (IS_PF(bp)) {
  struct host_sp_status_block *def_sb = bp->def_status_blk;
  int data_size, cstorm_offset;

  BNX2X_ERR("def_idx(0x%x) def_att_idx(0x%x) attn_state(0x%x) spq_prod_idx(0x%x) next_stats_cnt(0x%x)\n",
     bp->def_idx, bp->def_att_idx, bp->attn_state,
     bp->spq_prod_idx, bp->stats_counter);
  BNX2X_ERR("DSB: attn bits(0x%x) ack(0x%x) id(0x%x) idx(0x%x)\n",
     def_sb->atten_status_block.attn_bits,
     def_sb->atten_status_block.attn_bits_ack,
     def_sb->atten_status_block.status_block_id,
     def_sb->atten_status_block.attn_bits_index);
  BNX2X_ERR(" def (");
  for (i = 0; i < HC_SP_SB_MAX_INDICES; i++)
   pr_cont("0x%x%s",
    def_sb->sp_sb.index_values[i],
    (i == HC_SP_SB_MAX_INDICES - 1) ? ") " : " ");

  data_size = sizeof(struct hc_sp_status_block_data) /
       sizeof(u32);
  cstorm_offset = CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func);
  for (i = 0; i < data_size; i++)
   *((u32 *)&sp_sb_data + i) =
    REG_RD(bp, BAR_CSTRORM_INTMEM + cstorm_offset +
        i * sizeof(u32));

  pr_cont("igu_sb_id(0x%x) igu_seg_id(0x%x) pf_id(0x%x) vnic_id(0x%x) vf_id(0x%x) vf_valid (0x%x) state(0x%x)\n",
   sp_sb_data.igu_sb_id,
   sp_sb_data.igu_seg_id,
   sp_sb_data.p_func.pf_id,
   sp_sb_data.p_func.vnic_id,
   sp_sb_data.p_func.vf_id,
   sp_sb_data.p_func.vf_valid,
   sp_sb_data.state);
 }

 for_each_eth_queue(bp, i) {
  struct bnx2x_fastpath *fp = &bp->fp[i];
  int loop;
  struct hc_status_block_data_e2 sb_data_e2;
  struct hc_status_block_data_e1x sb_data_e1x;
  struct hc_status_block_sm  *hc_sm_p =
   CHIP_IS_E1x(bp) ?
   sb_data_e1x.common.state_machine :
   sb_data_e2.common.state_machine;
  struct hc_index_data *hc_index_p =
   CHIP_IS_E1x(bp) ?
   sb_data_e1x.index_data :
   sb_data_e2.index_data;
  u8 data_size, cos;
  u32 *sb_data_p;
  struct bnx2x_fp_txdata txdata;

  if (!bp->fp)
   break;

  if (!fp->rx_cons_sb)
   continue;

  /* Rx */
  BNX2X_ERR("fp%d: rx_bd_prod(0x%x) rx_bd_cons(0x%x) rx_comp_prod(0x%x) rx_comp_cons(0x%x) *rx_cons_sb(0x%x)\n",
     i, fp->rx_bd_prod, fp->rx_bd_cons,
     fp->rx_comp_prod,
     fp->rx_comp_cons, le16_to_cpu(*fp->rx_cons_sb));
  BNX2X_ERR(" rx_sge_prod(0x%x) last_max_sge(0x%x) fp_hc_idx(0x%x)\n",
     fp->rx_sge_prod, fp->last_max_sge,
     le16_to_cpu(fp->fp_hc_idx));

  /* Tx */
  for_each_cos_in_tx_queue(fp, cos)
  {
   if (!fp->txdata_ptr[cos])
    break;

   txdata = *fp->txdata_ptr[cos];

   if (!txdata.tx_cons_sb)
    continue;

   BNX2X_ERR("fp%d: tx_pkt_prod(0x%x) tx_pkt_cons(0x%x) tx_bd_prod(0x%x) tx_bd_cons(0x%x) *tx_cons_sb(0x%x)\n",
      i, txdata.tx_pkt_prod,
      txdata.tx_pkt_cons, txdata.tx_bd_prod,
      txdata.tx_bd_cons,
      le16_to_cpu(*txdata.tx_cons_sb));
  }

  loop = CHIP_IS_E1x(bp) ?
   HC_SB_MAX_INDICES_E1X : HC_SB_MAX_INDICES_E2;

  /* host sb data */

  if (IS_FCOE_FP(fp))
   continue;

  BNX2X_ERR(" run indexes (");
  for (j = 0; j < HC_SB_MAX_SM; j++)
   pr_cont("0x%x%s",
          fp->sb_running_index[j],
          (j == HC_SB_MAX_SM - 1) ? ")" : " ");

  BNX2X_ERR(" indexes (");
  for (j = 0; j < loop; j++)
   pr_cont("0x%x%s",
          fp->sb_index_values[j],
          (j == loop - 1) ? ")" : " ");

  /* VF cannot access FW refelection for status block */
  if (IS_VF(bp))
   continue;

  /* fw sb data */
  data_size = CHIP_IS_E1x(bp) ?
   sizeof(struct hc_status_block_data_e1x) :
   sizeof(struct hc_status_block_data_e2);
  data_size /= sizeof(u32);
  sb_data_p = CHIP_IS_E1x(bp) ?
   (u32 *)&sb_data_e1x :
   (u32 *)&sb_data_e2;
  /* copy sb data in here */
  for (j = 0; j < data_size; j++)
   *(sb_data_p + j) = REG_RD(bp, BAR_CSTRORM_INTMEM +
    CSTORM_STATUS_BLOCK_DATA_OFFSET(fp->fw_sb_id) +
    j * sizeof(u32));

  if (!CHIP_IS_E1x(bp)) {
   pr_cont("pf_id(0x%x) vf_id(0x%x) vf_valid(0x%x) vnic_id(0x%x) same_igu_sb_1b(0x%x) state(0x%x)\n",
    sb_data_e2.common.p_func.pf_id,
    sb_data_e2.common.p_func.vf_id,
    sb_data_e2.common.p_func.vf_valid,
    sb_data_e2.common.p_func.vnic_id,
    sb_data_e2.common.same_igu_sb_1b,
    sb_data_e2.common.state);
  } else {
   pr_cont("pf_id(0x%x) vf_id(0x%x) vf_valid(0x%x) vnic_id(0x%x) same_igu_sb_1b(0x%x) state(0x%x)\n",
    sb_data_e1x.common.p_func.pf_id,
    sb_data_e1x.common.p_func.vf_id,
    sb_data_e1x.common.p_func.vf_valid,
    sb_data_e1x.common.p_func.vnic_id,
    sb_data_e1x.common.same_igu_sb_1b,
    sb_data_e1x.common.state);
  }

  /* SB_SMs data */
  for (j = 0; j < HC_SB_MAX_SM; j++) {
   pr_cont("SM[%d] __flags (0x%x) igu_sb_id (0x%x) igu_seg_id(0x%x) time_to_expire (0x%x) timer_value(0x%x)\n",
    j, hc_sm_p[j].__flags,
    hc_sm_p[j].igu_sb_id,
    hc_sm_p[j].igu_seg_id,
    hc_sm_p[j].time_to_expire,
    hc_sm_p[j].timer_value);
  }

  /* Indices data */
  for (j = 0; j < loop; j++) {
   pr_cont("INDEX[%d] flags (0x%x) timeout (0x%x)\n", j,
          hc_index_p[j].flags,
          hc_index_p[j].timeout);
  }
 }

#ifdef BNX2X_STOP_ON_ERROR
 if (IS_PF(bp)) {
  /* event queue */
  BNX2X_ERR("eq cons %x prod %x\n", bp->eq_cons, bp->eq_prod);
  for (i = 0; i < NUM_EQ_DESC; i++) {
   u32 *data = (u32 *)&bp->eq_ring[i].message.data;

   BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n",
      i, bp->eq_ring[i].message.opcode,
      bp->eq_ring[i].message.error);
   BNX2X_ERR("data: %x %x %x\n",
      data[0], data[1], data[2]);
  }
 }

 /* Rings */
 /* Rx */
 for_each_valid_rx_queue(bp, i) {
  struct bnx2x_fastpath *fp = &bp->fp[i];

  if (!bp->fp)
   break;

  if (!fp->rx_cons_sb)
   continue;

  start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
  end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503);
  for (j = start; j != end; j = RX_BD(j + 1)) {
   u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j];
   struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j];

   BNX2X_ERR("fp%d: rx_bd[%x]=[%x:%x] sw_bd=[%p]\n",
      i, j, rx_bd[1], rx_bd[0], sw_bd->data);
  }

  start = RX_SGE(fp->rx_sge_prod);
  end = RX_SGE(fp->last_max_sge);
  for (j = start; j != end; j = RX_SGE(j + 1)) {
   u32 *rx_sge = (u32 *)&fp->rx_sge_ring[j];
   struct sw_rx_page *sw_page = &fp->rx_page_ring[j];

   BNX2X_ERR("fp%d: rx_sge[%x]=[%x:%x] sw_page=[%p]\n",
      i, j, rx_sge[1], rx_sge[0], sw_page->page);
  }

  start = RCQ_BD(fp->rx_comp_cons - 10);
  end = RCQ_BD(fp->rx_comp_cons + 503);
  for (j = start; j != end; j = RCQ_BD(j + 1)) {
   u32 *cqe = (u32 *)&fp->rx_comp_ring[j];

   BNX2X_ERR("fp%d: cqe[%x]=[%x:%x:%x:%x]\n",
      i, j, cqe[0], cqe[1], cqe[2], cqe[3]);
  }
 }

 /* Tx */
 for_each_valid_tx_queue(bp, i) {
  struct bnx2x_fastpath *fp = &bp->fp[i];

  if (!bp->fp)
   break;

  for_each_cos_in_tx_queue(fp, cos) {
   struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];

   if (!fp->txdata_ptr[cos])
    break;

   if (!txdata->tx_cons_sb)
    continue;

   start = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) - 10);
   end = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) + 245);
   for (j = start; j != end; j = TX_BD(j + 1)) {
    struct sw_tx_bd *sw_bd =
     &txdata->tx_buf_ring[j];

    BNX2X_ERR("fp%d: txdata %d, packet[%x]=[%p,%x]\n",
       i, cos, j, sw_bd->skb,
       sw_bd->first_bd);
   }

   start = TX_BD(txdata->tx_bd_cons - 10);
   end = TX_BD(txdata->tx_bd_cons + 254);
   for (j = start; j != end; j = TX_BD(j + 1)) {
    u32 *tx_bd = (u32 *)&txdata->tx_desc_ring[j];

    BNX2X_ERR("fp%d: txdata %d, tx_bd[%x]=[%x:%x:%x:%x]\n",
       i, cos, j, tx_bd[0], tx_bd[1],
       tx_bd[2], tx_bd[3]);
   }
  }
 }
#endif
 if (IS_PF(bp)) {
  int tmp_msg_en = bp->msg_enable;

  bnx2x_fw_dump(bp);
  bp->msg_enable |= NETIF_MSG_HW;
  BNX2X_ERR("Idle check (1st round) ----------\n");
  bnx2x_idle_chk(bp);
  BNX2X_ERR("Idle check (2nd round) ----------\n");
  bnx2x_idle_chk(bp);
  bp->msg_enable = tmp_msg_en;
  bnx2x_mc_assert(bp);
 }

 BNX2X_ERR("end crash dump -----------------\n");
}

/*
 * FLR Support for E2
 *
 * bnx2x_pf_flr_clnup() is called during nic_load in the per function HW
 * initialization.
 */

#define FLR_WAIT_USEC  10000 /* 10 milliseconds */
#define FLR_WAIT_INTERVAL 50 /* usec */
#define FLR_POLL_CNT  (FLR_WAIT_USEC/FLR_WAIT_INTERVAL) /* 200 */

struct pbf_pN_buf_regs {
 int pN;
 u32 init_crd;
 u32 crd;
 u32 crd_freed;
};

struct pbf_pN_cmd_regs {
 int pN;
 u32 lines_occup;
 u32 lines_freed;
};

static void bnx2x_pbf_pN_buf_flushed(struct bnx2x *bp,
         struct pbf_pN_buf_regs *regs,
         u32 poll_count)
{
 u32 init_crd, crd, crd_start, crd_freed, crd_freed_start;
 u32 cur_cnt = poll_count;

 crd_freed = crd_freed_start = REG_RD(bp, regs->crd_freed);
 crd = crd_start = REG_RD(bp, regs->crd);
 init_crd = REG_RD(bp, regs->init_crd);

 DP(BNX2X_MSG_SP, "INIT CREDIT[%d] : %x\n", regs->pN, init_crd);
 DP(BNX2X_MSG_SP, "CREDIT[%d] : s:%x\n", regs->pN, crd);
 DP(BNX2X_MSG_SP, "CREDIT_FREED[%d]: s:%x\n", regs->pN, crd_freed);

 while ((crd != init_crd) && ((u32)SUB_S32(crd_freed, crd_freed_start) <
        (init_crd - crd_start))) {
  if (cur_cnt--) {
   udelay(FLR_WAIT_INTERVAL);
   crd = REG_RD(bp, regs->crd);
   crd_freed = REG_RD(bp, regs->crd_freed);
  } else {
   DP(BNX2X_MSG_SP, "PBF tx buffer[%d] timed out\n",
      regs->pN);
   DP(BNX2X_MSG_SP, "CREDIT[%d] : c:%x\n",
      regs->pN, crd);
   DP(BNX2X_MSG_SP, "CREDIT_FREED[%d]: c:%x\n",
      regs->pN, crd_freed);
   break;
  }
 }
 DP(BNX2X_MSG_SP, "Waited %d*%d usec for PBF tx buffer[%d]\n",
    poll_count-cur_cnt, FLR_WAIT_INTERVAL, regs->pN);
}

static void bnx2x_pbf_pN_cmd_flushed(struct bnx2x *bp,
         struct pbf_pN_cmd_regs *regs,
         u32 poll_count)
{
 u32 occup, to_free, freed, freed_start;
 u32 cur_cnt = poll_count;

 occup = to_free = REG_RD(bp, regs->lines_occup);
 freed = freed_start = REG_RD(bp, regs->lines_freed);

 DP(BNX2X_MSG_SP, "OCCUPANCY[%d] : s:%x\n", regs->pN, occup);
 DP(BNX2X_MSG_SP, "LINES_FREED[%d] : s:%x\n", regs->pN, freed);

 while (occup && ((u32)SUB_S32(freed, freed_start) < to_free)) {
  if (cur_cnt--) {
   udelay(FLR_WAIT_INTERVAL);
   occup = REG_RD(bp, regs->lines_occup);
   freed = REG_RD(bp, regs->lines_freed);
  } else {
   DP(BNX2X_MSG_SP, "PBF cmd queue[%d] timed out\n",
      regs->pN);
   DP(BNX2X_MSG_SP, "OCCUPANCY[%d] : s:%x\n",
      regs->pN, occup);
   DP(BNX2X_MSG_SP, "LINES_FREED[%d] : s:%x\n",
      regs->pN, freed);
   break;
  }
 }
 DP(BNX2X_MSG_SP, "Waited %d*%d usec for PBF cmd queue[%d]\n",
    poll_count-cur_cnt, FLR_WAIT_INTERVAL, regs->pN);
}

static u32 bnx2x_flr_clnup_reg_poll(struct bnx2x *bp, u32 reg,
        u32 expected, u32 poll_count)
{
 u32 cur_cnt = poll_count;
 u32 val;

 while ((val = REG_RD(bp, reg)) != expected && cur_cnt--)
  udelay(FLR_WAIT_INTERVAL);

 return val;
}

int bnx2x_flr_clnup_poll_hw_counter(struct bnx2x *bp, u32 reg,
        char *msg, u32 poll_cnt)
{
 u32 val = bnx2x_flr_clnup_reg_poll(bp, reg, 0, poll_cnt);
 if (val != 0) {
  BNX2X_ERR("%s usage count=%d\n", msg, val);
  return 1;
 }
 return 0;
}

/* Common routines with VF FLR cleanup */
u32 bnx2x_flr_clnup_poll_count(struct bnx2x *bp)
{
 /* adjust polling timeout */
 if (CHIP_REV_IS_EMUL(bp))
  return FLR_POLL_CNT * 2000;

 if (CHIP_REV_IS_FPGA(bp))
  return FLR_POLL_CNT * 120;

 return FLR_POLL_CNT;
}

void bnx2x_tx_hw_flushed(struct bnx2x *bp, u32 poll_count)
{
 struct pbf_pN_cmd_regs cmd_regs[] = {
  {0, (CHIP_IS_E3B0(bp)) ?
   PBF_REG_TQ_OCCUPANCY_Q0 :
   PBF_REG_P0_TQ_OCCUPANCY,
      (CHIP_IS_E3B0(bp)) ?
   PBF_REG_TQ_LINES_FREED_CNT_Q0 :
   PBF_REG_P0_TQ_LINES_FREED_CNT},
  {1, (CHIP_IS_E3B0(bp)) ?
   PBF_REG_TQ_OCCUPANCY_Q1 :
   PBF_REG_P1_TQ_OCCUPANCY,
      (CHIP_IS_E3B0(bp)) ?
   PBF_REG_TQ_LINES_FREED_CNT_Q1 :
   PBF_REG_P1_TQ_LINES_FREED_CNT},
  {4, (CHIP_IS_E3B0(bp)) ?
   PBF_REG_TQ_OCCUPANCY_LB_Q :
   PBF_REG_P4_TQ_OCCUPANCY,
      (CHIP_IS_E3B0(bp)) ?
   PBF_REG_TQ_LINES_FREED_CNT_LB_Q :
   PBF_REG_P4_TQ_LINES_FREED_CNT}
 };

 struct pbf_pN_buf_regs buf_regs[] = {
  {0, (CHIP_IS_E3B0(bp)) ?
   PBF_REG_INIT_CRD_Q0 :
   PBF_REG_P0_INIT_CRD ,
      (CHIP_IS_E3B0(bp)) ?
   PBF_REG_CREDIT_Q0 :
   PBF_REG_P0_CREDIT,
      (CHIP_IS_E3B0(bp)) ?
   PBF_REG_INTERNAL_CRD_FREED_CNT_Q0 :
   PBF_REG_P0_INTERNAL_CRD_FREED_CNT},
  {1, (CHIP_IS_E3B0(bp)) ?
   PBF_REG_INIT_CRD_Q1 :
   PBF_REG_P1_INIT_CRD,
      (CHIP_IS_E3B0(bp)) ?
   PBF_REG_CREDIT_Q1 :
   PBF_REG_P1_CREDIT,
      (CHIP_IS_E3B0(bp)) ?
   PBF_REG_INTERNAL_CRD_FREED_CNT_Q1 :
   PBF_REG_P1_INTERNAL_CRD_FREED_CNT},
  {4, (CHIP_IS_E3B0(bp)) ?
   PBF_REG_INIT_CRD_LB_Q :
   PBF_REG_P4_INIT_CRD,
      (CHIP_IS_E3B0(bp)) ?
   PBF_REG_CREDIT_LB_Q :
   PBF_REG_P4_CREDIT,
      (CHIP_IS_E3B0(bp)) ?
   PBF_REG_INTERNAL_CRD_FREED_CNT_LB_Q :
   PBF_REG_P4_INTERNAL_CRD_FREED_CNT},
 };

 int i;

 /* Verify the command queues are flushed P0, P1, P4 */
 for (i = 0; i < ARRAY_SIZE(cmd_regs); i++)
  bnx2x_pbf_pN_cmd_flushed(bp, &cmd_regs[i], poll_count);

 /* Verify the transmission buffers are flushed P0, P1, P4 */
 for (i = 0; i < ARRAY_SIZE(buf_regs); i++)
  bnx2x_pbf_pN_buf_flushed(bp, &buf_regs[i], poll_count);
}

#define OP_GEN_PARAM(param) \
 (((param) << SDM_OP_GEN_COMP_PARAM_SHIFT) & SDM_OP_GEN_COMP_PARAM)

#define OP_GEN_TYPE(type) \
 (((type) << SDM_OP_GEN_COMP_TYPE_SHIFT) & SDM_OP_GEN_COMP_TYPE)

#define OP_GEN_AGG_VECT(index) \
 (((index) << SDM_OP_GEN_AGG_VECT_IDX_SHIFT) & SDM_OP_GEN_AGG_VECT_IDX)

int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, u32 poll_cnt)
{
 u32 op_gen_command = 0;
 u32 comp_addr = BAR_CSTRORM_INTMEM +
   CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(clnup_func);

 if (REG_RD(bp, comp_addr)) {
  BNX2X_ERR("Cleanup complete was not 0 before sending\n");
  return 1;
 }

 op_gen_command |= OP_GEN_PARAM(XSTORM_AGG_INT_FINAL_CLEANUP_INDEX);
 op_gen_command |= OP_GEN_TYPE(XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE);
 op_gen_command |= OP_GEN_AGG_VECT(clnup_func);
 op_gen_command |= 1 << SDM_OP_GEN_AGG_VECT_IDX_VALID_SHIFT;

 DP(BNX2X_MSG_SP, "sending FW Final cleanup\n");
 REG_WR(bp, XSDM_REG_OPERATION_GEN, op_gen_command);

 if (bnx2x_flr_clnup_reg_poll(bp, comp_addr, 1, poll_cnt) != 1) {
  BNX2X_ERR("FW final cleanup did not succeed\n");
  DP(BNX2X_MSG_SP, "At timeout completion address contained %x\n",
     (REG_RD(bp, comp_addr)));
  bnx2x_panic();
  return 1;
 }
 /* Zero completion for next FLR */
 REG_WR(bp, comp_addr, 0);

 return 0;
}

u8 bnx2x_is_pcie_pending(struct pci_dev *dev)
{
 u16 status;

 pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status);
 return status & PCI_EXP_DEVSTA_TRPND;
}

/* PF FLR specific routines
*/

static int bnx2x_poll_hw_usage_counters(struct bnx2x *bp, u32 poll_cnt)
{
 /* wait for CFC PF usage-counter to zero (includes all the VFs) */
 if (bnx2x_flr_clnup_poll_hw_counter(bp,
   CFC_REG_NUM_LCIDS_INSIDE_PF,
   "CFC PF usage counter timed out",
   poll_cnt))
  return 1;

 /* Wait for DQ PF usage-counter to zero (until DQ cleanup) */
 if (bnx2x_flr_clnup_poll_hw_counter(bp,
   DORQ_REG_PF_USAGE_CNT,
   "DQ PF usage counter timed out",
   poll_cnt))
  return 1;

 /* Wait for QM PF usage-counter to zero (until DQ cleanup) */
 if (bnx2x_flr_clnup_poll_hw_counter(bp,
   QM_REG_PF_USG_CNT_0 + 4*BP_FUNC(bp),
   "QM PF usage counter timed out",
   poll_cnt))
  return 1;

 /* Wait for Timer PF usage-counters to zero (until DQ cleanup) */
 if (bnx2x_flr_clnup_poll_hw_counter(bp,
   TM_REG_LIN0_VNIC_UC + 4*BP_PORT(bp),
   "Timers VNIC usage counter timed out",
   poll_cnt))
  return 1;
 if (bnx2x_flr_clnup_poll_hw_counter(bp,
   TM_REG_LIN0_NUM_SCANS + 4*BP_PORT(bp),
   "Timers NUM_SCANS usage counter timed out",
   poll_cnt))
  return 1;

 /* Wait DMAE PF usage counter to zero */
 if (bnx2x_flr_clnup_poll_hw_counter(bp,
   dmae_reg_go_c[INIT_DMAE_C(bp)],
   "DMAE command register timed out",
   poll_cnt))
  return 1;

 return 0;
}

static void bnx2x_hw_enable_status(struct bnx2x *bp)
{
 u32 val;

 val = REG_RD(bp, CFC_REG_WEAK_ENABLE_PF);
 DP(BNX2X_MSG_SP, "CFC_REG_WEAK_ENABLE_PF is 0x%x\n", val);

 val = REG_RD(bp, PBF_REG_DISABLE_PF);
 DP(BNX2X_MSG_SP, "PBF_REG_DISABLE_PF is 0x%x\n", val);

 val = REG_RD(bp, IGU_REG_PCI_PF_MSI_EN);
 DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSI_EN is 0x%x\n", val);

 val = REG_RD(bp, IGU_REG_PCI_PF_MSIX_EN);
 DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSIX_EN is 0x%x\n", val);

 val = REG_RD(bp, IGU_REG_PCI_PF_MSIX_FUNC_MASK);
 DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSIX_FUNC_MASK is 0x%x\n", val);

 val = REG_RD(bp, PGLUE_B_REG_SHADOW_BME_PF_7_0_CLR);
 DP(BNX2X_MSG_SP, "PGLUE_B_REG_SHADOW_BME_PF_7_0_CLR is 0x%x\n", val);

 val = REG_RD(bp, PGLUE_B_REG_FLR_REQUEST_PF_7_0_CLR);
 DP(BNX2X_MSG_SP, "PGLUE_B_REG_FLR_REQUEST_PF_7_0_CLR is 0x%x\n", val);

 val = REG_RD(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER);
 DP(BNX2X_MSG_SP, "PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER is 0x%x\n",
    val);
}

static int bnx2x_pf_flr_clnup(struct bnx2x *bp)
{
 u32 poll_cnt = bnx2x_flr_clnup_poll_count(bp);

 DP(BNX2X_MSG_SP, "Cleanup after FLR PF[%d]\n", BP_ABS_FUNC(bp));

 /* Re-enable PF target read access */
 REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1);

 /* Poll HW usage counters */
 DP(BNX2X_MSG_SP, "Polling usage counters\n");
 if (bnx2x_poll_hw_usage_counters(bp, poll_cnt))
  return -EBUSY;

 /* Zero the igu 'trailing edge' and 'leading edge' */

 /* Send the FW cleanup command */
 if (bnx2x_send_final_clnup(bp, (u8)BP_FUNC(bp), poll_cnt))
  return -EBUSY;

 /* ATC cleanup */

 /* Verify TX hw is flushed */
 bnx2x_tx_hw_flushed(bp, poll_cnt);

 /* Wait 100ms (not adjusted according to platform) */
 msleep(100);

 /* Verify no pending pci transactions */
 if (bnx2x_is_pcie_pending(bp->pdev))
  BNX2X_ERR("PCIE Transactions still pending\n");

 /* Debug */
 bnx2x_hw_enable_status(bp);

 /*
 * Master enable - Due to WB DMAE writes performed before this
 * register is re-initialized as part of the regular function init
 */

 REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, 1);

 return 0;
}

static void bnx2x_hc_int_enable(struct bnx2x *bp)
{
 int port = BP_PORT(bp);
 u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
 u32 val = REG_RD(bp, addr);
 bool msix = (bp->flags & USING_MSIX_FLAG) ? true : false;
 bool single_msix = (bp->flags & USING_SINGLE_MSIX_FLAG) ? true : false;
 bool msi = (bp->flags & USING_MSI_FLAG) ? true : false;

 if (msix) {
  val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
    HC_CONFIG_0_REG_INT_LINE_EN_0);
  val |= (HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
   HC_CONFIG_0_REG_ATTN_BIT_EN_0);
  if (single_msix)
   val |= HC_CONFIG_0_REG_SINGLE_ISR_EN_0;
 } else if (msi) {
  val &= ~HC_CONFIG_0_REG_INT_LINE_EN_0;
  val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
   HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
   HC_CONFIG_0_REG_ATTN_BIT_EN_0);
 } else {
  val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
   HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
   HC_CONFIG_0_REG_INT_LINE_EN_0 |
   HC_CONFIG_0_REG_ATTN_BIT_EN_0);

  if (!CHIP_IS_E1(bp)) {
   DP(NETIF_MSG_IFUP,
      "write %x to HC %d (addr 0x%x)\n", val, port, addr);

   REG_WR(bp, addr, val);

   val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0;
  }
 }

 if (CHIP_IS_E1(bp))
  REG_WR(bp, HC_REG_INT_MASK + port*4, 0x1FFFF);

 DP(NETIF_MSG_IFUP,
    "write %x to HC %d (addr 0x%x) mode %s\n", val, port, addr,
    (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));

 REG_WR(bp, addr, val);
 /*
 * Ensure that HC_CONFIG is written before leading/trailing edge config
 */

 barrier();

 if (!CHIP_IS_E1(bp)) {
  /* init leading/trailing edge */
  if (IS_MF(bp)) {
   val = (0xee0f | (1 << (BP_VN(bp) + 4)));
   if (bp->port.pmf)
    /* enable nig and gpio3 attention */
    val |= 0x1100;
  } else
   val = 0xffff;

  REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val);
  REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val);
 }
}

static void bnx2x_igu_int_enable(struct bnx2x *bp)
{
 u32 val;
 bool msix = (bp->flags & USING_MSIX_FLAG) ? true : false;
 bool single_msix = (bp->flags & USING_SINGLE_MSIX_FLAG) ? true : false;
 bool msi = (bp->flags & USING_MSI_FLAG) ? true : false;

 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION);

 if (msix) {
  val &= ~(IGU_PF_CONF_INT_LINE_EN |
    IGU_PF_CONF_SINGLE_ISR_EN);
  val |= (IGU_PF_CONF_MSI_MSIX_EN |
   IGU_PF_CONF_ATTN_BIT_EN);

  if (single_msix)
   val |= IGU_PF_CONF_SINGLE_ISR_EN;
 } else if (msi) {
  val &= ~IGU_PF_CONF_INT_LINE_EN;
  val |= (IGU_PF_CONF_MSI_MSIX_EN |
   IGU_PF_CONF_ATTN_BIT_EN |
   IGU_PF_CONF_SINGLE_ISR_EN);
 } else {
  val &= ~IGU_PF_CONF_MSI_MSIX_EN;
  val |= (IGU_PF_CONF_INT_LINE_EN |
   IGU_PF_CONF_ATTN_BIT_EN |
   IGU_PF_CONF_SINGLE_ISR_EN);
 }

 /* Clean previous status - need to configure igu prior to ack*/
 if ((!msix) || single_msix) {
  REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);
  bnx2x_ack_int(bp);
 }

 val |= IGU_PF_CONF_FUNC_EN;

 DP(NETIF_MSG_IFUP, "write 0x%x to IGU mode %s\n",
    val, (msix ? "MSI-X" : (msi ? "MSI" : "INTx")));

 REG_WR(bp, IGU_REG_PF_CONFIGURATION, val);

 if (val & IGU_PF_CONF_INT_LINE_EN)
  pci_intx(bp->pdev, true);

 barrier();

 /* init leading/trailing edge */
 if (IS_MF(bp)) {
  val = (0xee0f | (1 << (BP_VN(bp) + 4)));
  if (bp->port.pmf)
   /* enable nig and gpio3 attention */
   val |= 0x1100;
 } else
  val = 0xffff;

 REG_WR(bp, IGU_REG_TRAILING_EDGE_LATCH, val);
 REG_WR(bp, IGU_REG_LEADING_EDGE_LATCH, val);
}

void bnx2x_int_enable(struct bnx2x *bp)
{
 if (bp->common.int_block == INT_BLOCK_HC)
  bnx2x_hc_int_enable(bp);
 else
  bnx2x_igu_int_enable(bp);
}

void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
{
 int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
 int i, offset;

 if (disable_hw)
  /* prevent the HW from sending interrupts */
  bnx2x_int_disable(bp);

 /* make sure all ISRs are done */
 if (msix) {
  synchronize_irq(bp->msix_table[0].vector);
  offset = 1;
  if (CNIC_SUPPORT(bp))
   offset++;
  for_each_eth_queue(bp, i)
   synchronize_irq(bp->msix_table[offset++].vector);
 } else
  synchronize_irq(bp->pdev->irq);

 /* make sure sp_task is not running */
 cancel_delayed_work(&bp->sp_task);
 cancel_delayed_work(&bp->period_task);
 flush_workqueue(bnx2x_wq);
}

/* fast path */

/*
 * General service functions
 */


/* Return true if succeeded to acquire the lock */
static bool bnx2x_trylock_hw_lock(struct bnx2x *bp, u32 resource)
{
 u32 lock_status;
 u32 resource_bit = (1 << resource);
 int func = BP_FUNC(bp);
 u32 hw_lock_control_reg;

 DP(NETIF_MSG_HW | NETIF_MSG_IFUP,
    "Trying to take a lock on resource %d\n", resource);

 /* Validating that the resource is within range */
 if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
  DP(NETIF_MSG_HW | NETIF_MSG_IFUP,
     "resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
     resource, HW_LOCK_MAX_RESOURCE_VALUE);
  return false;
 }

 if (func <= 5)
  hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
 else
  hw_lock_control_reg =
    (MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);

 /* Try to acquire the lock */
 REG_WR(bp, hw_lock_control_reg + 4, resource_bit);
 lock_status = REG_RD(bp, hw_lock_control_reg);
 if (lock_status & resource_bit)
  return true;

 DP(NETIF_MSG_HW | NETIF_MSG_IFUP,
    "Failed to get a lock on resource %d\n", resource);
 return false;
}

/**
 * bnx2x_get_leader_lock_resource - get the recovery leader resource id
 *
 * @bp: driver handle
 *
 * Returns the recovery leader resource id according to the engine this function
 * belongs to. Currently only 2 engines is supported.
 */

static int bnx2x_get_leader_lock_resource(struct bnx2x *bp)
{
 if (BP_PATH(bp))
  return HW_LOCK_RESOURCE_RECOVERY_LEADER_1;
 else
  return HW_LOCK_RESOURCE_RECOVERY_LEADER_0;
}

/**
 * bnx2x_trylock_leader_lock- try to acquire a leader lock.
 *
 * @bp: driver handle
 *
 * Tries to acquire a leader lock for current engine.
 */

static bool bnx2x_trylock_leader_lock(struct bnx2x *bp)
{
 return bnx2x_trylock_hw_lock(bp, bnx2x_get_leader_lock_resource(bp));
}

static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid, u8 err);

/* schedule the sp task and mark that interrupt occurred (runs from ISR) */
static int bnx2x_schedule_sp_task(struct bnx2x *bp)
{
 /* Set the interrupt occurred bit for the sp-task to recognize it
 * must ack the interrupt and transition according to the IGU
 * state machine.
 */

 atomic_set(&bp->interrupt_occurred, 1);

 /* The sp_task must execute only after this bit
 * is set, otherwise we will get out of sync and miss all
 * further interrupts. Hence, the barrier.
 */

 smp_wmb();

 /* schedule sp_task to workqueue */
 return queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
}

void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe)
{
 struct bnx2x *bp = fp->bp;
 int cid = SW_CID(rr_cqe->ramrod_cqe.conn_and_cmd_data);
 int command = CQE_CMD(rr_cqe->ramrod_cqe.conn_and_cmd_data);
 enum bnx2x_queue_cmd drv_cmd = BNX2X_Q_CMD_MAX;
 struct bnx2x_queue_sp_obj *q_obj = &bnx2x_sp_obj(bp, fp).q_obj;

 DP(BNX2X_MSG_SP,
    "fp %d cid %d got ramrod #%d state is %x type is %d\n",
    fp->index, cid, command, bp->state,
    rr_cqe->ramrod_cqe.ramrod_type);

 /* If cid is within VF range, replace the slowpath object with the
 * one corresponding to this VF
 */

 if (cid >= BNX2X_FIRST_VF_CID  &&
     cid < BNX2X_FIRST_VF_CID + BNX2X_VF_CIDS)
  bnx2x_iov_set_queue_sp_obj(bp, cid, &q_obj);

 switch (command) {
 case (RAMROD_CMD_ID_ETH_CLIENT_UPDATE):
  DP(BNX2X_MSG_SP, "got UPDATE ramrod. CID %d\n", cid);
  drv_cmd = BNX2X_Q_CMD_UPDATE;
  break;

 case (RAMROD_CMD_ID_ETH_CLIENT_SETUP):
  DP(BNX2X_MSG_SP, "got MULTI[%d] setup ramrod\n", cid);
  drv_cmd = BNX2X_Q_CMD_SETUP;
  break;

 case (RAMROD_CMD_ID_ETH_TX_QUEUE_SETUP):
  DP(BNX2X_MSG_SP, "got MULTI[%d] tx-only setup ramrod\n", cid);
  drv_cmd = BNX2X_Q_CMD_SETUP_TX_ONLY;
  break;

 case (RAMROD_CMD_ID_ETH_HALT):
  DP(BNX2X_MSG_SP, "got MULTI[%d] halt ramrod\n", cid);
  drv_cmd = BNX2X_Q_CMD_HALT;
  break;

 case (RAMROD_CMD_ID_ETH_TERMINATE):
  DP(BNX2X_MSG_SP, "got MULTI[%d] terminate ramrod\n", cid);
  drv_cmd = BNX2X_Q_CMD_TERMINATE;
  break;

 case (RAMROD_CMD_ID_ETH_EMPTY):
  DP(BNX2X_MSG_SP, "got MULTI[%d] empty ramrod\n", cid);
  drv_cmd = BNX2X_Q_CMD_EMPTY;
  break;

 case (RAMROD_CMD_ID_ETH_TPA_UPDATE):
  DP(BNX2X_MSG_SP, "got tpa update ramrod CID=%d\n", cid);
  drv_cmd = BNX2X_Q_CMD_UPDATE_TPA;
  break;

 default:
  BNX2X_ERR("unexpected MC reply (%d) on fp[%d]\n",
     command, fp->index);
  return;
 }

 if ((drv_cmd != BNX2X_Q_CMD_MAX) &&
     q_obj->complete_cmd(bp, q_obj, drv_cmd))
  /* q_obj->complete_cmd() failure means that this was
 * an unexpected completion.
 *
 * In this case we don't want to increase the bp->spq_left
 * because apparently we haven't sent this command the first
 * place.
 */

#ifdef BNX2X_STOP_ON_ERROR
  bnx2x_panic();
#else
  return;
#endif

 smp_mb__before_atomic();
 atomic_inc(&bp->cq_spq_left);
 /* push the change in bp->spq_left and towards the memory */
 smp_mb__after_atomic();

 DP(BNX2X_MSG_SP, "bp->cq_spq_left %x\n", atomic_read(&bp->cq_spq_left));

 if ((drv_cmd == BNX2X_Q_CMD_UPDATE) && (IS_FCOE_FP(fp)) &&
     (!!test_bit(BNX2X_AFEX_FCOE_Q_UPDATE_PENDING, &bp->sp_state))) {
  /* if Q update ramrod is completed for last Q in AFEX vif set
 * flow, then ACK MCP at the end
 *
 * mark pending ACK to MCP bit.
 * prevent case that both bits are cleared.
 * At the end of load/unload driver checks that
 * sp_state is cleared, and this order prevents
 * races
 */

  smp_mb__before_atomic();
  set_bit(BNX2X_AFEX_PENDING_VIFSET_MCP_ACK, &bp->sp_state);
  wmb();
  clear_bit(BNX2X_AFEX_FCOE_Q_UPDATE_PENDING, &bp->sp_state);
  smp_mb__after_atomic();

  /* schedule the sp task as mcp ack is required */
  bnx2x_schedule_sp_task(bp);
 }

 return;
}

irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
{
 struct bnx2x *bp = netdev_priv(dev_instance);
 u16 status = bnx2x_ack_int(bp);
 u16 mask;
 int i;
 u8 cos;

 /* Return here if interrupt is shared and it's not for us */
 if (unlikely(status == 0)) {
  DP(NETIF_MSG_INTR, "not our interrupt!\n");
  return IRQ_NONE;
 }
 DP(NETIF_MSG_INTR, "got an interrupt status 0x%x\n", status);

#ifdef BNX2X_STOP_ON_ERROR
 if (unlikely(bp->panic))
  return IRQ_HANDLED;
#endif

 for_each_eth_queue(bp, i) {
  struct bnx2x_fastpath *fp = &bp->fp[i];

  mask = 0x2 << (fp->index + CNIC_SUPPORT(bp));
  if (status & mask) {
   /* Handle Rx or Tx according to SB id */
   for_each_cos_in_tx_queue(fp, cos)
    prefetch(fp->txdata_ptr[cos]->tx_cons_sb);
   prefetch(&fp->sb_running_index[SM_RX_ID]);
   napi_schedule_irqoff(&bnx2x_fp(bp, fp->index, napi));
   status &= ~mask;
  }
 }

 if (CNIC_SUPPORT(bp)) {
  mask = 0x2;
  if (status & (mask | 0x1)) {
   struct cnic_ops *c_ops = NULL;

   rcu_read_lock();
   c_ops = rcu_dereference(bp->cnic_ops);
   if (c_ops && (bp->cnic_eth_dev.drv_state &
          CNIC_DRV_STATE_HANDLES_IRQ))
    c_ops->cnic_handler(bp->cnic_data, NULL);
   rcu_read_unlock();

   status &= ~mask;
  }
 }

 if (unlikely(status & 0x1)) {

  /* schedule sp task to perform default status block work, ack
 * attentions and enable interrupts.
 */

  bnx2x_schedule_sp_task(bp);

  status &= ~0x1;
  if (!status)
   return IRQ_HANDLED;
 }

 if (unlikely(status))
  DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n",
     status);

 return IRQ_HANDLED;
}

/* Link */

/*
 * General service functions
 */


int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource)
{
 u32 lock_status;
 u32 resource_bit = (1 << resource);
 int func = BP_FUNC(bp);
 u32 hw_lock_control_reg;
 int cnt;

 /* Validating that the resource is within range */
 if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
  BNX2X_ERR("resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
     resource, HW_LOCK_MAX_RESOURCE_VALUE);
  return -EINVAL;
 }

 if (func <= 5) {
  hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
 } else {
  hw_lock_control_reg =
    (MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
 }

 /* Validating that the resource is not already taken */
 lock_status = REG_RD(bp, hw_lock_control_reg);
 if (lock_status & resource_bit) {
  BNX2X_ERR("lock_status 0x%x resource_bit 0x%x\n",
     lock_status, resource_bit);
  return -EEXIST;
 }

 /* Try for 5 second every 5ms */
 for (cnt = 0; cnt < 1000; cnt++) {
  /* Try to acquire the lock */
  REG_WR(bp, hw_lock_control_reg + 4, resource_bit);
  lock_status = REG_RD(bp, hw_lock_control_reg);
  if (lock_status & resource_bit)
   return 0;

  usleep_range(5000, 10000);
 }
 BNX2X_ERR("Timeout\n");
 return -EAGAIN;
}

int bnx2x_release_leader_lock(struct bnx2x *bp)
{
 return bnx2x_release_hw_lock(bp, bnx2x_get_leader_lock_resource(bp));
}

int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource)
{
 u32 lock_status;
 u32 resource_bit = (1 << resource);
 int func = BP_FUNC(bp);
 u32 hw_lock_control_reg;

 /* Validating that the resource is within range */
 if (resource > HW_LOCK_MAX_RESOURCE_VALUE) {
  BNX2X_ERR("resource(0x%x) > HW_LOCK_MAX_RESOURCE_VALUE(0x%x)\n",
     resource, HW_LOCK_MAX_RESOURCE_VALUE);
  return -EINVAL;
 }

 if (func <= 5) {
  hw_lock_control_reg = (MISC_REG_DRIVER_CONTROL_1 + func*8);
 } else {
  hw_lock_control_reg =
    (MISC_REG_DRIVER_CONTROL_7 + (func - 6)*8);
 }

 /* Validating that the resource is currently taken */
 lock_status = REG_RD(bp, hw_lock_control_reg);
 if (!(lock_status & resource_bit)) {
  BNX2X_ERR("lock_status 0x%x resource_bit 0x%x. Unlock was called but lock wasn't taken!\n",
     lock_status, resource_bit);
  return -EFAULT;
 }

 REG_WR(bp, hw_lock_control_reg, resource_bit);
 return 0;
}

int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port)
{
 /* The GPIO should be swapped if swap register is set and active */
 int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
    REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
 int gpio_shift = gpio_num +
   (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
 u32 gpio_mask = (1 << gpio_shift);
 u32 gpio_reg;
 int value;

 if (gpio_num > MISC_REGISTERS_GPIO_3) {
  BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
  return -EINVAL;
 }

 /* read GPIO value */
 gpio_reg = REG_RD(bp, MISC_REG_GPIO);

 /* get the requested pin value */
 if ((gpio_reg & gpio_mask) == gpio_mask)
  value = 1;
 else
  value = 0;

 return value;
}

int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port)
{
 /* The GPIO should be swapped if swap register is set and active */
 int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
    REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
 int gpio_shift = gpio_num +
   (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
 u32 gpio_mask = (1 << gpio_shift);
 u32 gpio_reg;

 if (gpio_num > MISC_REGISTERS_GPIO_3) {
  BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
  return -EINVAL;
 }

 bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
 /* read GPIO and mask except the float bits */
 gpio_reg = (REG_RD(bp, MISC_REG_GPIO) & MISC_REGISTERS_GPIO_FLOAT);

 switch (mode) {
 case MISC_REGISTERS_GPIO_OUTPUT_LOW:
  DP(NETIF_MSG_LINK,
     "Set GPIO %d (shift %d) -> output low\n",
     gpio_num, gpio_shift);
  /* clear FLOAT and set CLR */
  gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
  gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_CLR_POS);
  break;

 case MISC_REGISTERS_GPIO_OUTPUT_HIGH:
  DP(NETIF_MSG_LINK,
     "Set GPIO %d (shift %d) -> output high\n",
     gpio_num, gpio_shift);
  /* clear FLOAT and set SET */
  gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
  gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_SET_POS);
  break;

 case MISC_REGISTERS_GPIO_INPUT_HI_Z:
  DP(NETIF_MSG_LINK,
     "Set GPIO %d (shift %d) -> input\n",
     gpio_num, gpio_shift);
  /* set FLOAT */
  gpio_reg |= (gpio_mask << MISC_REGISTERS_GPIO_FLOAT_POS);
  break;

 default:
  break;
 }

 REG_WR(bp, MISC_REG_GPIO, gpio_reg);
 bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);

 return 0;
}

int bnx2x_set_mult_gpio(struct bnx2x *bp, u8 pins, u32 mode)
{
 u32 gpio_reg = 0;
 int rc = 0;

 /* Any port swapping should be handled by caller. */

 bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
 /* read GPIO and mask except the float bits */
 gpio_reg = REG_RD(bp, MISC_REG_GPIO);
 gpio_reg &= ~(pins << MISC_REGISTERS_GPIO_FLOAT_POS);
 gpio_reg &= ~(pins << MISC_REGISTERS_GPIO_CLR_POS);
 gpio_reg &= ~(pins << MISC_REGISTERS_GPIO_SET_POS);

 switch (mode) {
 case MISC_REGISTERS_GPIO_OUTPUT_LOW:
  DP(NETIF_MSG_LINK, "Set GPIO 0x%x -> output low\n", pins);
  /* set CLR */
  gpio_reg |= (pins << MISC_REGISTERS_GPIO_CLR_POS);
  break;

 case MISC_REGISTERS_GPIO_OUTPUT_HIGH:
  DP(NETIF_MSG_LINK, "Set GPIO 0x%x -> output high\n", pins);
  /* set SET */
  gpio_reg |= (pins << MISC_REGISTERS_GPIO_SET_POS);
  break;

 case MISC_REGISTERS_GPIO_INPUT_HI_Z:
  DP(NETIF_MSG_LINK, "Set GPIO 0x%x -> input\n", pins);
  /* set FLOAT */
  gpio_reg |= (pins << MISC_REGISTERS_GPIO_FLOAT_POS);
  break;

 default:
  BNX2X_ERR("Invalid GPIO mode assignment %d\n", mode);
  rc = -EINVAL;
  break;
 }

 if (rc == 0)
  REG_WR(bp, MISC_REG_GPIO, gpio_reg);

 bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);

 return rc;
}

int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port)
{
 /* The GPIO should be swapped if swap register is set and active */
 int gpio_port = (REG_RD(bp, NIG_REG_PORT_SWAP) &&
    REG_RD(bp, NIG_REG_STRAP_OVERRIDE)) ^ port;
 int gpio_shift = gpio_num +
   (gpio_port ? MISC_REGISTERS_GPIO_PORT_SHIFT : 0);
 u32 gpio_mask = (1 << gpio_shift);
 u32 gpio_reg;

 if (gpio_num > MISC_REGISTERS_GPIO_3) {
  BNX2X_ERR("Invalid GPIO %d\n", gpio_num);
  return -EINVAL;
 }

 bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);
 /* read GPIO int */
 gpio_reg = REG_RD(bp, MISC_REG_GPIO_INT);

 switch (mode) {
 case MISC_REGISTERS_GPIO_INT_OUTPUT_CLR:
  DP(NETIF_MSG_LINK,
     "Clear GPIO INT %d (shift %d) -> output low\n",
     gpio_num, gpio_shift);
  /* clear SET and set CLR */
  gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_INT_SET_POS);
  gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_INT_CLR_POS);
  break;

 case MISC_REGISTERS_GPIO_INT_OUTPUT_SET:
  DP(NETIF_MSG_LINK,
     "Set GPIO INT %d (shift %d) -> output high\n",
     gpio_num, gpio_shift);
  /* clear CLR and set SET */
  gpio_reg &= ~(gpio_mask << MISC_REGISTERS_GPIO_INT_CLR_POS);
  gpio_reg |=  (gpio_mask << MISC_REGISTERS_GPIO_INT_SET_POS);
  break;

 default:
  break;
 }

 REG_WR(bp, MISC_REG_GPIO_INT, gpio_reg);
 bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_GPIO);

 return 0;
}

static int bnx2x_set_spio(struct bnx2x *bp, int spio, u32 mode)
{
 u32 spio_reg;

 /* Only 2 SPIOs are configurable */
 if ((spio != MISC_SPIO_SPIO4) && (spio != MISC_SPIO_SPIO5)) {
  BNX2X_ERR("Invalid SPIO 0x%x\n", spio);
  return -EINVAL;
 }

 bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);
 /* read SPIO and mask except the float bits */
 spio_reg = (REG_RD(bp, MISC_REG_SPIO) & MISC_SPIO_FLOAT);

 switch (mode) {
 case MISC_SPIO_OUTPUT_LOW:
  DP(NETIF_MSG_HW, "Set SPIO 0x%x -> output low\n", spio);
  /* clear FLOAT and set CLR */
  spio_reg &= ~(spio << MISC_SPIO_FLOAT_POS);
  spio_reg |=  (spio << MISC_SPIO_CLR_POS);
  break;

 case MISC_SPIO_OUTPUT_HIGH:
  DP(NETIF_MSG_HW, "Set SPIO 0x%x -> output high\n", spio);
  /* clear FLOAT and set SET */
  spio_reg &= ~(spio << MISC_SPIO_FLOAT_POS);
  spio_reg |=  (spio << MISC_SPIO_SET_POS);
  break;

 case MISC_SPIO_INPUT_HI_Z:
  DP(NETIF_MSG_HW, "Set SPIO 0x%x -> input\n", spio);
  /* set FLOAT */
  spio_reg |= (spio << MISC_SPIO_FLOAT_POS);
  break;

 default:
  break;
 }

 REG_WR(bp, MISC_REG_SPIO, spio_reg);
 bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_SPIO);

 return 0;
}

void bnx2x_calc_fc_adv(struct bnx2x *bp)
{
 u8 cfg_idx = bnx2x_get_link_cfg_idx(bp);

 bp->port.advertising[cfg_idx] &= ~(ADVERTISED_Asym_Pause |
        ADVERTISED_Pause);
 switch (bp->link_vars.ieee_fc &
  MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK) {
 case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH:
  bp->port.advertising[cfg_idx] |= (ADVERTISED_Asym_Pause |
        ADVERTISED_Pause);
  break;

 case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC:
  bp->port.advertising[cfg_idx] |= ADVERTISED_Asym_Pause;
  break;

 default:
  break;
 }
}

static void bnx2x_set_requested_fc(struct bnx2x *bp)
{
 /* Initialize link parameters structure variables
 * It is recommended to turn off RX FC for jumbo frames
 *  for better performance
 */

 if (CHIP_IS_E1x(bp) && (bp->dev->mtu > 5000))
  bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_TX;
 else
--> --------------------

--> maximum size reached

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

Messung V0.5
C=94 H=90 G=91

¤ Dauer der Verarbeitung: 0.27 Sekunden  ¤

*© 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.