From adfc5217e9db68d3f0cec8dd847c1a6d3ab549ee Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 7 Apr 2011 06:03:04 -0700 Subject: broadcom: Move the Broadcom drivers Moves the drivers for Broadcom devices into drivers/net/ethernet/broadcom/ and the necessary Kconfig and Makefile changes. CC: Eilon Greenstein CC: Michael Chan CC: Matt Carlson CC: Gary Zambrano CC: "Maciej W. Rozycki" Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/broadcom/bnx2x/Makefile | 7 + drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 2014 +++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 3571 ++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 1491 +++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c | 2507 ++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h | 203 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h | 1156 ++ .../net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 2355 ++++ .../net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h | 410 + .../ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h | 38 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 5131 ++++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h | 567 + .../net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h | 912 ++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c | 12472 +++++++++++++++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h | 493 + drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 11531 +++++++++++++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 7146 +++++++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 5692 +++++++++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h | 1297 ++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c | 1598 +++ drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h | 381 + 21 files changed, 60972 insertions(+) create mode 100644 drivers/net/ethernet/broadcom/bnx2x/Makefile create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c create mode 100644 drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h (limited to 'drivers/net/ethernet/broadcom/bnx2x') diff --git a/drivers/net/ethernet/broadcom/bnx2x/Makefile b/drivers/net/ethernet/broadcom/bnx2x/Makefile new file mode 100644 index 000000000000..48fbdd48f88f --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for Broadcom 10-Gigabit ethernet driver +# + +obj-$(CONFIG_BNX2X) += bnx2x.o + +bnx2x-objs := bnx2x_main.o bnx2x_link.o bnx2x_cmn.o bnx2x_ethtool.o bnx2x_stats.o bnx2x_dcb.o bnx2x_sp.o diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h new file mode 100644 index 000000000000..c423504a755f --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -0,0 +1,2014 @@ +/* bnx2x.h: Broadcom Everest network driver. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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: Eilon Greenstein + * Written by: Eliezer Tamir + * Based on code from Michael Chan's bnx2 driver + */ + +#ifndef BNX2X_H +#define BNX2X_H +#include +#include +#include + +/* compilation time flags */ + +/* define this to make the driver freeze on error to allow getting debug info + * (you will need to reboot afterwards) */ +/* #define BNX2X_STOP_ON_ERROR */ + +#define DRV_MODULE_VERSION "1.70.00-0" +#define DRV_MODULE_RELDATE "2011/06/13" +#define BNX2X_BC_VER 0x040200 + +#if defined(CONFIG_DCB) +#define BCM_DCBNL +#endif +#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE) +#define BCM_CNIC 1 +#include "../cnic_if.h" +#endif + +#ifdef BCM_CNIC +#define BNX2X_MIN_MSIX_VEC_CNT 3 +#define BNX2X_MSIX_VEC_FP_START 2 +#else +#define BNX2X_MIN_MSIX_VEC_CNT 2 +#define BNX2X_MSIX_VEC_FP_START 1 +#endif + +#include + +#include "bnx2x_reg.h" +#include "bnx2x_fw_defs.h" +#include "bnx2x_hsi.h" +#include "bnx2x_link.h" +#include "bnx2x_sp.h" +#include "bnx2x_dcb.h" +#include "bnx2x_stats.h" + +/* error/debug prints */ + +#define DRV_MODULE_NAME "bnx2x" + +/* for messages that are currently off */ +#define BNX2X_MSG_OFF 0 +#define BNX2X_MSG_MCP 0x010000 /* was: NETIF_MSG_HW */ +#define BNX2X_MSG_STATS 0x020000 /* was: NETIF_MSG_TIMER */ +#define BNX2X_MSG_NVM 0x040000 /* was: NETIF_MSG_HW */ +#define BNX2X_MSG_DMAE 0x080000 /* was: NETIF_MSG_HW */ +#define BNX2X_MSG_SP 0x100000 /* was: NETIF_MSG_INTR */ +#define BNX2X_MSG_FP 0x200000 /* was: NETIF_MSG_INTR */ + +#define DP_LEVEL KERN_NOTICE /* was: KERN_DEBUG */ + +/* regular debug print */ +#define DP(__mask, __fmt, __args...) \ +do { \ + if (bp->msg_enable & (__mask)) \ + printk(DP_LEVEL "[%s:%d(%s)]" __fmt, \ + __func__, __LINE__, \ + bp->dev ? (bp->dev->name) : "?", \ + ##__args); \ +} while (0) + +#define DP_CONT(__mask, __fmt, __args...) \ +do { \ + if (bp->msg_enable & (__mask)) \ + pr_cont(__fmt, ##__args); \ +} while (0) + +/* errors debug print */ +#define BNX2X_DBG_ERR(__fmt, __args...) \ +do { \ + if (netif_msg_probe(bp)) \ + pr_err("[%s:%d(%s)]" __fmt, \ + __func__, __LINE__, \ + bp->dev ? (bp->dev->name) : "?", \ + ##__args); \ +} while (0) + +/* for errors (never masked) */ +#define BNX2X_ERR(__fmt, __args...) \ +do { \ + pr_err("[%s:%d(%s)]" __fmt, \ + __func__, __LINE__, \ + bp->dev ? (bp->dev->name) : "?", \ + ##__args); \ + } while (0) + +#define BNX2X_ERROR(__fmt, __args...) do { \ + pr_err("[%s:%d]" __fmt, __func__, __LINE__, ##__args); \ + } while (0) + + +/* before we have a dev->name use dev_info() */ +#define BNX2X_DEV_INFO(__fmt, __args...) \ +do { \ + if (netif_msg_probe(bp)) \ + dev_info(&bp->pdev->dev, __fmt, ##__args); \ +} while (0) + +#define BNX2X_MAC_FMT "%pM" +#define BNX2X_MAC_PRN_LIST(mac) (mac) + + +#ifdef BNX2X_STOP_ON_ERROR +void bnx2x_int_disable(struct bnx2x *bp); +#define bnx2x_panic() do { \ + bp->panic = 1; \ + BNX2X_ERR("driver assert\n"); \ + bnx2x_int_disable(bp); \ + bnx2x_panic_dump(bp); \ + } while (0) +#else +#define bnx2x_panic() do { \ + bp->panic = 1; \ + BNX2X_ERR("driver assert\n"); \ + bnx2x_panic_dump(bp); \ + } while (0) +#endif + +#define bnx2x_mc_addr(ha) ((ha)->addr) +#define bnx2x_uc_addr(ha) ((ha)->addr) + +#define U64_LO(x) (u32)(((u64)(x)) & 0xffffffff) +#define U64_HI(x) (u32)(((u64)(x)) >> 32) +#define HILO_U64(hi, lo) ((((u64)(hi)) << 32) + (lo)) + + +#define REG_ADDR(bp, offset) ((bp->regview) + (offset)) + +#define REG_RD(bp, offset) readl(REG_ADDR(bp, offset)) +#define REG_RD8(bp, offset) readb(REG_ADDR(bp, offset)) +#define REG_RD16(bp, offset) readw(REG_ADDR(bp, offset)) + +#define REG_WR(bp, offset, val) writel((u32)val, REG_ADDR(bp, offset)) +#define REG_WR8(bp, offset, val) writeb((u8)val, REG_ADDR(bp, offset)) +#define REG_WR16(bp, offset, val) writew((u16)val, REG_ADDR(bp, offset)) + +#define REG_RD_IND(bp, offset) bnx2x_reg_rd_ind(bp, offset) +#define REG_WR_IND(bp, offset, val) bnx2x_reg_wr_ind(bp, offset, val) + +#define REG_RD_DMAE(bp, offset, valp, len32) \ + do { \ + bnx2x_read_dmae(bp, offset, len32);\ + memcpy(valp, bnx2x_sp(bp, wb_data[0]), (len32) * 4); \ + } while (0) + +#define REG_WR_DMAE(bp, offset, valp, len32) \ + do { \ + memcpy(bnx2x_sp(bp, wb_data[0]), valp, (len32) * 4); \ + bnx2x_write_dmae(bp, bnx2x_sp_mapping(bp, wb_data), \ + offset, len32); \ + } while (0) + +#define REG_WR_DMAE_LEN(bp, offset, valp, len32) \ + REG_WR_DMAE(bp, offset, valp, len32) + +#define VIRT_WR_DMAE_LEN(bp, data, addr, len32, le32_swap) \ + do { \ + memcpy(GUNZIP_BUF(bp), data, (len32) * 4); \ + bnx2x_write_big_buf_wb(bp, addr, len32); \ + } while (0) + +#define SHMEM_ADDR(bp, field) (bp->common.shmem_base + \ + offsetof(struct shmem_region, field)) +#define SHMEM_RD(bp, field) REG_RD(bp, SHMEM_ADDR(bp, field)) +#define SHMEM_WR(bp, field, val) REG_WR(bp, SHMEM_ADDR(bp, field), val) + +#define SHMEM2_ADDR(bp, field) (bp->common.shmem2_base + \ + offsetof(struct shmem2_region, field)) +#define SHMEM2_RD(bp, field) REG_RD(bp, SHMEM2_ADDR(bp, field)) +#define SHMEM2_WR(bp, field, val) REG_WR(bp, SHMEM2_ADDR(bp, field), val) +#define MF_CFG_ADDR(bp, field) (bp->common.mf_cfg_base + \ + offsetof(struct mf_cfg, field)) +#define MF2_CFG_ADDR(bp, field) (bp->common.mf2_cfg_base + \ + offsetof(struct mf2_cfg, field)) + +#define MF_CFG_RD(bp, field) REG_RD(bp, MF_CFG_ADDR(bp, field)) +#define MF_CFG_WR(bp, field, val) REG_WR(bp,\ + MF_CFG_ADDR(bp, field), (val)) +#define MF2_CFG_RD(bp, field) REG_RD(bp, MF2_CFG_ADDR(bp, field)) + +#define SHMEM2_HAS(bp, field) ((bp)->common.shmem2_base && \ + (SHMEM2_RD((bp), size) > \ + offsetof(struct shmem2_region, field))) + +#define EMAC_RD(bp, reg) REG_RD(bp, emac_base + reg) +#define EMAC_WR(bp, reg, val) REG_WR(bp, emac_base + reg, val) + +/* SP SB indices */ + +/* General SP events - stats query, cfc delete, etc */ +#define HC_SP_INDEX_ETH_DEF_CONS 3 + +/* EQ completions */ +#define HC_SP_INDEX_EQ_CONS 7 + +/* FCoE L2 connection completions */ +#define HC_SP_INDEX_ETH_FCOE_TX_CQ_CONS 6 +#define HC_SP_INDEX_ETH_FCOE_RX_CQ_CONS 4 +/* iSCSI L2 */ +#define HC_SP_INDEX_ETH_ISCSI_CQ_CONS 5 +#define HC_SP_INDEX_ETH_ISCSI_RX_CQ_CONS 1 + +/* Special clients parameters */ + +/* SB indices */ +/* FCoE L2 */ +#define BNX2X_FCOE_L2_RX_INDEX \ + (&bp->def_status_blk->sp_sb.\ + index_values[HC_SP_INDEX_ETH_FCOE_RX_CQ_CONS]) + +#define BNX2X_FCOE_L2_TX_INDEX \ + (&bp->def_status_blk->sp_sb.\ + index_values[HC_SP_INDEX_ETH_FCOE_TX_CQ_CONS]) + +/** + * CIDs and CLIDs: + * CLIDs below is a CLID for func 0, then the CLID for other + * functions will be calculated by the formula: + * + * FUNC_N_CLID_X = N * NUM_SPECIAL_CLIENTS + FUNC_0_CLID_X + * + */ +/* iSCSI L2 */ +#define BNX2X_ISCSI_ETH_CL_ID_IDX 1 +#define BNX2X_ISCSI_ETH_CID 49 + +/* FCoE L2 */ +#define BNX2X_FCOE_ETH_CL_ID_IDX 2 +#define BNX2X_FCOE_ETH_CID 50 + +/** Additional rings budgeting */ +#ifdef BCM_CNIC +#define CNIC_PRESENT 1 +#define FCOE_PRESENT 1 +#else +#define CNIC_PRESENT 0 +#define FCOE_PRESENT 0 +#endif /* BCM_CNIC */ +#define NON_ETH_CONTEXT_USE (FCOE_PRESENT) + +#define AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR \ + AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR + +#define SM_RX_ID 0 +#define SM_TX_ID 1 + +/* defines for multiple tx priority indices */ +#define FIRST_TX_ONLY_COS_INDEX 1 +#define FIRST_TX_COS_INDEX 0 + +/* defines for decodeing the fastpath index and the cos index out of the + * transmission queue index + */ +#define MAX_TXQS_PER_COS FP_SB_MAX_E1x + +#define TXQ_TO_FP(txq_index) ((txq_index) % MAX_TXQS_PER_COS) +#define TXQ_TO_COS(txq_index) ((txq_index) / MAX_TXQS_PER_COS) + +/* rules for calculating the cids of tx-only connections */ +#define CID_TO_FP(cid) ((cid) % MAX_TXQS_PER_COS) +#define CID_COS_TO_TX_ONLY_CID(cid, cos) (cid + cos * MAX_TXQS_PER_COS) + +/* fp index inside class of service range */ +#define FP_COS_TO_TXQ(fp, cos) ((fp)->index + cos * MAX_TXQS_PER_COS) + +/* + * 0..15 eth cos0 + * 16..31 eth cos1 if applicable + * 32..47 eth cos2 If applicable + * fcoe queue follows eth queues (16, 32, 48 depending on cos) + */ +#define MAX_ETH_TXQ_IDX(bp) (MAX_TXQS_PER_COS * (bp)->max_cos) +#define FCOE_TXQ_IDX(bp) (MAX_ETH_TXQ_IDX(bp)) + +/* fast path */ +struct sw_rx_bd { + struct sk_buff *skb; + DEFINE_DMA_UNMAP_ADDR(mapping); +}; + +struct sw_tx_bd { + struct sk_buff *skb; + u16 first_bd; + u8 flags; +/* Set on the first BD descriptor when there is a split BD */ +#define BNX2X_TSO_SPLIT_BD (1<<0) +}; + +struct sw_rx_page { + struct page *page; + DEFINE_DMA_UNMAP_ADDR(mapping); +}; + +union db_prod { + struct doorbell_set_prod data; + u32 raw; +}; + + +/* MC hsi */ +#define BCM_PAGE_SHIFT 12 +#define BCM_PAGE_SIZE (1 << BCM_PAGE_SHIFT) +#define BCM_PAGE_MASK (~(BCM_PAGE_SIZE - 1)) +#define BCM_PAGE_ALIGN(addr) (((addr) + BCM_PAGE_SIZE - 1) & BCM_PAGE_MASK) + +#define PAGES_PER_SGE_SHIFT 0 +#define PAGES_PER_SGE (1 << PAGES_PER_SGE_SHIFT) +#define SGE_PAGE_SIZE PAGE_SIZE +#define SGE_PAGE_SHIFT PAGE_SHIFT +#define SGE_PAGE_ALIGN(addr) PAGE_ALIGN((typeof(PAGE_SIZE))(addr)) + +/* SGE ring related macros */ +#define NUM_RX_SGE_PAGES 2 +#define RX_SGE_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_sge)) +#define MAX_RX_SGE_CNT (RX_SGE_CNT - 2) +/* RX_SGE_CNT is promised to be a power of 2 */ +#define RX_SGE_MASK (RX_SGE_CNT - 1) +#define NUM_RX_SGE (RX_SGE_CNT * NUM_RX_SGE_PAGES) +#define MAX_RX_SGE (NUM_RX_SGE - 1) +#define NEXT_SGE_IDX(x) ((((x) & RX_SGE_MASK) == \ + (MAX_RX_SGE_CNT - 1)) ? (x) + 3 : (x) + 1) +#define RX_SGE(x) ((x) & MAX_RX_SGE) + +/* Manipulate a bit vector defined as an array of u64 */ + +/* Number of bits in one sge_mask array element */ +#define BIT_VEC64_ELEM_SZ 64 +#define BIT_VEC64_ELEM_SHIFT 6 +#define BIT_VEC64_ELEM_MASK ((u64)BIT_VEC64_ELEM_SZ - 1) + + +#define __BIT_VEC64_SET_BIT(el, bit) \ + do { \ + el = ((el) | ((u64)0x1 << (bit))); \ + } while (0) + +#define __BIT_VEC64_CLEAR_BIT(el, bit) \ + do { \ + el = ((el) & (~((u64)0x1 << (bit)))); \ + } while (0) + + +#define BIT_VEC64_SET_BIT(vec64, idx) \ + __BIT_VEC64_SET_BIT((vec64)[(idx) >> BIT_VEC64_ELEM_SHIFT], \ + (idx) & BIT_VEC64_ELEM_MASK) + +#define BIT_VEC64_CLEAR_BIT(vec64, idx) \ + __BIT_VEC64_CLEAR_BIT((vec64)[(idx) >> BIT_VEC64_ELEM_SHIFT], \ + (idx) & BIT_VEC64_ELEM_MASK) + +#define BIT_VEC64_TEST_BIT(vec64, idx) \ + (((vec64)[(idx) >> BIT_VEC64_ELEM_SHIFT] >> \ + ((idx) & BIT_VEC64_ELEM_MASK)) & 0x1) + +/* Creates a bitmask of all ones in less significant bits. + idx - index of the most significant bit in the created mask */ +#define BIT_VEC64_ONES_MASK(idx) \ + (((u64)0x1 << (((idx) & BIT_VEC64_ELEM_MASK) + 1)) - 1) +#define BIT_VEC64_ELEM_ONE_MASK ((u64)(~0)) + +/*******************************************************/ + + + +/* Number of u64 elements in SGE mask array */ +#define RX_SGE_MASK_LEN ((NUM_RX_SGE_PAGES * RX_SGE_CNT) / \ + BIT_VEC64_ELEM_SZ) +#define RX_SGE_MASK_LEN_MASK (RX_SGE_MASK_LEN - 1) +#define NEXT_SGE_MASK_ELEM(el) (((el) + 1) & RX_SGE_MASK_LEN_MASK) + +union host_hc_status_block { + /* pointer to fp status block e1x */ + struct host_hc_status_block_e1x *e1x_sb; + /* pointer to fp status block e2 */ + struct host_hc_status_block_e2 *e2_sb; +}; + +struct bnx2x_agg_info { + /* + * First aggregation buffer is an skb, the following - are pages. + * We will preallocate the skbs for each aggregation when + * we open the interface and will replace the BD at the consumer + * with this one when we receive the TPA_START CQE in order to + * keep the Rx BD ring consistent. + */ + struct sw_rx_bd first_buf; + u8 tpa_state; +#define BNX2X_TPA_START 1 +#define BNX2X_TPA_STOP 2 +#define BNX2X_TPA_ERROR 3 + u8 placement_offset; + u16 parsing_flags; + u16 vlan_tag; + u16 len_on_bd; +}; + +#define Q_STATS_OFFSET32(stat_name) \ + (offsetof(struct bnx2x_eth_q_stats, stat_name) / 4) + +struct bnx2x_fp_txdata { + + struct sw_tx_bd *tx_buf_ring; + + union eth_tx_bd_types *tx_desc_ring; + dma_addr_t tx_desc_mapping; + + u32 cid; + + union db_prod tx_db; + + u16 tx_pkt_prod; + u16 tx_pkt_cons; + u16 tx_bd_prod; + u16 tx_bd_cons; + + unsigned long tx_pkt; + + __le16 *tx_cons_sb; + + int txq_index; +}; + +struct bnx2x_fastpath { + struct bnx2x *bp; /* parent */ + +#define BNX2X_NAPI_WEIGHT 128 + struct napi_struct napi; + union host_hc_status_block status_blk; + /* chip independed shortcuts into sb structure */ + __le16 *sb_index_values; + __le16 *sb_running_index; + /* chip independed shortcut into rx_prods_offset memory */ + u32 ustorm_rx_prods_offset; + + u32 rx_buf_size; + + dma_addr_t status_blk_mapping; + + u8 max_cos; /* actual number of active tx coses */ + struct bnx2x_fp_txdata txdata[BNX2X_MULTI_TX_COS]; + + struct sw_rx_bd *rx_buf_ring; /* BDs mappings ring */ + struct sw_rx_page *rx_page_ring; /* SGE pages mappings ring */ + + struct eth_rx_bd *rx_desc_ring; + dma_addr_t rx_desc_mapping; + + union eth_rx_cqe *rx_comp_ring; + dma_addr_t rx_comp_mapping; + + /* SGE ring */ + struct eth_rx_sge *rx_sge_ring; + dma_addr_t rx_sge_mapping; + + u64 sge_mask[RX_SGE_MASK_LEN]; + + u32 cid; + + __le16 fp_hc_idx; + + u8 index; /* number in fp array */ + u8 cl_id; /* eth client id */ + u8 cl_qzone_id; + u8 fw_sb_id; /* status block number in FW */ + u8 igu_sb_id; /* status block number in HW */ + + u16 rx_bd_prod; + u16 rx_bd_cons; + u16 rx_comp_prod; + u16 rx_comp_cons; + u16 rx_sge_prod; + /* The last maximal completed SGE */ + u16 last_max_sge; + __le16 *rx_cons_sb; + unsigned long rx_pkt, + rx_calls; + + /* TPA related */ + struct bnx2x_agg_info tpa_info[ETH_MAX_AGGREGATION_QUEUES_E1H_E2]; + u8 disable_tpa; +#ifdef BNX2X_STOP_ON_ERROR + u64 tpa_queue_used; +#endif + + struct tstorm_per_queue_stats old_tclient; + struct ustorm_per_queue_stats old_uclient; + struct xstorm_per_queue_stats old_xclient; + struct bnx2x_eth_q_stats eth_q_stats; + + /* The size is calculated using the following: + sizeof name field from netdev structure + + 4 ('-Xx-' string) + + 4 (for the digits and to make it DWORD aligned) */ +#define FP_NAME_SIZE (sizeof(((struct net_device *)0)->name) + 8) + char name[FP_NAME_SIZE]; + + /* MACs object */ + struct bnx2x_vlan_mac_obj mac_obj; + + /* Queue State object */ + struct bnx2x_queue_sp_obj q_obj; + +}; + +#define bnx2x_fp(bp, nr, var) (bp->fp[nr].var) + +/* Use 2500 as a mini-jumbo MTU for FCoE */ +#define BNX2X_FCOE_MINI_JUMBO_MTU 2500 + +/* FCoE L2 `fastpath' entry is right after the eth entries */ +#define FCOE_IDX BNX2X_NUM_ETH_QUEUES(bp) +#define bnx2x_fcoe_fp(bp) (&bp->fp[FCOE_IDX]) +#define bnx2x_fcoe(bp, var) (bnx2x_fcoe_fp(bp)->var) +#define bnx2x_fcoe_tx(bp, var) (bnx2x_fcoe_fp(bp)-> \ + txdata[FIRST_TX_COS_INDEX].var) + + +#define IS_ETH_FP(fp) (fp->index < \ + BNX2X_NUM_ETH_QUEUES(fp->bp)) +#ifdef BCM_CNIC +#define IS_FCOE_FP(fp) (fp->index == FCOE_IDX) +#define IS_FCOE_IDX(idx) ((idx) == FCOE_IDX) +#else +#define IS_FCOE_FP(fp) false +#define IS_FCOE_IDX(idx) false +#endif + + +/* MC hsi */ +#define MAX_FETCH_BD 13 /* HW max BDs per packet */ +#define RX_COPY_THRESH 92 + +#define NUM_TX_RINGS 16 +#define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_tx_bd_types)) +#define MAX_TX_DESC_CNT (TX_DESC_CNT - 1) +#define NUM_TX_BD (TX_DESC_CNT * NUM_TX_RINGS) +#define MAX_TX_BD (NUM_TX_BD - 1) +#define MAX_TX_AVAIL (MAX_TX_DESC_CNT * NUM_TX_RINGS - 2) +#define NEXT_TX_IDX(x) ((((x) & MAX_TX_DESC_CNT) == \ + (MAX_TX_DESC_CNT - 1)) ? (x) + 2 : (x) + 1) +#define TX_BD(x) ((x) & MAX_TX_BD) +#define TX_BD_POFF(x) ((x) & MAX_TX_DESC_CNT) + +/* The RX BD ring is special, each bd is 8 bytes but the last one is 16 */ +#define NUM_RX_RINGS 8 +#define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_rx_bd)) +#define MAX_RX_DESC_CNT (RX_DESC_CNT - 2) +#define RX_DESC_MASK (RX_DESC_CNT - 1) +#define NUM_RX_BD (RX_DESC_CNT * NUM_RX_RINGS) +#define MAX_RX_BD (NUM_RX_BD - 1) +#define MAX_RX_AVAIL (MAX_RX_DESC_CNT * NUM_RX_RINGS - 2) +#define MIN_RX_AVAIL 128 + +#define MIN_RX_SIZE_TPA_HW (CHIP_IS_E1(bp) ? \ + ETH_MIN_RX_CQES_WITH_TPA_E1 : \ + ETH_MIN_RX_CQES_WITH_TPA_E1H_E2) +#define MIN_RX_SIZE_NONTPA_HW ETH_MIN_RX_CQES_WITHOUT_TPA +#define MIN_RX_SIZE_TPA (max_t(u32, MIN_RX_SIZE_TPA_HW, MIN_RX_AVAIL)) +#define MIN_RX_SIZE_NONTPA (max_t(u32, MIN_RX_SIZE_NONTPA_HW,\ + MIN_RX_AVAIL)) + +#define NEXT_RX_IDX(x) ((((x) & RX_DESC_MASK) == \ + (MAX_RX_DESC_CNT - 1)) ? (x) + 3 : (x) + 1) +#define RX_BD(x) ((x) & MAX_RX_BD) + +/* + * As long as CQE is X times bigger than BD entry we have to allocate X times + * more pages for CQ ring in order to keep it balanced with BD ring + */ +#define CQE_BD_REL (sizeof(union eth_rx_cqe) / sizeof(struct eth_rx_bd)) +#define NUM_RCQ_RINGS (NUM_RX_RINGS * CQE_BD_REL) +#define RCQ_DESC_CNT (BCM_PAGE_SIZE / sizeof(union eth_rx_cqe)) +#define MAX_RCQ_DESC_CNT (RCQ_DESC_CNT - 1) +#define NUM_RCQ_BD (RCQ_DESC_CNT * NUM_RCQ_RINGS) +#define MAX_RCQ_BD (NUM_RCQ_BD - 1) +#define MAX_RCQ_AVAIL (MAX_RCQ_DESC_CNT * NUM_RCQ_RINGS - 2) +#define NEXT_RCQ_IDX(x) ((((x) & MAX_RCQ_DESC_CNT) == \ + (MAX_RCQ_DESC_CNT - 1)) ? (x) + 2 : (x) + 1) +#define RCQ_BD(x) ((x) & MAX_RCQ_BD) + + +/* This is needed for determining of last_max */ +#define SUB_S16(a, b) (s16)((s16)(a) - (s16)(b)) +#define SUB_S32(a, b) (s32)((s32)(a) - (s32)(b)) + + +#define BNX2X_SWCID_SHIFT 17 +#define BNX2X_SWCID_MASK ((0x1 << BNX2X_SWCID_SHIFT) - 1) + +/* used on a CID received from the HW */ +#define SW_CID(x) (le32_to_cpu(x) & BNX2X_SWCID_MASK) +#define CQE_CMD(x) (le32_to_cpu(x) >> \ + COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT) + +#define BD_UNMAP_ADDR(bd) HILO_U64(le32_to_cpu((bd)->addr_hi), \ + le32_to_cpu((bd)->addr_lo)) +#define BD_UNMAP_LEN(bd) (le16_to_cpu((bd)->nbytes)) + +#define BNX2X_DB_MIN_SHIFT 3 /* 8 bytes */ +#define BNX2X_DB_SHIFT 7 /* 128 bytes*/ +#if (BNX2X_DB_SHIFT < BNX2X_DB_MIN_SHIFT) +#error "Min DB doorbell stride is 8" +#endif +#define DPM_TRIGER_TYPE 0x40 +#define DOORBELL(bp, cid, val) \ + do { \ + writel((u32)(val), bp->doorbells + (bp->db_size * (cid)) + \ + DPM_TRIGER_TYPE); \ + } while (0) + + +/* TX CSUM helpers */ +#define SKB_CS_OFF(skb) (offsetof(struct tcphdr, check) - \ + skb->csum_offset) +#define SKB_CS(skb) (*(u16 *)(skb_transport_header(skb) + \ + skb->csum_offset)) + +#define pbd_tcp_flags(skb) (ntohl(tcp_flag_word(tcp_hdr(skb)))>>16 & 0xff) + +#define XMIT_PLAIN 0 +#define XMIT_CSUM_V4 0x1 +#define XMIT_CSUM_V6 0x2 +#define XMIT_CSUM_TCP 0x4 +#define XMIT_GSO_V4 0x8 +#define XMIT_GSO_V6 0x10 + +#define XMIT_CSUM (XMIT_CSUM_V4 | XMIT_CSUM_V6) +#define XMIT_GSO (XMIT_GSO_V4 | XMIT_GSO_V6) + + +/* stuff added to make the code fit 80Col */ +#define CQE_TYPE(cqe_fp_flags) ((cqe_fp_flags) & ETH_FAST_PATH_RX_CQE_TYPE) +#define CQE_TYPE_START(cqe_type) ((cqe_type) == RX_ETH_CQE_TYPE_ETH_START_AGG) +#define CQE_TYPE_STOP(cqe_type) ((cqe_type) == RX_ETH_CQE_TYPE_ETH_STOP_AGG) +#define CQE_TYPE_SLOW(cqe_type) ((cqe_type) == RX_ETH_CQE_TYPE_ETH_RAMROD) +#define CQE_TYPE_FAST(cqe_type) ((cqe_type) == RX_ETH_CQE_TYPE_ETH_FASTPATH) + +#define ETH_RX_ERROR_FALGS ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG + +#define BNX2X_IP_CSUM_ERR(cqe) \ + (!((cqe)->fast_path_cqe.status_flags & \ + ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG) && \ + ((cqe)->fast_path_cqe.type_error_flags & \ + ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG)) + +#define BNX2X_L4_CSUM_ERR(cqe) \ + (!((cqe)->fast_path_cqe.status_flags & \ + ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG) && \ + ((cqe)->fast_path_cqe.type_error_flags & \ + ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG)) + +#define BNX2X_RX_CSUM_OK(cqe) \ + (!(BNX2X_L4_CSUM_ERR(cqe) || BNX2X_IP_CSUM_ERR(cqe))) + +#define BNX2X_PRS_FLAG_OVERETH_IPV4(flags) \ + (((le16_to_cpu(flags) & \ + PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) >> \ + PARSING_FLAGS_OVER_ETHERNET_PROTOCOL_SHIFT) \ + == PRS_FLAG_OVERETH_IPV4) +#define BNX2X_RX_SUM_FIX(cqe) \ + BNX2X_PRS_FLAG_OVERETH_IPV4(cqe->fast_path_cqe.pars_flags.flags) + + +#define FP_USB_FUNC_OFF \ + offsetof(struct cstorm_status_block_u, func) +#define FP_CSB_FUNC_OFF \ + offsetof(struct cstorm_status_block_c, func) + +#define HC_INDEX_TOE_RX_CQ_CONS 0 /* Formerly Ustorm TOE CQ index */ + /* (HC_INDEX_U_TOE_RX_CQ_CONS) */ +#define HC_INDEX_ETH_RX_CQ_CONS 1 /* Formerly Ustorm ETH CQ index */ + /* (HC_INDEX_U_ETH_RX_CQ_CONS) */ +#define HC_INDEX_ETH_RX_BD_CONS 2 /* Formerly Ustorm ETH BD index */ + /* (HC_INDEX_U_ETH_RX_BD_CONS) */ + +#define HC_INDEX_TOE_TX_CQ_CONS 4 /* Formerly Cstorm TOE CQ index */ + /* (HC_INDEX_C_TOE_TX_CQ_CONS) */ +#define HC_INDEX_ETH_TX_CQ_CONS_COS0 5 /* Formerly Cstorm ETH CQ index */ + /* (HC_INDEX_C_ETH_TX_CQ_CONS) */ +#define HC_INDEX_ETH_TX_CQ_CONS_COS1 6 /* Formerly Cstorm ETH CQ index */ + /* (HC_INDEX_C_ETH_TX_CQ_CONS) */ +#define HC_INDEX_ETH_TX_CQ_CONS_COS2 7 /* Formerly Cstorm ETH CQ index */ + /* (HC_INDEX_C_ETH_TX_CQ_CONS) */ + +#define HC_INDEX_ETH_FIRST_TX_CQ_CONS HC_INDEX_ETH_TX_CQ_CONS_COS0 + + +#define BNX2X_RX_SB_INDEX \ + (&fp->sb_index_values[HC_INDEX_ETH_RX_CQ_CONS]) + +#define BNX2X_TX_SB_INDEX_BASE BNX2X_TX_SB_INDEX_COS0 + +#define BNX2X_TX_SB_INDEX_COS0 \ + (&fp->sb_index_values[HC_INDEX_ETH_TX_CQ_CONS_COS0]) + +/* end of fast path */ + +/* common */ + +struct bnx2x_common { + + u32 chip_id; +/* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ +#define CHIP_ID(bp) (bp->common.chip_id & 0xfffffff0) + +#define CHIP_NUM(bp) (bp->common.chip_id >> 16) +#define CHIP_NUM_57710 0x164e +#define CHIP_NUM_57711 0x164f +#define CHIP_NUM_57711E 0x1650 +#define CHIP_NUM_57712 0x1662 +#define CHIP_NUM_57712_MF 0x1663 +#define CHIP_NUM_57713 0x1651 +#define CHIP_NUM_57713E 0x1652 +#define CHIP_NUM_57800 0x168a +#define CHIP_NUM_57800_MF 0x16a5 +#define CHIP_NUM_57810 0x168e +#define CHIP_NUM_57810_MF 0x16ae +#define CHIP_NUM_57840 0x168d +#define CHIP_NUM_57840_MF 0x16ab +#define CHIP_IS_E1(bp) (CHIP_NUM(bp) == CHIP_NUM_57710) +#define CHIP_IS_57711(bp) (CHIP_NUM(bp) == CHIP_NUM_57711) +#define CHIP_IS_57711E(bp) (CHIP_NUM(bp) == CHIP_NUM_57711E) +#define CHIP_IS_57712(bp) (CHIP_NUM(bp) == CHIP_NUM_57712) +#define CHIP_IS_57712_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57712_MF) +#define CHIP_IS_57800(bp) (CHIP_NUM(bp) == CHIP_NUM_57800) +#define CHIP_IS_57800_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57800_MF) +#define CHIP_IS_57810(bp) (CHIP_NUM(bp) == CHIP_NUM_57810) +#define CHIP_IS_57810_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57810_MF) +#define CHIP_IS_57840(bp) (CHIP_NUM(bp) == CHIP_NUM_57840) +#define CHIP_IS_57840_MF(bp) (CHIP_NUM(bp) == CHIP_NUM_57840_MF) +#define CHIP_IS_E1H(bp) (CHIP_IS_57711(bp) || \ + CHIP_IS_57711E(bp)) +#define CHIP_IS_E2(bp) (CHIP_IS_57712(bp) || \ + CHIP_IS_57712_MF(bp)) +#define CHIP_IS_E3(bp) (CHIP_IS_57800(bp) || \ + CHIP_IS_57800_MF(bp) || \ + CHIP_IS_57810(bp) || \ + CHIP_IS_57810_MF(bp) || \ + CHIP_IS_57840(bp) || \ + CHIP_IS_57840_MF(bp)) +#define CHIP_IS_E1x(bp) (CHIP_IS_E1((bp)) || CHIP_IS_E1H((bp))) +#define USES_WARPCORE(bp) (CHIP_IS_E3(bp)) +#define IS_E1H_OFFSET (!CHIP_IS_E1(bp)) + +#define CHIP_REV_SHIFT 12 +#define CHIP_REV_MASK (0xF << CHIP_REV_SHIFT) +#define CHIP_REV_VAL(bp) (bp->common.chip_id & CHIP_REV_MASK) +#define CHIP_REV_Ax (0x0 << CHIP_REV_SHIFT) +#define CHIP_REV_Bx (0x1 << CHIP_REV_SHIFT) +/* assume maximum 5 revisions */ +#define CHIP_REV_IS_SLOW(bp) (CHIP_REV_VAL(bp) > 0x00005000) +/* Emul versions are A=>0xe, B=>0xc, C=>0xa, D=>8, E=>6 */ +#define CHIP_REV_IS_EMUL(bp) ((CHIP_REV_IS_SLOW(bp)) && \ + !(CHIP_REV_VAL(bp) & 0x00001000)) +/* FPGA versions are A=>0xf, B=>0xd, C=>0xb, D=>9, E=>7 */ +#define CHIP_REV_IS_FPGA(bp) ((CHIP_REV_IS_SLOW(bp)) && \ + (CHIP_REV_VAL(bp) & 0x00001000)) + +#define CHIP_TIME(bp) ((CHIP_REV_IS_EMUL(bp)) ? 2000 : \ + ((CHIP_REV_IS_FPGA(bp)) ? 200 : 1)) + +#define CHIP_METAL(bp) (bp->common.chip_id & 0x00000ff0) +#define CHIP_BOND_ID(bp) (bp->common.chip_id & 0x0000000f) +#define CHIP_REV_SIM(bp) (((CHIP_REV_MASK - CHIP_REV_VAL(bp)) >>\ + (CHIP_REV_SHIFT + 1)) \ + << CHIP_REV_SHIFT) +#define CHIP_REV(bp) (CHIP_REV_IS_SLOW(bp) ? \ + CHIP_REV_SIM(bp) :\ + CHIP_REV_VAL(bp)) +#define CHIP_IS_E3B0(bp) (CHIP_IS_E3(bp) && \ + (CHIP_REV(bp) == CHIP_REV_Bx)) +#define CHIP_IS_E3A0(bp) (CHIP_IS_E3(bp) && \ + (CHIP_REV(bp) == CHIP_REV_Ax)) + + int flash_size; +#define BNX2X_NVRAM_1MB_SIZE 0x20000 /* 1M bit in bytes */ +#define BNX2X_NVRAM_TIMEOUT_COUNT 30000 +#define BNX2X_NVRAM_PAGE_SIZE 256 + + u32 shmem_base; + u32 shmem2_base; + u32 mf_cfg_base; + u32 mf2_cfg_base; + + u32 hw_config; + + u32 bc_ver; + + u8 int_block; +#define INT_BLOCK_HC 0 +#define INT_BLOCK_IGU 1 +#define INT_BLOCK_MODE_NORMAL 0 +#define INT_BLOCK_MODE_BW_COMP 2 +#define CHIP_INT_MODE_IS_NBC(bp) \ + (!CHIP_IS_E1x(bp) && \ + !((bp)->common.int_block & INT_BLOCK_MODE_BW_COMP)) +#define CHIP_INT_MODE_IS_BC(bp) (!CHIP_INT_MODE_IS_NBC(bp)) + + u8 chip_port_mode; +#define CHIP_4_PORT_MODE 0x0 +#define CHIP_2_PORT_MODE 0x1 +#define CHIP_PORT_MODE_NONE 0x2 +#define CHIP_MODE(bp) (bp->common.chip_port_mode) +#define CHIP_MODE_IS_4_PORT(bp) (CHIP_MODE(bp) == CHIP_4_PORT_MODE) +}; + +/* IGU MSIX STATISTICS on 57712: 64 for VFs; 4 for PFs; 4 for Attentions */ +#define BNX2X_IGU_STAS_MSG_VF_CNT 64 +#define BNX2X_IGU_STAS_MSG_PF_CNT 4 + +/* end of common */ + +/* port */ + +struct bnx2x_port { + u32 pmf; + + u32 link_config[LINK_CONFIG_SIZE]; + + u32 supported[LINK_CONFIG_SIZE]; +/* link settings - missing defines */ +#define SUPPORTED_2500baseX_Full (1 << 15) + + u32 advertising[LINK_CONFIG_SIZE]; +/* link settings - missing defines */ +#define ADVERTISED_2500baseX_Full (1 << 15) + + u32 phy_addr; + + /* used to synchronize phy accesses */ + struct mutex phy_mutex; + int need_hw_lock; + + u32 port_stx; + + struct nig_stats old_nig_stats; +}; + +/* end of port */ + +#define STATS_OFFSET32(stat_name) \ + (offsetof(struct bnx2x_eth_stats, stat_name) / 4) + +/* slow path */ + +/* slow path work-queue */ +extern struct workqueue_struct *bnx2x_wq; + +#define BNX2X_MAX_NUM_OF_VFS 64 +#define BNX2X_VF_ID_INVALID 0xFF + +/* + * The total number of L2 queues, MSIX vectors and HW contexts (CIDs) is + * control by the number of fast-path status blocks supported by the + * device (HW/FW). Each fast-path status block (FP-SB) aka non-default + * status block represents an independent interrupts context that can + * serve a regular L2 networking queue. However special L2 queues such + * as the FCoE queue do not require a FP-SB and other components like + * the CNIC may consume FP-SB reducing the number of possible L2 queues + * + * If the maximum number of FP-SB available is X then: + * a. If CNIC is supported it consumes 1 FP-SB thus the max number of + * regular L2 queues is Y=X-1 + * b. in MF mode the actual number of L2 queues is Y= (X-1/MF_factor) + * c. If the FCoE L2 queue is supported the actual number of L2 queues + * is Y+1 + * d. The number of irqs (MSIX vectors) is either Y+1 (one extra for + * slow-path interrupts) or Y+2 if CNIC is supported (one additional + * FP interrupt context for the CNIC). + * e. The number of HW context (CID count) is always X or X+1 if FCoE + * L2 queue is supported. the cid for the FCoE L2 queue is always X. + */ + +/* fast-path interrupt contexts E1x */ +#define FP_SB_MAX_E1x 16 +/* fast-path interrupt contexts E2 */ +#define FP_SB_MAX_E2 HC_SB_MAX_SB_E2 + +union cdu_context { + struct eth_context eth; + char pad[1024]; +}; + +/* CDU host DB constants */ +#define CDU_ILT_PAGE_SZ_HW 3 +#define CDU_ILT_PAGE_SZ (8192 << CDU_ILT_PAGE_SZ_HW) /* 64K */ +#define ILT_PAGE_CIDS (CDU_ILT_PAGE_SZ / sizeof(union cdu_context)) + +#ifdef BCM_CNIC +#define CNIC_ISCSI_CID_MAX 256 +#define CNIC_FCOE_CID_MAX 2048 +#define CNIC_CID_MAX (CNIC_ISCSI_CID_MAX + CNIC_FCOE_CID_MAX) +#define CNIC_ILT_LINES DIV_ROUND_UP(CNIC_CID_MAX, ILT_PAGE_CIDS) +#endif + +#define QM_ILT_PAGE_SZ_HW 0 +#define QM_ILT_PAGE_SZ (4096 << QM_ILT_PAGE_SZ_HW) /* 4K */ +#define QM_CID_ROUND 1024 + +#ifdef BCM_CNIC +/* TM (timers) host DB constants */ +#define TM_ILT_PAGE_SZ_HW 0 +#define TM_ILT_PAGE_SZ (4096 << TM_ILT_PAGE_SZ_HW) /* 4K */ +/* #define TM_CONN_NUM (CNIC_STARTING_CID+CNIC_ISCSI_CXT_MAX) */ +#define TM_CONN_NUM 1024 +#define TM_ILT_SZ (8 * TM_CONN_NUM) +#define TM_ILT_LINES DIV_ROUND_UP(TM_ILT_SZ, TM_ILT_PAGE_SZ) + +/* SRC (Searcher) host DB constants */ +#define SRC_ILT_PAGE_SZ_HW 0 +#define SRC_ILT_PAGE_SZ (4096 << SRC_ILT_PAGE_SZ_HW) /* 4K */ +#define SRC_HASH_BITS 10 +#define SRC_CONN_NUM (1 << SRC_HASH_BITS) /* 1024 */ +#define SRC_ILT_SZ (sizeof(struct src_ent) * SRC_CONN_NUM) +#define SRC_T2_SZ SRC_ILT_SZ +#define SRC_ILT_LINES DIV_ROUND_UP(SRC_ILT_SZ, SRC_ILT_PAGE_SZ) + +#endif + +#define MAX_DMAE_C 8 + +/* DMA memory not used in fastpath */ +struct bnx2x_slowpath { + union { + struct mac_configuration_cmd e1x; + struct eth_classify_rules_ramrod_data e2; + } mac_rdata; + + + union { + struct tstorm_eth_mac_filter_config e1x; + struct eth_filter_rules_ramrod_data e2; + } rx_mode_rdata; + + union { + struct mac_configuration_cmd e1; + struct eth_multicast_rules_ramrod_data e2; + } mcast_rdata; + + struct eth_rss_update_ramrod_data rss_rdata; + + /* Queue State related ramrods are always sent under rtnl_lock */ + union { + struct client_init_ramrod_data init_data; + struct client_update_ramrod_data update_data; + } q_rdata; + + union { + struct function_start_data func_start; + /* pfc configuration for DCBX ramrod */ + struct flow_control_configuration pfc_config; + } func_rdata; + + /* used by dmae command executer */ + struct dmae_command dmae[MAX_DMAE_C]; + + u32 stats_comp; + union mac_stats mac_stats; + struct nig_stats nig_stats; + struct host_port_stats port_stats; + struct host_func_stats func_stats; + struct host_func_stats func_stats_base; + + u32 wb_comp; + u32 wb_data[4]; +}; + +#define bnx2x_sp(bp, var) (&bp->slowpath->var) +#define bnx2x_sp_mapping(bp, var) \ + (bp->slowpath_mapping + offsetof(struct bnx2x_slowpath, var)) + + +/* attn group wiring */ +#define MAX_DYNAMIC_ATTN_GRPS 8 + +struct attn_route { + u32 sig[5]; +}; + +struct iro { + u32 base; + u16 m1; + u16 m2; + u16 m3; + u16 size; +}; + +struct hw_context { + union cdu_context *vcxt; + dma_addr_t cxt_mapping; + size_t size; +}; + +/* forward */ +struct bnx2x_ilt; + + +enum bnx2x_recovery_state { + BNX2X_RECOVERY_DONE, + BNX2X_RECOVERY_INIT, + BNX2X_RECOVERY_WAIT, + BNX2X_RECOVERY_FAILED +}; + +/* + * Event queue (EQ or event ring) MC hsi + * NUM_EQ_PAGES and EQ_DESC_CNT_PAGE must be power of 2 + */ +#define NUM_EQ_PAGES 1 +#define EQ_DESC_CNT_PAGE (BCM_PAGE_SIZE / sizeof(union event_ring_elem)) +#define EQ_DESC_MAX_PAGE (EQ_DESC_CNT_PAGE - 1) +#define NUM_EQ_DESC (EQ_DESC_CNT_PAGE * NUM_EQ_PAGES) +#define EQ_DESC_MASK (NUM_EQ_DESC - 1) +#define MAX_EQ_AVAIL (EQ_DESC_MAX_PAGE * NUM_EQ_PAGES - 2) + +/* depends on EQ_DESC_CNT_PAGE being a power of 2 */ +#define NEXT_EQ_IDX(x) ((((x) & EQ_DESC_MAX_PAGE) == \ + (EQ_DESC_MAX_PAGE - 1)) ? (x) + 2 : (x) + 1) + +/* depends on the above and on NUM_EQ_PAGES being a power of 2 */ +#define EQ_DESC(x) ((x) & EQ_DESC_MASK) + +#define BNX2X_EQ_INDEX \ + (&bp->def_status_blk->sp_sb.\ + index_values[HC_SP_INDEX_EQ_CONS]) + +/* This is a data that will be used to create a link report message. + * We will keep the data used for the last link report in order + * to prevent reporting the same link parameters twice. + */ +struct bnx2x_link_report_data { + u16 line_speed; /* Effective line speed */ + unsigned long link_report_flags;/* BNX2X_LINK_REPORT_XXX flags */ +}; + +enum { + BNX2X_LINK_REPORT_FD, /* Full DUPLEX */ + BNX2X_LINK_REPORT_LINK_DOWN, + BNX2X_LINK_REPORT_RX_FC_ON, + BNX2X_LINK_REPORT_TX_FC_ON, +}; + +enum { + BNX2X_PORT_QUERY_IDX, + BNX2X_PF_QUERY_IDX, + BNX2X_FIRST_QUEUE_QUERY_IDX, +}; + +struct bnx2x_fw_stats_req { + struct stats_query_header hdr; + struct stats_query_entry query[STATS_QUERY_CMD_COUNT]; +}; + +struct bnx2x_fw_stats_data { + struct stats_counter storm_counters; + struct per_port_stats port; + struct per_pf_stats pf; + struct per_queue_stats queue_stats[1]; +}; + +/* Public slow path states */ +enum { + BNX2X_SP_RTNL_SETUP_TC, + BNX2X_SP_RTNL_TX_TIMEOUT, +}; + + +struct bnx2x { + /* Fields used in the tx and intr/napi performance paths + * are grouped together in the beginning of the structure + */ + struct bnx2x_fastpath *fp; + void __iomem *regview; + void __iomem *doorbells; + u16 db_size; + + u8 pf_num; /* absolute PF number */ + u8 pfid; /* per-path PF number */ + int base_fw_ndsb; /**/ +#define BP_PATH(bp) (CHIP_IS_E1x(bp) ? 0 : (bp->pf_num & 1)) +#define BP_PORT(bp) (bp->pfid & 1) +#define BP_FUNC(bp) (bp->pfid) +#define BP_ABS_FUNC(bp) (bp->pf_num) +#define BP_E1HVN(bp) (bp->pfid >> 1) +#define BP_VN(bp) (BP_E1HVN(bp)) /*remove when approved*/ +#define BP_L_ID(bp) (BP_E1HVN(bp) << 2) +#define BP_FW_MB_IDX(bp) (BP_PORT(bp) +\ + BP_VN(bp) * ((CHIP_IS_E1x(bp) || (CHIP_MODE_IS_4_PORT(bp))) ? 2 : 1)) + + struct net_device *dev; + struct pci_dev *pdev; + + const struct iro *iro_arr; +#define IRO (bp->iro_arr) + + enum bnx2x_recovery_state recovery_state; + int is_leader; + struct msix_entry *msix_table; + + int tx_ring_size; + +/* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */ +#define ETH_OVREHEAD (ETH_HLEN + 8 + 8) +#define ETH_MIN_PACKET_SIZE 60 +#define ETH_MAX_PACKET_SIZE 1500 +#define ETH_MAX_JUMBO_PACKET_SIZE 9600 + + /* Max supported alignment is 256 (8 shift) */ +#define BNX2X_RX_ALIGN_SHIFT ((L1_CACHE_SHIFT < 8) ? \ + L1_CACHE_SHIFT : 8) + /* FW use 2 Cache lines Alignment for start packet and size */ +#define BNX2X_FW_RX_ALIGN (2 << BNX2X_RX_ALIGN_SHIFT) +#define BNX2X_PXP_DRAM_ALIGN (BNX2X_RX_ALIGN_SHIFT - 5) + + struct host_sp_status_block *def_status_blk; +#define DEF_SB_IGU_ID 16 +#define DEF_SB_ID HC_SP_SB_ID + __le16 def_idx; + __le16 def_att_idx; + u32 attn_state; + struct attn_route attn_group[MAX_DYNAMIC_ATTN_GRPS]; + + /* slow path ring */ + struct eth_spe *spq; + dma_addr_t spq_mapping; + u16 spq_prod_idx; + struct eth_spe *spq_prod_bd; + struct eth_spe *spq_last_bd; + __le16 *dsb_sp_prod; + atomic_t cq_spq_left; /* ETH_XXX ramrods credit */ + /* used to synchronize spq accesses */ + spinlock_t spq_lock; + + /* event queue */ + union event_ring_elem *eq_ring; + dma_addr_t eq_mapping; + u16 eq_prod; + u16 eq_cons; + __le16 *eq_cons_sb; + atomic_t eq_spq_left; /* COMMON_XXX ramrods credit */ + + + + /* Counter for marking that there is a STAT_QUERY ramrod pending */ + u16 stats_pending; + /* Counter for completed statistics ramrods */ + u16 stats_comp; + + /* End of fields used in the performance code paths */ + + int panic; + int msg_enable; + + u32 flags; +#define PCIX_FLAG (1 << 0) +#define PCI_32BIT_FLAG (1 << 1) +#define ONE_PORT_FLAG (1 << 2) +#define NO_WOL_FLAG (1 << 3) +#define USING_DAC_FLAG (1 << 4) +#define USING_MSIX_FLAG (1 << 5) +#define USING_MSI_FLAG (1 << 6) +#define DISABLE_MSI_FLAG (1 << 7) +#define TPA_ENABLE_FLAG (1 << 8) +#define NO_MCP_FLAG (1 << 9) + +#define BP_NOMCP(bp) (bp->flags & NO_MCP_FLAG) +#define MF_FUNC_DIS (1 << 11) +#define OWN_CNIC_IRQ (1 << 12) +#define NO_ISCSI_OOO_FLAG (1 << 13) +#define NO_ISCSI_FLAG (1 << 14) +#define NO_FCOE_FLAG (1 << 15) + +#define NO_ISCSI(bp) ((bp)->flags & NO_ISCSI_FLAG) +#define NO_ISCSI_OOO(bp) ((bp)->flags & NO_ISCSI_OOO_FLAG) +#define NO_FCOE(bp) ((bp)->flags & NO_FCOE_FLAG) + + int pm_cap; + int mrrs; + + struct delayed_work sp_task; + struct delayed_work sp_rtnl_task; + + struct delayed_work period_task; + struct timer_list timer; + int current_interval; + + u16 fw_seq; + u16 fw_drv_pulse_wr_seq; + u32 func_stx; + + struct link_params link_params; + struct link_vars link_vars; + u32 link_cnt; + struct bnx2x_link_report_data last_reported_link; + + struct mdio_if_info mdio; + + struct bnx2x_common common; + struct bnx2x_port port; + + struct cmng_struct_per_port cmng; + u32 vn_weight_sum; + u32 mf_config[E1HVN_MAX]; + u32 mf2_config[E2_FUNC_MAX]; + u32 path_has_ovlan; /* E3 */ + u16 mf_ov; + u8 mf_mode; +#define IS_MF(bp) (bp->mf_mode != 0) +#define IS_MF_SI(bp) (bp->mf_mode == MULTI_FUNCTION_SI) +#define IS_MF_SD(bp) (bp->mf_mode == MULTI_FUNCTION_SD) + + u8 wol; + + int rx_ring_size; + + u16 tx_quick_cons_trip_int; + u16 tx_quick_cons_trip; + u16 tx_ticks_int; + u16 tx_ticks; + + u16 rx_quick_cons_trip_int; + u16 rx_quick_cons_trip; + u16 rx_ticks_int; + u16 rx_ticks; +/* Maximal coalescing timeout in us */ +#define BNX2X_MAX_COALESCE_TOUT (0xf0*12) + + u32 lin_cnt; + + u16 state; +#define BNX2X_STATE_CLOSED 0 +#define BNX2X_STATE_OPENING_WAIT4_LOAD 0x1000 +#define BNX2X_STATE_OPENING_WAIT4_PORT 0x2000 +#define BNX2X_STATE_OPEN 0x3000 +#define BNX2X_STATE_CLOSING_WAIT4_HALT 0x4000 +#define BNX2X_STATE_CLOSING_WAIT4_DELETE 0x5000 + +#define BNX2X_STATE_DIAG 0xe000 +#define BNX2X_STATE_ERROR 0xf000 + + int multi_mode; +#define BNX2X_MAX_PRIORITY 8 +#define BNX2X_MAX_ENTRIES_PER_PRI 16 +#define BNX2X_MAX_COS 3 +#define BNX2X_MAX_TX_COS 2 + int num_queues; + int disable_tpa; + + u32 rx_mode; +#define BNX2X_RX_MODE_NONE 0 +#define BNX2X_RX_MODE_NORMAL 1 +#define BNX2X_RX_MODE_ALLMULTI 2 +#define BNX2X_RX_MODE_PROMISC 3 +#define BNX2X_MAX_MULTICAST 64 + + u8 igu_dsb_id; + u8 igu_base_sb; + u8 igu_sb_cnt; + dma_addr_t def_status_blk_mapping; + + struct bnx2x_slowpath *slowpath; + dma_addr_t slowpath_mapping; + + /* Total number of FW statistics requests */ + u8 fw_stats_num; + + /* + * This is a memory buffer that will contain both statistics + * ramrod request and data. + */ + void *fw_stats; + dma_addr_t fw_stats_mapping; + + /* + * FW statistics request shortcut (points at the + * beginning of fw_stats buffer). + */ + struct bnx2x_fw_stats_req *fw_stats_req; + dma_addr_t fw_stats_req_mapping; + int fw_stats_req_sz; + + /* + * FW statistics data shortcut (points at the begining of + * fw_stats buffer + fw_stats_req_sz). + */ + struct bnx2x_fw_stats_data *fw_stats_data; + dma_addr_t fw_stats_data_mapping; + int fw_stats_data_sz; + + struct hw_context context; + + struct bnx2x_ilt *ilt; +#define BP_ILT(bp) ((bp)->ilt) +#define ILT_MAX_LINES 256 +/* + * Maximum supported number of RSS queues: number of IGU SBs minus one that goes + * to CNIC. + */ +#define BNX2X_MAX_RSS_COUNT(bp) ((bp)->igu_sb_cnt - CNIC_PRESENT) + +/* + * Maximum CID count that might be required by the bnx2x: + * Max Tss * Max_Tx_Multi_Cos + CNIC L2 Clients (FCoE and iSCSI related) + */ +#define BNX2X_L2_CID_COUNT(bp) (MAX_TXQS_PER_COS * BNX2X_MULTI_TX_COS +\ + NON_ETH_CONTEXT_USE + CNIC_PRESENT) +#define L2_ILT_LINES(bp) (DIV_ROUND_UP(BNX2X_L2_CID_COUNT(bp),\ + ILT_PAGE_CIDS)) +#define BNX2X_DB_SIZE(bp) (BNX2X_L2_CID_COUNT(bp) * (1 << BNX2X_DB_SHIFT)) + + int qm_cid_count; + + int dropless_fc; + +#ifdef BCM_CNIC + u32 cnic_flags; +#define BNX2X_CNIC_FLAG_MAC_SET 1 + void *t2; + dma_addr_t t2_mapping; + struct cnic_ops __rcu *cnic_ops; + void *cnic_data; + u32 cnic_tag; + struct cnic_eth_dev cnic_eth_dev; + union host_hc_status_block cnic_sb; + dma_addr_t cnic_sb_mapping; + struct eth_spe *cnic_kwq; + struct eth_spe *cnic_kwq_prod; + struct eth_spe *cnic_kwq_cons; + struct eth_spe *cnic_kwq_last; + u16 cnic_kwq_pending; + u16 cnic_spq_pending; + u8 fip_mac[ETH_ALEN]; + struct mutex cnic_mutex; + struct bnx2x_vlan_mac_obj iscsi_l2_mac_obj; + + /* Start index of the "special" (CNIC related) L2 cleints */ + u8 cnic_base_cl_id; +#endif + + int dmae_ready; + /* used to synchronize dmae accesses */ + spinlock_t dmae_lock; + + /* used to protect the FW mail box */ + struct mutex fw_mb_mutex; + + /* used to synchronize stats collecting */ + int stats_state; + + /* used for synchronization of concurrent threads statistics handling */ + spinlock_t stats_lock; + + /* used by dmae command loader */ + struct dmae_command stats_dmae; + int executer_idx; + + u16 stats_counter; + struct bnx2x_eth_stats eth_stats; + + struct z_stream_s *strm; + void *gunzip_buf; + dma_addr_t gunzip_mapping; + int gunzip_outlen; +#define FW_BUF_SIZE 0x8000 +#define GUNZIP_BUF(bp) (bp->gunzip_buf) +#define GUNZIP_PHYS(bp) (bp->gunzip_mapping) +#define GUNZIP_OUTLEN(bp) (bp->gunzip_outlen) + + struct raw_op *init_ops; + /* Init blocks offsets inside init_ops */ + u16 *init_ops_offsets; + /* Data blob - has 32 bit granularity */ + u32 *init_data; + u32 init_mode_flags; +#define INIT_MODE_FLAGS(bp) (bp->init_mode_flags) + /* Zipped PRAM blobs - raw data */ + const u8 *tsem_int_table_data; + const u8 *tsem_pram_data; + const u8 *usem_int_table_data; + const u8 *usem_pram_data; + const u8 *xsem_int_table_data; + const u8 *xsem_pram_data; + const u8 *csem_int_table_data; + const u8 *csem_pram_data; +#define INIT_OPS(bp) (bp->init_ops) +#define INIT_OPS_OFFSETS(bp) (bp->init_ops_offsets) +#define INIT_DATA(bp) (bp->init_data) +#define INIT_TSEM_INT_TABLE_DATA(bp) (bp->tsem_int_table_data) +#define INIT_TSEM_PRAM_DATA(bp) (bp->tsem_pram_data) +#define INIT_USEM_INT_TABLE_DATA(bp) (bp->usem_int_table_data) +#define INIT_USEM_PRAM_DATA(bp) (bp->usem_pram_data) +#define INIT_XSEM_INT_TABLE_DATA(bp) (bp->xsem_int_table_data) +#define INIT_XSEM_PRAM_DATA(bp) (bp->xsem_pram_data) +#define INIT_CSEM_INT_TABLE_DATA(bp) (bp->csem_int_table_data) +#define INIT_CSEM_PRAM_DATA(bp) (bp->csem_pram_data) + +#define PHY_FW_VER_LEN 20 + char fw_ver[32]; + const struct firmware *firmware; + + /* DCB support on/off */ + u16 dcb_state; +#define BNX2X_DCB_STATE_OFF 0 +#define BNX2X_DCB_STATE_ON 1 + + /* DCBX engine mode */ + int dcbx_enabled; +#define BNX2X_DCBX_ENABLED_OFF 0 +#define BNX2X_DCBX_ENABLED_ON_NEG_OFF 1 +#define BNX2X_DCBX_ENABLED_ON_NEG_ON 2 +#define BNX2X_DCBX_ENABLED_INVALID (-1) + + bool dcbx_mode_uset; + + struct bnx2x_config_dcbx_params dcbx_config_params; + struct bnx2x_dcbx_port_params dcbx_port_params; + int dcb_version; + + /* CAM credit pools */ + struct bnx2x_credit_pool_obj macs_pool; + + /* RX_MODE object */ + struct bnx2x_rx_mode_obj rx_mode_obj; + + /* MCAST object */ + struct bnx2x_mcast_obj mcast_obj; + + /* RSS configuration object */ + struct bnx2x_rss_config_obj rss_conf_obj; + + /* Function State controlling object */ + struct bnx2x_func_sp_obj func_obj; + + unsigned long sp_state; + + /* operation indication for the sp_rtnl task */ + unsigned long sp_rtnl_state; + + /* DCBX Negotation results */ + struct dcbx_features dcbx_local_feat; + u32 dcbx_error; + +#ifdef BCM_DCBNL + struct dcbx_features dcbx_remote_feat; + u32 dcbx_remote_flags; +#endif + u32 pending_max; + + /* multiple tx classes of service */ + u8 max_cos; + + /* priority to cos mapping */ + u8 prio_to_cos[8]; +}; + +/* Tx queues may be less or equal to Rx queues */ +extern int num_queues; +#define BNX2X_NUM_QUEUES(bp) (bp->num_queues) +#define BNX2X_NUM_ETH_QUEUES(bp) (BNX2X_NUM_QUEUES(bp) - NON_ETH_CONTEXT_USE) +#define BNX2X_NUM_RX_QUEUES(bp) BNX2X_NUM_QUEUES(bp) + +#define is_multi(bp) (BNX2X_NUM_QUEUES(bp) > 1) + +#define BNX2X_MAX_QUEUES(bp) BNX2X_MAX_RSS_COUNT(bp) +/* #define is_eth_multi(bp) (BNX2X_NUM_ETH_QUEUES(bp) > 1) */ + +#define RSS_IPV4_CAP_MASK \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY + +#define RSS_IPV4_TCP_CAP_MASK \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY + +#define RSS_IPV6_CAP_MASK \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY + +#define RSS_IPV6_TCP_CAP_MASK \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY + +/* func init flags */ +#define FUNC_FLG_RSS 0x0001 +#define FUNC_FLG_STATS 0x0002 +/* removed FUNC_FLG_UNMATCHED 0x0004 */ +#define FUNC_FLG_TPA 0x0008 +#define FUNC_FLG_SPQ 0x0010 +#define FUNC_FLG_LEADING 0x0020 /* PF only */ + + +struct bnx2x_func_init_params { + /* dma */ + dma_addr_t fw_stat_map; /* valid iff FUNC_FLG_STATS */ + dma_addr_t spq_map; /* valid iff FUNC_FLG_SPQ */ + + u16 func_flgs; + u16 func_id; /* abs fid */ + u16 pf_id; + u16 spq_prod; /* valid iff FUNC_FLG_SPQ */ +}; + +#define for_each_eth_queue(bp, var) \ + for ((var) = 0; (var) < BNX2X_NUM_ETH_QUEUES(bp); (var)++) + +#define for_each_nondefault_eth_queue(bp, var) \ + for ((var) = 1; (var) < BNX2X_NUM_ETH_QUEUES(bp); (var)++) + +#define for_each_queue(bp, var) \ + for ((var) = 0; (var) < BNX2X_NUM_QUEUES(bp); (var)++) \ + if (skip_queue(bp, var)) \ + continue; \ + else + +/* Skip forwarding FP */ +#define for_each_rx_queue(bp, var) \ + for ((var) = 0; (var) < BNX2X_NUM_QUEUES(bp); (var)++) \ + if (skip_rx_queue(bp, var)) \ + continue; \ + else + +/* Skip OOO FP */ +#define for_each_tx_queue(bp, var) \ + for ((var) = 0; (var) < BNX2X_NUM_QUEUES(bp); (var)++) \ + if (skip_tx_queue(bp, var)) \ + continue; \ + else + +#define for_each_nondefault_queue(bp, var) \ + for ((var) = 1; (var) < BNX2X_NUM_QUEUES(bp); (var)++) \ + if (skip_queue(bp, var)) \ + continue; \ + else + +#define for_each_cos_in_tx_queue(fp, var) \ + for ((var) = 0; (var) < (fp)->max_cos; (var)++) + +/* skip rx queue + * if FCOE l2 support is disabled and this is the fcoe L2 queue + */ +#define skip_rx_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx)) + +/* skip tx queue + * if FCOE l2 support is disabled and this is the fcoe L2 queue + */ +#define skip_tx_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx)) + +#define skip_queue(bp, idx) (NO_FCOE(bp) && IS_FCOE_IDX(idx)) + + + + +/** + * bnx2x_set_mac_one - configure a single MAC address + * + * @bp: driver handle + * @mac: MAC to configure + * @obj: MAC object handle + * @set: if 'true' add a new MAC, otherwise - delete + * @mac_type: the type of the MAC to configure (e.g. ETH, UC list) + * @ramrod_flags: RAMROD_XXX flags (e.g. RAMROD_CONT, RAMROD_COMP_WAIT) + * + * Configures one MAC according to provided parameters or continues the + * execution of previously scheduled commands if RAMROD_CONT is set in + * ramrod_flags. + * + * Returns zero if operation has successfully completed, a positive value if the + * operation has been successfully scheduled and a negative - if a requested + * operations has failed. + */ +int bnx2x_set_mac_one(struct bnx2x *bp, u8 *mac, + struct bnx2x_vlan_mac_obj *obj, bool set, + int mac_type, unsigned long *ramrod_flags); +/** + * Deletes all MACs configured for the specific MAC object. + * + * @param bp Function driver instance + * @param mac_obj MAC object to cleanup + * + * @return zero if all MACs were cleaned + */ + +/** + * bnx2x_del_all_macs - delete all MACs configured for the specific MAC object + * + * @bp: driver handle + * @mac_obj: MAC object handle + * @mac_type: type of the MACs to clear (BNX2X_XXX_MAC) + * @wait_for_comp: if 'true' block until completion + * + * Deletes all MACs of the specific type (e.g. ETH, UC list). + * + * Returns zero if operation has successfully completed, a positive value if the + * operation has been successfully scheduled and a negative - if a requested + * operations has failed. + */ +int bnx2x_del_all_macs(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *mac_obj, + int mac_type, bool wait_for_comp); + +/* Init Function API */ +void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p); +int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port); +int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); +int bnx2x_set_mult_gpio(struct bnx2x *bp, u8 pins, u32 mode); +int bnx2x_set_gpio_int(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); +void bnx2x_read_mf_cfg(struct bnx2x *bp); + + +/* dmae */ +void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32); +void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr, + u32 len32); +void bnx2x_post_dmae(struct bnx2x *bp, struct dmae_command *dmae, int idx); +u32 bnx2x_dmae_opcode_add_comp(u32 opcode, u8 comp_type); +u32 bnx2x_dmae_opcode_clr_src_reset(u32 opcode); +u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type, + bool with_comp, u8 comp_type); + + +void bnx2x_calc_fc_adv(struct bnx2x *bp); +int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, + u32 data_hi, u32 data_lo, int cmd_type); +void bnx2x_update_coalesce(struct bnx2x *bp); +int bnx2x_get_cur_phy_idx(struct bnx2x *bp); + +static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms, + int wait) +{ + u32 val; + + do { + val = REG_RD(bp, reg); + if (val == expected) + break; + ms -= wait; + msleep(wait); + + } while (ms > 0); + + return val; +} + +#define BNX2X_ILT_ZALLOC(x, y, size) \ + do { \ + x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ + if (x) \ + memset(x, 0, size); \ + } while (0) + +#define BNX2X_ILT_FREE(x, y, size) \ + do { \ + if (x) { \ + dma_free_coherent(&bp->pdev->dev, size, x, y); \ + x = NULL; \ + y = 0; \ + } \ + } while (0) + +#define ILOG2(x) (ilog2((x))) + +#define ILT_NUM_PAGE_ENTRIES (3072) +/* In 57710/11 we use whole table since we have 8 func + * In 57712 we have only 4 func, but use same size per func, then only half of + * the table in use + */ +#define ILT_PER_FUNC (ILT_NUM_PAGE_ENTRIES/8) + +#define FUNC_ILT_BASE(func) (func * ILT_PER_FUNC) +/* + * the phys address is shifted right 12 bits and has an added + * 1=valid bit added to the 53rd bit + * then since this is a wide register(TM) + * we split it into two 32 bit writes + */ +#define ONCHIP_ADDR1(x) ((u32)(((u64)x >> 12) & 0xFFFFFFFF)) +#define ONCHIP_ADDR2(x) ((u32)((1 << 20) | ((u64)x >> 44))) + +/* load/unload mode */ +#define LOAD_NORMAL 0 +#define LOAD_OPEN 1 +#define LOAD_DIAG 2 +#define UNLOAD_NORMAL 0 +#define UNLOAD_CLOSE 1 +#define UNLOAD_RECOVERY 2 + + +/* DMAE command defines */ +#define DMAE_TIMEOUT -1 +#define DMAE_PCI_ERROR -2 /* E2 and onward */ +#define DMAE_NOT_RDY -3 +#define DMAE_PCI_ERR_FLAG 0x80000000 + +#define DMAE_SRC_PCI 0 +#define DMAE_SRC_GRC 1 + +#define DMAE_DST_NONE 0 +#define DMAE_DST_PCI 1 +#define DMAE_DST_GRC 2 + +#define DMAE_COMP_PCI 0 +#define DMAE_COMP_GRC 1 + +/* E2 and onward - PCI error handling in the completion */ + +#define DMAE_COMP_REGULAR 0 +#define DMAE_COM_SET_ERR 1 + +#define DMAE_CMD_SRC_PCI (DMAE_SRC_PCI << \ + DMAE_COMMAND_SRC_SHIFT) +#define DMAE_CMD_SRC_GRC (DMAE_SRC_GRC << \ + DMAE_COMMAND_SRC_SHIFT) + +#define DMAE_CMD_DST_PCI (DMAE_DST_PCI << \ + DMAE_COMMAND_DST_SHIFT) +#define DMAE_CMD_DST_GRC (DMAE_DST_GRC << \ + DMAE_COMMAND_DST_SHIFT) + +#define DMAE_CMD_C_DST_PCI (DMAE_COMP_PCI << \ + DMAE_COMMAND_C_DST_SHIFT) +#define DMAE_CMD_C_DST_GRC (DMAE_COMP_GRC << \ + DMAE_COMMAND_C_DST_SHIFT) + +#define DMAE_CMD_C_ENABLE DMAE_COMMAND_C_TYPE_ENABLE + +#define DMAE_CMD_ENDIANITY_NO_SWAP (0 << DMAE_COMMAND_ENDIANITY_SHIFT) +#define DMAE_CMD_ENDIANITY_B_SWAP (1 << DMAE_COMMAND_ENDIANITY_SHIFT) +#define DMAE_CMD_ENDIANITY_DW_SWAP (2 << DMAE_COMMAND_ENDIANITY_SHIFT) +#define DMAE_CMD_ENDIANITY_B_DW_SWAP (3 << DMAE_COMMAND_ENDIANITY_SHIFT) + +#define DMAE_CMD_PORT_0 0 +#define DMAE_CMD_PORT_1 DMAE_COMMAND_PORT + +#define DMAE_CMD_SRC_RESET DMAE_COMMAND_SRC_RESET +#define DMAE_CMD_DST_RESET DMAE_COMMAND_DST_RESET +#define DMAE_CMD_E1HVN_SHIFT DMAE_COMMAND_E1HVN_SHIFT + +#define DMAE_SRC_PF 0 +#define DMAE_SRC_VF 1 + +#define DMAE_DST_PF 0 +#define DMAE_DST_VF 1 + +#define DMAE_C_SRC 0 +#define DMAE_C_DST 1 + +#define DMAE_LEN32_RD_MAX 0x80 +#define DMAE_LEN32_WR_MAX(bp) (CHIP_IS_E1(bp) ? 0x400 : 0x2000) + +#define DMAE_COMP_VAL 0x60d0d0ae /* E2 and on - upper bit + indicates eror */ + +#define MAX_DMAE_C_PER_PORT 8 +#define INIT_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \ + BP_E1HVN(bp)) +#define PMF_DMAE_C(bp) (BP_PORT(bp) * MAX_DMAE_C_PER_PORT + \ + E1HVN_MAX) + +/* PCIE link and speed */ +#define PCICFG_LINK_WIDTH 0x1f00000 +#define PCICFG_LINK_WIDTH_SHIFT 20 +#define PCICFG_LINK_SPEED 0xf0000 +#define PCICFG_LINK_SPEED_SHIFT 16 + + +#define BNX2X_NUM_TESTS 7 + +#define BNX2X_PHY_LOOPBACK 0 +#define BNX2X_MAC_LOOPBACK 1 +#define BNX2X_PHY_LOOPBACK_FAILED 1 +#define BNX2X_MAC_LOOPBACK_FAILED 2 +#define BNX2X_LOOPBACK_FAILED (BNX2X_MAC_LOOPBACK_FAILED | \ + BNX2X_PHY_LOOPBACK_FAILED) + + +#define STROM_ASSERT_ARRAY_SIZE 50 + + +/* must be used on a CID before placing it on a HW ring */ +#define HW_CID(bp, x) ((BP_PORT(bp) << 23) | \ + (BP_E1HVN(bp) << BNX2X_SWCID_SHIFT) | \ + (x)) + +#define SP_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct eth_spe)) +#define MAX_SP_DESC_CNT (SP_DESC_CNT - 1) + + +#define BNX2X_BTR 4 +#define MAX_SPQ_PENDING 8 + +/* CMNG constants, as derived from system spec calculations */ +/* default MIN rate in case VNIC min rate is configured to zero - 100Mbps */ +#define DEF_MIN_RATE 100 +/* resolution of the rate shaping timer - 400 usec */ +#define RS_PERIODIC_TIMEOUT_USEC 400 +/* number of bytes in single QM arbitration cycle - + * coefficient for calculating the fairness timer */ +#define QM_ARB_BYTES 160000 +/* resolution of Min algorithm 1:100 */ +#define MIN_RES 100 +/* how many bytes above threshold for the minimal credit of Min algorithm*/ +#define MIN_ABOVE_THRESH 32768 +/* Fairness algorithm integration time coefficient - + * for calculating the actual Tfair */ +#define T_FAIR_COEF ((MIN_ABOVE_THRESH + QM_ARB_BYTES) * 8 * MIN_RES) +/* Memory of fairness algorithm . 2 cycles */ +#define FAIR_MEM 2 + + +#define ATTN_NIG_FOR_FUNC (1L << 8) +#define ATTN_SW_TIMER_4_FUNC (1L << 9) +#define GPIO_2_FUNC (1L << 10) +#define GPIO_3_FUNC (1L << 11) +#define GPIO_4_FUNC (1L << 12) +#define ATTN_GENERAL_ATTN_1 (1L << 13) +#define ATTN_GENERAL_ATTN_2 (1L << 14) +#define ATTN_GENERAL_ATTN_3 (1L << 15) +#define ATTN_GENERAL_ATTN_4 (1L << 13) +#define ATTN_GENERAL_ATTN_5 (1L << 14) +#define ATTN_GENERAL_ATTN_6 (1L << 15) + +#define ATTN_HARD_WIRED_MASK 0xff00 +#define ATTENTION_ID 4 + + +/* stuff added to make the code fit 80Col */ + +#define BNX2X_PMF_LINK_ASSERT \ + GENERAL_ATTEN_OFFSET(LINK_SYNC_ATTENTION_BIT_FUNC_0 + BP_FUNC(bp)) + +#define BNX2X_MC_ASSERT_BITS \ + (GENERAL_ATTEN_OFFSET(TSTORM_FATAL_ASSERT_ATTENTION_BIT) | \ + GENERAL_ATTEN_OFFSET(USTORM_FATAL_ASSERT_ATTENTION_BIT) | \ + GENERAL_ATTEN_OFFSET(CSTORM_FATAL_ASSERT_ATTENTION_BIT) | \ + GENERAL_ATTEN_OFFSET(XSTORM_FATAL_ASSERT_ATTENTION_BIT)) + +#define BNX2X_MCP_ASSERT \ + GENERAL_ATTEN_OFFSET(MCP_FATAL_ASSERT_ATTENTION_BIT) + +#define BNX2X_GRC_TIMEOUT GENERAL_ATTEN_OFFSET(LATCHED_ATTN_TIMEOUT_GRC) +#define BNX2X_GRC_RSV (GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCR) | \ + GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCT) | \ + GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCN) | \ + GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCU) | \ + GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RBCP) | \ + GENERAL_ATTEN_OFFSET(LATCHED_ATTN_RSVD_GRC)) + +#define HW_INTERRUT_ASSERT_SET_0 \ + (AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_PBCLIENT_HW_INTERRUPT) +#define HW_PRTY_ASSERT_SET_0 (AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_TCM_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR) +#define HW_INTERRUT_ASSERT_SET_1 \ + (AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_TIMERS_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_XSDM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_XCM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_XSEMI_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_USDM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_UCM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_USEMI_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_UPB_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_CSDM_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT) +#define HW_PRTY_ASSERT_SET_1 (AEU_INPUTS_ATTN_BITS_PBF_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_TIMERS_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_XCM_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_NIG_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_UCM_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_CCM_PARITY_ERROR) +#define HW_INTERRUT_ASSERT_SET_2 \ + (AEU_INPUTS_ATTN_BITS_CSEMI_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_CDU_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT | \ + AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_HW_INTERRUPT |\ + AEU_INPUTS_ATTN_BITS_MISC_HW_INTERRUPT) +#define HW_PRTY_ASSERT_SET_2 (AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_DMAE_PARITY_ERROR |\ + AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR) + +#define HW_PRTY_ASSERT_SET_3 (AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY | \ + AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY | \ + AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY | \ + AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY) + +#define HW_PRTY_ASSERT_SET_4 (AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR | \ + AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR) + +#define RSS_FLAGS(bp) \ + (TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY | \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY | \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY | \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY | \ + (bp->multi_mode << \ + TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE_SHIFT)) +#define MULTI_MASK 0x7f + + +#define DEF_USB_FUNC_OFF offsetof(struct cstorm_def_status_block_u, func) +#define DEF_CSB_FUNC_OFF offsetof(struct cstorm_def_status_block_c, func) +#define DEF_XSB_FUNC_OFF offsetof(struct xstorm_def_status_block, func) +#define DEF_TSB_FUNC_OFF offsetof(struct tstorm_def_status_block, func) + +#define DEF_USB_IGU_INDEX_OFF \ + offsetof(struct cstorm_def_status_block_u, igu_index) +#define DEF_CSB_IGU_INDEX_OFF \ + offsetof(struct cstorm_def_status_block_c, igu_index) +#define DEF_XSB_IGU_INDEX_OFF \ + offsetof(struct xstorm_def_status_block, igu_index) +#define DEF_TSB_IGU_INDEX_OFF \ + offsetof(struct tstorm_def_status_block, igu_index) + +#define DEF_USB_SEGMENT_OFF \ + offsetof(struct cstorm_def_status_block_u, segment) +#define DEF_CSB_SEGMENT_OFF \ + offsetof(struct cstorm_def_status_block_c, segment) +#define DEF_XSB_SEGMENT_OFF \ + offsetof(struct xstorm_def_status_block, segment) +#define DEF_TSB_SEGMENT_OFF \ + offsetof(struct tstorm_def_status_block, segment) + +#define BNX2X_SP_DSB_INDEX \ + (&bp->def_status_blk->sp_sb.\ + index_values[HC_SP_INDEX_ETH_DEF_CONS]) + +#define SET_FLAG(value, mask, flag) \ + do {\ + (value) &= ~(mask);\ + (value) |= ((flag) << (mask##_SHIFT));\ + } while (0) + +#define GET_FLAG(value, mask) \ + (((value) & (mask)) >> (mask##_SHIFT)) + +#define GET_FIELD(value, fname) \ + (((value) & (fname##_MASK)) >> (fname##_SHIFT)) + +#define CAM_IS_INVALID(x) \ + (GET_FLAG(x.flags, \ + MAC_CONFIGURATION_ENTRY_ACTION_TYPE) == \ + (T_ETH_MAC_COMMAND_INVALIDATE)) + +/* Number of u32 elements in MC hash array */ +#define MC_HASH_SIZE 8 +#define MC_HASH_OFFSET(bp, i) (BAR_TSTRORM_INTMEM + \ + TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(BP_FUNC(bp)) + i*4) + + +#ifndef PXP2_REG_PXP2_INT_STS +#define PXP2_REG_PXP2_INT_STS PXP2_REG_PXP2_INT_STS_0 +#endif + +#ifndef ETH_MAX_RX_CLIENTS_E2 +#define ETH_MAX_RX_CLIENTS_E2 ETH_MAX_RX_CLIENTS_E1H +#endif + +#define BNX2X_VPD_LEN 128 +#define VENDOR_ID_LEN 4 + +/* Congestion management fairness mode */ +#define CMNG_FNS_NONE 0 +#define CMNG_FNS_MINMAX 1 + +#define HC_SEG_ACCESS_DEF 0 /*Driver decision 0-3*/ +#define HC_SEG_ACCESS_ATTN 4 +#define HC_SEG_ACCESS_NORM 0 /*Driver decision 0-1*/ + +static 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 +}; + +void bnx2x_set_ethtool_ops(struct net_device *netdev); +void bnx2x_notify_link_changed(struct bnx2x *bp); +#endif /* bnx2x.h */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c new file mode 100644 index 000000000000..d724a18b5285 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -0,0 +1,3571 @@ +/* bnx2x_cmn.c: Broadcom Everest network driver. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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: Eilon Greenstein + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "bnx2x_cmn.h" +#include "bnx2x_init.h" +#include "bnx2x_sp.h" + + + +/** + * bnx2x_bz_fp - zero content of the fastpath structure. + * + * @bp: driver handle + * @index: fastpath index to be zeroed + * + * Makes sure the contents of the bp->fp[index].napi is kept + * intact. + */ +static inline void bnx2x_bz_fp(struct bnx2x *bp, int index) +{ + struct bnx2x_fastpath *fp = &bp->fp[index]; + struct napi_struct orig_napi = fp->napi; + /* bzero bnx2x_fastpath contents */ + memset(fp, 0, sizeof(*fp)); + + /* Restore the NAPI object as it has been already initialized */ + fp->napi = orig_napi; + + fp->bp = bp; + fp->index = index; + if (IS_ETH_FP(fp)) + fp->max_cos = bp->max_cos; + else + /* Special queues support only one CoS */ + fp->max_cos = 1; + + /* + * set the tpa flag for each queue. The tpa flag determines the queue + * minimal size so it must be set prior to queue memory allocation + */ + fp->disable_tpa = ((bp->flags & TPA_ENABLE_FLAG) == 0); + +#ifdef BCM_CNIC + /* We don't want TPA on FCoE, FWD and OOO L2 rings */ + bnx2x_fcoe(bp, disable_tpa) = 1; +#endif +} + +/** + * bnx2x_move_fp - move content of the fastpath structure. + * + * @bp: driver handle + * @from: source FP index + * @to: destination FP index + * + * Makes sure the contents of the bp->fp[to].napi is kept + * intact. + */ +static inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to) +{ + struct bnx2x_fastpath *from_fp = &bp->fp[from]; + struct bnx2x_fastpath *to_fp = &bp->fp[to]; + struct napi_struct orig_napi = to_fp->napi; + /* Move bnx2x_fastpath contents */ + memcpy(to_fp, from_fp, sizeof(*to_fp)); + to_fp->index = to; + + /* Restore the NAPI object as it has been already initialized */ + to_fp->napi = orig_napi; +} + +int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */ + +/* free skb in the packet ring at pos idx + * return idx of last bd freed + */ +static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, + u16 idx) +{ + struct sw_tx_bd *tx_buf = &txdata->tx_buf_ring[idx]; + struct eth_tx_start_bd *tx_start_bd; + struct eth_tx_bd *tx_data_bd; + struct sk_buff *skb = tx_buf->skb; + u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons; + int nbd; + + /* prefetch skb end pointer to speedup dev_kfree_skb() */ + prefetch(&skb->end); + + DP(BNX2X_MSG_FP, "fp[%d]: pkt_idx %d buff @(%p)->skb %p\n", + txdata->txq_index, idx, tx_buf, skb); + + /* unmap first bd */ + DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx); + tx_start_bd = &txdata->tx_desc_ring[bd_idx].start_bd; + dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd), + BD_UNMAP_LEN(tx_start_bd), DMA_TO_DEVICE); + + + nbd = le16_to_cpu(tx_start_bd->nbd) - 1; +#ifdef BNX2X_STOP_ON_ERROR + if ((nbd - 1) > (MAX_SKB_FRAGS + 2)) { + BNX2X_ERR("BAD nbd!\n"); + bnx2x_panic(); + } +#endif + new_cons = nbd + tx_buf->first_bd; + + /* Get the next bd */ + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + + /* Skip a parse bd... */ + --nbd; + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + + /* ...and the TSO split header bd since they have no mapping */ + if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) { + --nbd; + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + } + + /* now free frags */ + while (nbd > 0) { + + DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx); + tx_data_bd = &txdata->tx_desc_ring[bd_idx].reg_bd; + dma_unmap_page(&bp->pdev->dev, BD_UNMAP_ADDR(tx_data_bd), + BD_UNMAP_LEN(tx_data_bd), DMA_TO_DEVICE); + if (--nbd) + bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); + } + + /* release skb */ + WARN_ON(!skb); + dev_kfree_skb_any(skb); + tx_buf->first_bd = 0; + tx_buf->skb = NULL; + + return new_cons; +} + +int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata) +{ + struct netdev_queue *txq; + u16 hw_cons, sw_cons, bd_cons = txdata->tx_bd_cons; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return -1; +#endif + + txq = netdev_get_tx_queue(bp->dev, txdata->txq_index); + hw_cons = le16_to_cpu(*txdata->tx_cons_sb); + sw_cons = txdata->tx_pkt_cons; + + while (sw_cons != hw_cons) { + u16 pkt_cons; + + pkt_cons = TX_BD(sw_cons); + + DP(NETIF_MSG_TX_DONE, "queue[%d]: hw_cons %u sw_cons %u " + " pkt_cons %u\n", + txdata->txq_index, hw_cons, sw_cons, pkt_cons); + + bd_cons = bnx2x_free_tx_pkt(bp, txdata, pkt_cons); + sw_cons++; + } + + txdata->tx_pkt_cons = sw_cons; + txdata->tx_bd_cons = bd_cons; + + /* Need to make the tx_bd_cons update visible to start_xmit() + * before checking for netif_tx_queue_stopped(). Without the + * memory barrier, there is a small possibility that + * start_xmit() will miss it and cause the queue to be stopped + * forever. + * On the other hand we need an rmb() here to ensure the proper + * ordering of bit testing in the following + * netif_tx_queue_stopped(txq) call. + */ + smp_mb(); + + if (unlikely(netif_tx_queue_stopped(txq))) { + /* Taking tx_lock() is needed to prevent reenabling the queue + * while it's empty. This could have happen if rx_action() gets + * suspended in bnx2x_tx_int() after the condition before + * netif_tx_wake_queue(), while tx_action (bnx2x_start_xmit()): + * + * stops the queue->sees fresh tx_bd_cons->releases the queue-> + * sends some packets consuming the whole queue again-> + * stops the queue + */ + + __netif_tx_lock(txq, smp_processor_id()); + + if ((netif_tx_queue_stopped(txq)) && + (bp->state == BNX2X_STATE_OPEN) && + (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 3)) + netif_tx_wake_queue(txq); + + __netif_tx_unlock(txq); + } + return 0; +} + +static inline void bnx2x_update_last_max_sge(struct bnx2x_fastpath *fp, + u16 idx) +{ + u16 last_max = fp->last_max_sge; + + if (SUB_S16(idx, last_max) > 0) + fp->last_max_sge = idx; +} + +static void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp, + struct eth_fast_path_rx_cqe *fp_cqe) +{ + struct bnx2x *bp = fp->bp; + u16 sge_len = SGE_PAGE_ALIGN(le16_to_cpu(fp_cqe->pkt_len) - + le16_to_cpu(fp_cqe->len_on_bd)) >> + SGE_PAGE_SHIFT; + u16 last_max, last_elem, first_elem; + u16 delta = 0; + u16 i; + + if (!sge_len) + return; + + /* First mark all used pages */ + for (i = 0; i < sge_len; i++) + BIT_VEC64_CLEAR_BIT(fp->sge_mask, + RX_SGE(le16_to_cpu(fp_cqe->sgl_or_raw_data.sgl[i]))); + + DP(NETIF_MSG_RX_STATUS, "fp_cqe->sgl[%d] = %d\n", + sge_len - 1, le16_to_cpu(fp_cqe->sgl_or_raw_data.sgl[sge_len - 1])); + + /* Here we assume that the last SGE index is the biggest */ + prefetch((void *)(fp->sge_mask)); + bnx2x_update_last_max_sge(fp, + le16_to_cpu(fp_cqe->sgl_or_raw_data.sgl[sge_len - 1])); + + last_max = RX_SGE(fp->last_max_sge); + last_elem = last_max >> BIT_VEC64_ELEM_SHIFT; + first_elem = RX_SGE(fp->rx_sge_prod) >> BIT_VEC64_ELEM_SHIFT; + + /* If ring is not full */ + if (last_elem + 1 != first_elem) + last_elem++; + + /* Now update the prod */ + for (i = first_elem; i != last_elem; i = NEXT_SGE_MASK_ELEM(i)) { + if (likely(fp->sge_mask[i])) + break; + + fp->sge_mask[i] = BIT_VEC64_ELEM_ONE_MASK; + delta += BIT_VEC64_ELEM_SZ; + } + + if (delta > 0) { + fp->rx_sge_prod += delta; + /* clear page-end entries */ + bnx2x_clear_sge_mask_next_elems(fp); + } + + DP(NETIF_MSG_RX_STATUS, + "fp->last_max_sge = %d fp->rx_sge_prod = %d\n", + fp->last_max_sge, fp->rx_sge_prod); +} + +static void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue, + struct sk_buff *skb, u16 cons, u16 prod, + struct eth_fast_path_rx_cqe *cqe) +{ + struct bnx2x *bp = fp->bp; + struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons]; + struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod]; + struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod]; + dma_addr_t mapping; + struct bnx2x_agg_info *tpa_info = &fp->tpa_info[queue]; + struct sw_rx_bd *first_buf = &tpa_info->first_buf; + + /* print error if current state != stop */ + if (tpa_info->tpa_state != BNX2X_TPA_STOP) + BNX2X_ERR("start of bin not in stop [%d]\n", queue); + + /* Try to map an empty skb from the aggregation info */ + mapping = dma_map_single(&bp->pdev->dev, + first_buf->skb->data, + fp->rx_buf_size, DMA_FROM_DEVICE); + /* + * ...if it fails - move the skb from the consumer to the producer + * and set the current aggregation state as ERROR to drop it + * when TPA_STOP arrives. + */ + + if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { + /* Move the BD from the consumer to the producer */ + bnx2x_reuse_rx_skb(fp, cons, prod); + tpa_info->tpa_state = BNX2X_TPA_ERROR; + return; + } + + /* move empty skb from pool to prod */ + prod_rx_buf->skb = first_buf->skb; + dma_unmap_addr_set(prod_rx_buf, mapping, mapping); + /* point prod_bd to new skb */ + prod_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + prod_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + + /* move partial skb from cons to pool (don't unmap yet) */ + *first_buf = *cons_rx_buf; + + /* mark bin state as START */ + tpa_info->parsing_flags = + le16_to_cpu(cqe->pars_flags.flags); + tpa_info->vlan_tag = le16_to_cpu(cqe->vlan_tag); + tpa_info->tpa_state = BNX2X_TPA_START; + tpa_info->len_on_bd = le16_to_cpu(cqe->len_on_bd); + tpa_info->placement_offset = cqe->placement_offset; + +#ifdef BNX2X_STOP_ON_ERROR + fp->tpa_queue_used |= (1 << queue); +#ifdef _ASM_GENERIC_INT_L64_H + DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%lx\n", +#else + DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n", +#endif + fp->tpa_queue_used); +#endif +} + +/* Timestamp option length allowed for TPA aggregation: + * + * nop nop kind length echo val + */ +#define TPA_TSTAMP_OPT_LEN 12 +/** + * bnx2x_set_lro_mss - calculate the approximate value of the MSS + * + * @bp: driver handle + * @parsing_flags: parsing flags from the START CQE + * @len_on_bd: total length of the first packet for the + * aggregation. + * + * Approximate value of the MSS for this aggregation calculated using + * the first packet of it. + */ +static inline u16 bnx2x_set_lro_mss(struct bnx2x *bp, u16 parsing_flags, + u16 len_on_bd) +{ + /* + * TPA arrgregation won't have either IP options or TCP options + * other than timestamp or IPv6 extension headers. + */ + u16 hdrs_len = ETH_HLEN + sizeof(struct tcphdr); + + if (GET_FLAG(parsing_flags, PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) == + PRS_FLAG_OVERETH_IPV6) + hdrs_len += sizeof(struct ipv6hdr); + else /* IPv4 */ + hdrs_len += sizeof(struct iphdr); + + + /* Check if there was a TCP timestamp, if there is it's will + * always be 12 bytes length: nop nop kind length echo val. + * + * Otherwise FW would close the aggregation. + */ + if (parsing_flags & PARSING_FLAGS_TIME_STAMP_EXIST_FLAG) + hdrs_len += TPA_TSTAMP_OPT_LEN; + + return len_on_bd - hdrs_len; +} + +static int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp, + u16 queue, struct sk_buff *skb, + struct eth_end_agg_rx_cqe *cqe, + u16 cqe_idx) +{ + struct sw_rx_page *rx_pg, old_rx_pg; + u32 i, frag_len, frag_size, pages; + int err; + int j; + struct bnx2x_agg_info *tpa_info = &fp->tpa_info[queue]; + u16 len_on_bd = tpa_info->len_on_bd; + + frag_size = le16_to_cpu(cqe->pkt_len) - len_on_bd; + pages = SGE_PAGE_ALIGN(frag_size) >> SGE_PAGE_SHIFT; + + /* This is needed in order to enable forwarding support */ + if (frag_size) + skb_shinfo(skb)->gso_size = bnx2x_set_lro_mss(bp, + tpa_info->parsing_flags, len_on_bd); + +#ifdef BNX2X_STOP_ON_ERROR + if (pages > min_t(u32, 8, MAX_SKB_FRAGS)*SGE_PAGE_SIZE*PAGES_PER_SGE) { + BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n", + pages, cqe_idx); + BNX2X_ERR("cqe->pkt_len = %d\n", cqe->pkt_len); + bnx2x_panic(); + return -EINVAL; + } +#endif + + /* Run through the SGL and compose the fragmented skb */ + for (i = 0, j = 0; i < pages; i += PAGES_PER_SGE, j++) { + u16 sge_idx = RX_SGE(le16_to_cpu(cqe->sgl_or_raw_data.sgl[j])); + + /* FW gives the indices of the SGE as if the ring is an array + (meaning that "next" element will consume 2 indices) */ + frag_len = min(frag_size, (u32)(SGE_PAGE_SIZE*PAGES_PER_SGE)); + rx_pg = &fp->rx_page_ring[sge_idx]; + old_rx_pg = *rx_pg; + + /* If we fail to allocate a substitute page, we simply stop + where we are and drop the whole packet */ + err = bnx2x_alloc_rx_sge(bp, fp, sge_idx); + if (unlikely(err)) { + fp->eth_q_stats.rx_skb_alloc_failed++; + return err; + } + + /* Unmap the page as we r going to pass it to the stack */ + dma_unmap_page(&bp->pdev->dev, + dma_unmap_addr(&old_rx_pg, mapping), + SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE); + + /* Add one frag and update the appropriate fields in the skb */ + skb_fill_page_desc(skb, j, old_rx_pg.page, 0, frag_len); + + skb->data_len += frag_len; + skb->truesize += frag_len; + skb->len += frag_len; + + frag_size -= frag_len; + } + + return 0; +} + +static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, + u16 queue, struct eth_end_agg_rx_cqe *cqe, + u16 cqe_idx) +{ + struct bnx2x_agg_info *tpa_info = &fp->tpa_info[queue]; + struct sw_rx_bd *rx_buf = &tpa_info->first_buf; + u8 pad = tpa_info->placement_offset; + u16 len = tpa_info->len_on_bd; + struct sk_buff *skb = rx_buf->skb; + /* alloc new skb */ + struct sk_buff *new_skb; + u8 old_tpa_state = tpa_info->tpa_state; + + tpa_info->tpa_state = BNX2X_TPA_STOP; + + /* If we there was an error during the handling of the TPA_START - + * drop this aggregation. + */ + if (old_tpa_state == BNX2X_TPA_ERROR) + goto drop; + + /* Try to allocate the new skb */ + new_skb = netdev_alloc_skb(bp->dev, fp->rx_buf_size); + + /* Unmap skb in the pool anyway, as we are going to change + pool entry status to BNX2X_TPA_STOP even if new skb allocation + fails. */ + dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping), + fp->rx_buf_size, DMA_FROM_DEVICE); + + if (likely(new_skb)) { + prefetch(skb); + prefetch(((char *)(skb)) + L1_CACHE_BYTES); + +#ifdef BNX2X_STOP_ON_ERROR + if (pad + len > fp->rx_buf_size) { + BNX2X_ERR("skb_put is about to fail... " + "pad %d len %d rx_buf_size %d\n", + pad, len, fp->rx_buf_size); + bnx2x_panic(); + return; + } +#endif + + skb_reserve(skb, pad); + skb_put(skb, len); + + skb->protocol = eth_type_trans(skb, bp->dev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + if (!bnx2x_fill_frag_skb(bp, fp, queue, skb, cqe, cqe_idx)) { + if (tpa_info->parsing_flags & PARSING_FLAGS_VLAN) + __vlan_hwaccel_put_tag(skb, tpa_info->vlan_tag); + napi_gro_receive(&fp->napi, skb); + } else { + DP(NETIF_MSG_RX_STATUS, "Failed to allocate new pages" + " - dropping packet!\n"); + dev_kfree_skb_any(skb); + } + + + /* put new skb in bin */ + rx_buf->skb = new_skb; + + return; + } + +drop: + /* drop the packet and keep the buffer in the bin */ + DP(NETIF_MSG_RX_STATUS, + "Failed to allocate or map a new skb - dropping packet!\n"); + fp->eth_q_stats.rx_skb_alloc_failed++; +} + +/* Set Toeplitz hash value in the skb using the value from the + * CQE (calculated by HW). + */ +static inline void bnx2x_set_skb_rxhash(struct bnx2x *bp, union eth_rx_cqe *cqe, + struct sk_buff *skb) +{ + /* Set Toeplitz hash from CQE */ + if ((bp->dev->features & NETIF_F_RXHASH) && + (cqe->fast_path_cqe.status_flags & + ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG)) + skb->rxhash = + le32_to_cpu(cqe->fast_path_cqe.rss_hash_result); +} + +int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) +{ + struct bnx2x *bp = fp->bp; + u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons; + u16 hw_comp_cons, sw_comp_cons, sw_comp_prod; + int rx_pkt = 0; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return 0; +#endif + + /* CQ "next element" is of the size of the regular element, + that's why it's ok here */ + hw_comp_cons = le16_to_cpu(*fp->rx_cons_sb); + if ((hw_comp_cons & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) + hw_comp_cons++; + + bd_cons = fp->rx_bd_cons; + bd_prod = fp->rx_bd_prod; + bd_prod_fw = bd_prod; + sw_comp_cons = fp->rx_comp_cons; + sw_comp_prod = fp->rx_comp_prod; + + /* Memory barrier necessary as speculative reads of the rx + * buffer can be ahead of the index in the status block + */ + rmb(); + + DP(NETIF_MSG_RX_STATUS, + "queue[%d]: hw_comp_cons %u sw_comp_cons %u\n", + fp->index, hw_comp_cons, sw_comp_cons); + + while (sw_comp_cons != hw_comp_cons) { + struct sw_rx_bd *rx_buf = NULL; + struct sk_buff *skb; + union eth_rx_cqe *cqe; + struct eth_fast_path_rx_cqe *cqe_fp; + u8 cqe_fp_flags; + enum eth_rx_cqe_type cqe_fp_type; + u16 len, pad; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return 0; +#endif + + comp_ring_cons = RCQ_BD(sw_comp_cons); + bd_prod = RX_BD(bd_prod); + bd_cons = RX_BD(bd_cons); + + /* Prefetch the page containing the BD descriptor + at producer's index. It will be needed when new skb is + allocated */ + prefetch((void *)(PAGE_ALIGN((unsigned long) + (&fp->rx_desc_ring[bd_prod])) - + PAGE_SIZE + 1)); + + cqe = &fp->rx_comp_ring[comp_ring_cons]; + cqe_fp = &cqe->fast_path_cqe; + cqe_fp_flags = cqe_fp->type_error_flags; + cqe_fp_type = cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE; + + DP(NETIF_MSG_RX_STATUS, "CQE type %x err %x status %x" + " queue %x vlan %x len %u\n", CQE_TYPE(cqe_fp_flags), + cqe_fp_flags, cqe_fp->status_flags, + le32_to_cpu(cqe_fp->rss_hash_result), + le16_to_cpu(cqe_fp->vlan_tag), le16_to_cpu(cqe_fp->pkt_len)); + + /* is this a slowpath msg? */ + if (unlikely(CQE_TYPE_SLOW(cqe_fp_type))) { + bnx2x_sp_event(fp, cqe); + goto next_cqe; + + /* this is an rx packet */ + } else { + rx_buf = &fp->rx_buf_ring[bd_cons]; + skb = rx_buf->skb; + prefetch(skb); + + if (!CQE_TYPE_FAST(cqe_fp_type)) { +#ifdef BNX2X_STOP_ON_ERROR + /* sanity check */ + if (fp->disable_tpa && + (CQE_TYPE_START(cqe_fp_type) || + CQE_TYPE_STOP(cqe_fp_type))) + BNX2X_ERR("START/STOP packet while " + "disable_tpa type %x\n", + CQE_TYPE(cqe_fp_type)); +#endif + + if (CQE_TYPE_START(cqe_fp_type)) { + u16 queue = cqe_fp->queue_index; + DP(NETIF_MSG_RX_STATUS, + "calling tpa_start on queue %d\n", + queue); + + bnx2x_tpa_start(fp, queue, skb, + bd_cons, bd_prod, + cqe_fp); + + /* Set Toeplitz hash for LRO skb */ + bnx2x_set_skb_rxhash(bp, cqe, skb); + + goto next_rx; + + } else { + u16 queue = + cqe->end_agg_cqe.queue_index; + DP(NETIF_MSG_RX_STATUS, + "calling tpa_stop on queue %d\n", + queue); + + bnx2x_tpa_stop(bp, fp, queue, + &cqe->end_agg_cqe, + comp_ring_cons); +#ifdef BNX2X_STOP_ON_ERROR + if (bp->panic) + return 0; +#endif + + bnx2x_update_sge_prod(fp, cqe_fp); + goto next_cqe; + } + } + /* non TPA */ + len = le16_to_cpu(cqe_fp->pkt_len); + pad = cqe_fp->placement_offset; + dma_sync_single_for_cpu(&bp->pdev->dev, + dma_unmap_addr(rx_buf, mapping), + pad + RX_COPY_THRESH, + DMA_FROM_DEVICE); + prefetch(((char *)(skb)) + L1_CACHE_BYTES); + + /* is this an error packet? */ + if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) { + DP(NETIF_MSG_RX_ERR, + "ERROR flags %x rx packet %u\n", + cqe_fp_flags, sw_comp_cons); + fp->eth_q_stats.rx_err_discard_pkt++; + goto reuse_rx; + } + + /* Since we don't have a jumbo ring + * copy small packets if mtu > 1500 + */ + if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) && + (len <= RX_COPY_THRESH)) { + struct sk_buff *new_skb; + + new_skb = netdev_alloc_skb(bp->dev, len + pad); + if (new_skb == NULL) { + DP(NETIF_MSG_RX_ERR, + "ERROR packet dropped " + "because of alloc failure\n"); + fp->eth_q_stats.rx_skb_alloc_failed++; + goto reuse_rx; + } + + /* aligned copy */ + skb_copy_from_linear_data_offset(skb, pad, + new_skb->data + pad, len); + skb_reserve(new_skb, pad); + skb_put(new_skb, len); + + bnx2x_reuse_rx_skb(fp, bd_cons, bd_prod); + + skb = new_skb; + + } else + if (likely(bnx2x_alloc_rx_skb(bp, fp, bd_prod) == 0)) { + dma_unmap_single(&bp->pdev->dev, + dma_unmap_addr(rx_buf, mapping), + fp->rx_buf_size, + DMA_FROM_DEVICE); + skb_reserve(skb, pad); + skb_put(skb, len); + + } else { + DP(NETIF_MSG_RX_ERR, + "ERROR packet dropped because " + "of alloc failure\n"); + fp->eth_q_stats.rx_skb_alloc_failed++; +reuse_rx: + bnx2x_reuse_rx_skb(fp, bd_cons, bd_prod); + goto next_rx; + } + + skb->protocol = eth_type_trans(skb, bp->dev); + + /* Set Toeplitz hash for a none-LRO skb */ + bnx2x_set_skb_rxhash(bp, cqe, skb); + + skb_checksum_none_assert(skb); + + if (bp->dev->features & NETIF_F_RXCSUM) { + + if (likely(BNX2X_RX_CSUM_OK(cqe))) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + fp->eth_q_stats.hw_csum_err++; + } + } + + skb_record_rx_queue(skb, fp->index); + + if (le16_to_cpu(cqe_fp->pars_flags.flags) & + PARSING_FLAGS_VLAN) + __vlan_hwaccel_put_tag(skb, + le16_to_cpu(cqe_fp->vlan_tag)); + napi_gro_receive(&fp->napi, skb); + + +next_rx: + rx_buf->skb = NULL; + + bd_cons = NEXT_RX_IDX(bd_cons); + bd_prod = NEXT_RX_IDX(bd_prod); + bd_prod_fw = NEXT_RX_IDX(bd_prod_fw); + rx_pkt++; +next_cqe: + sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod); + sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons); + + if (rx_pkt == budget) + break; + } /* while */ + + fp->rx_bd_cons = bd_cons; + fp->rx_bd_prod = bd_prod_fw; + fp->rx_comp_cons = sw_comp_cons; + fp->rx_comp_prod = sw_comp_prod; + + /* Update producers */ + bnx2x_update_rx_prod(bp, fp, bd_prod_fw, sw_comp_prod, + fp->rx_sge_prod); + + fp->rx_pkt += rx_pkt; + fp->rx_calls++; + + return rx_pkt; +} + +static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) +{ + struct bnx2x_fastpath *fp = fp_cookie; + struct bnx2x *bp = fp->bp; + u8 cos; + + DP(BNX2X_MSG_FP, "got an MSI-X interrupt on IDX:SB " + "[fp %d fw_sd %d igusb %d]\n", + fp->index, fp->fw_sb_id, fp->igu_sb_id); + bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0); + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return IRQ_HANDLED; +#endif + + /* Handle Rx and Tx according to MSI-X vector */ + prefetch(fp->rx_cons_sb); + + for_each_cos_in_tx_queue(fp, cos) + prefetch(fp->txdata[cos].tx_cons_sb); + + prefetch(&fp->sb_running_index[SM_RX_ID]); + napi_schedule(&bnx2x_fp(bp, fp->index, napi)); + + return IRQ_HANDLED; +} + +/* HW Lock for shared dual port PHYs */ +void bnx2x_acquire_phy_lock(struct bnx2x *bp) +{ + mutex_lock(&bp->port.phy_mutex); + + if (bp->port.need_hw_lock) + bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_MDIO); +} + +void bnx2x_release_phy_lock(struct bnx2x *bp) +{ + if (bp->port.need_hw_lock) + bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_MDIO); + + mutex_unlock(&bp->port.phy_mutex); +} + +/* calculates MF speed according to current linespeed and MF configuration */ +u16 bnx2x_get_mf_speed(struct bnx2x *bp) +{ + u16 line_speed = bp->link_vars.line_speed; + if (IS_MF(bp)) { + u16 maxCfg = bnx2x_extract_max_cfg(bp, + bp->mf_config[BP_VN(bp)]); + + /* Calculate the current MAX line speed limit for the MF + * devices + */ + if (IS_MF_SI(bp)) + line_speed = (line_speed * maxCfg) / 100; + else { /* SD mode */ + u16 vn_max_rate = maxCfg * 100; + + if (vn_max_rate < line_speed) + line_speed = vn_max_rate; + } + } + + return line_speed; +} + +/** + * bnx2x_fill_report_data - fill link report data to report + * + * @bp: driver handle + * @data: link state to update + * + * It uses a none-atomic bit operations because is called under the mutex. + */ +static inline void bnx2x_fill_report_data(struct bnx2x *bp, + struct bnx2x_link_report_data *data) +{ + u16 line_speed = bnx2x_get_mf_speed(bp); + + memset(data, 0, sizeof(*data)); + + /* Fill the report data: efective line speed */ + data->line_speed = line_speed; + + /* Link is down */ + if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS)) + __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &data->link_report_flags); + + /* Full DUPLEX */ + if (bp->link_vars.duplex == DUPLEX_FULL) + __set_bit(BNX2X_LINK_REPORT_FD, &data->link_report_flags); + + /* Rx Flow Control is ON */ + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) + __set_bit(BNX2X_LINK_REPORT_RX_FC_ON, &data->link_report_flags); + + /* Tx Flow Control is ON */ + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) + __set_bit(BNX2X_LINK_REPORT_TX_FC_ON, &data->link_report_flags); +} + +/** + * bnx2x_link_report - report link status to OS. + * + * @bp: driver handle + * + * Calls the __bnx2x_link_report() under the same locking scheme + * as a link/PHY state managing code to ensure a consistent link + * reporting. + */ + +void bnx2x_link_report(struct bnx2x *bp) +{ + bnx2x_acquire_phy_lock(bp); + __bnx2x_link_report(bp); + bnx2x_release_phy_lock(bp); +} + +/** + * __bnx2x_link_report - report link status to OS. + * + * @bp: driver handle + * + * None atomic inmlementation. + * Should be called under the phy_lock. + */ +void __bnx2x_link_report(struct bnx2x *bp) +{ + struct bnx2x_link_report_data cur_data; + + /* reread mf_cfg */ + if (!CHIP_IS_E1(bp)) + bnx2x_read_mf_cfg(bp); + + /* Read the current link report info */ + bnx2x_fill_report_data(bp, &cur_data); + + /* Don't report link down or exactly the same link status twice */ + if (!memcmp(&cur_data, &bp->last_reported_link, sizeof(cur_data)) || + (test_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &bp->last_reported_link.link_report_flags) && + test_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &cur_data.link_report_flags))) + return; + + bp->link_cnt++; + + /* We are going to report a new link parameters now - + * remember the current data for the next time. + */ + memcpy(&bp->last_reported_link, &cur_data, sizeof(cur_data)); + + if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &cur_data.link_report_flags)) { + netif_carrier_off(bp->dev); + netdev_err(bp->dev, "NIC Link is Down\n"); + return; + } else { + netif_carrier_on(bp->dev); + netdev_info(bp->dev, "NIC Link is Up, "); + pr_cont("%d Mbps ", cur_data.line_speed); + + if (test_and_clear_bit(BNX2X_LINK_REPORT_FD, + &cur_data.link_report_flags)) + pr_cont("full duplex"); + else + pr_cont("half duplex"); + + /* Handle the FC at the end so that only these flags would be + * possibly set. This way we may easily check if there is no FC + * enabled. + */ + if (cur_data.link_report_flags) { + if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON, + &cur_data.link_report_flags)) { + pr_cont(", receive "); + if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON, + &cur_data.link_report_flags)) + pr_cont("& transmit "); + } else { + pr_cont(", transmit "); + } + pr_cont("flow control ON"); + } + pr_cont("\n"); + } +} + +void bnx2x_init_rx_rings(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + int max_agg_queues = CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 : + ETH_MAX_AGGREGATION_QUEUES_E1H_E2; + u16 ring_prod; + int i, j; + + /* Allocate TPA resources */ + for_each_rx_queue(bp, j) { + struct bnx2x_fastpath *fp = &bp->fp[j]; + + DP(NETIF_MSG_IFUP, + "mtu %d rx_buf_size %d\n", bp->dev->mtu, fp->rx_buf_size); + + if (!fp->disable_tpa) { + /* Fill the per-aggregtion pool */ + for (i = 0; i < max_agg_queues; i++) { + struct bnx2x_agg_info *tpa_info = + &fp->tpa_info[i]; + struct sw_rx_bd *first_buf = + &tpa_info->first_buf; + + first_buf->skb = netdev_alloc_skb(bp->dev, + fp->rx_buf_size); + if (!first_buf->skb) { + BNX2X_ERR("Failed to allocate TPA " + "skb pool for queue[%d] - " + "disabling TPA on this " + "queue!\n", j); + bnx2x_free_tpa_pool(bp, fp, i); + fp->disable_tpa = 1; + break; + } + dma_unmap_addr_set(first_buf, mapping, 0); + tpa_info->tpa_state = BNX2X_TPA_STOP; + } + + /* "next page" elements initialization */ + bnx2x_set_next_page_sgl(fp); + + /* set SGEs bit mask */ + bnx2x_init_sge_ring_bit_mask(fp); + + /* Allocate SGEs and initialize the ring elements */ + for (i = 0, ring_prod = 0; + i < MAX_RX_SGE_CNT*NUM_RX_SGE_PAGES; i++) { + + if (bnx2x_alloc_rx_sge(bp, fp, ring_prod) < 0) { + BNX2X_ERR("was only able to allocate " + "%d rx sges\n", i); + BNX2X_ERR("disabling TPA for " + "queue[%d]\n", j); + /* Cleanup already allocated elements */ + bnx2x_free_rx_sge_range(bp, fp, + ring_prod); + bnx2x_free_tpa_pool(bp, fp, + max_agg_queues); + fp->disable_tpa = 1; + ring_prod = 0; + break; + } + ring_prod = NEXT_SGE_IDX(ring_prod); + } + + fp->rx_sge_prod = ring_prod; + } + } + + for_each_rx_queue(bp, j) { + struct bnx2x_fastpath *fp = &bp->fp[j]; + + fp->rx_bd_cons = 0; + + /* Activate BD ring */ + /* Warning! + * this will generate an interrupt (to the TSTORM) + * must only be done after chip is initialized + */ + bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, + fp->rx_sge_prod); + + if (j != 0) + continue; + + if (CHIP_IS_E1(bp)) { + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func), + U64_LO(fp->rx_comp_mapping)); + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func) + 4, + U64_HI(fp->rx_comp_mapping)); + } + } +} + +static void bnx2x_free_tx_skbs(struct bnx2x *bp) +{ + int i; + u8 cos; + + for_each_tx_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + for_each_cos_in_tx_queue(fp, cos) { + struct bnx2x_fp_txdata *txdata = &fp->txdata[cos]; + + u16 bd_cons = txdata->tx_bd_cons; + u16 sw_prod = txdata->tx_pkt_prod; + u16 sw_cons = txdata->tx_pkt_cons; + + while (sw_cons != sw_prod) { + bd_cons = bnx2x_free_tx_pkt(bp, txdata, + TX_BD(sw_cons)); + sw_cons++; + } + } + } +} + +static void bnx2x_free_rx_bds(struct bnx2x_fastpath *fp) +{ + struct bnx2x *bp = fp->bp; + int i; + + /* ring wasn't allocated */ + if (fp->rx_buf_ring == NULL) + return; + + for (i = 0; i < NUM_RX_BD; i++) { + struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i]; + struct sk_buff *skb = rx_buf->skb; + + if (skb == NULL) + continue; + dma_unmap_single(&bp->pdev->dev, + dma_unmap_addr(rx_buf, mapping), + fp->rx_buf_size, DMA_FROM_DEVICE); + + rx_buf->skb = NULL; + dev_kfree_skb(skb); + } +} + +static void bnx2x_free_rx_skbs(struct bnx2x *bp) +{ + int j; + + for_each_rx_queue(bp, j) { + struct bnx2x_fastpath *fp = &bp->fp[j]; + + bnx2x_free_rx_bds(fp); + + if (!fp->disable_tpa) + bnx2x_free_tpa_pool(bp, fp, CHIP_IS_E1(bp) ? + ETH_MAX_AGGREGATION_QUEUES_E1 : + ETH_MAX_AGGREGATION_QUEUES_E1H_E2); + } +} + +void bnx2x_free_skbs(struct bnx2x *bp) +{ + bnx2x_free_tx_skbs(bp); + bnx2x_free_rx_skbs(bp); +} + +void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value) +{ + /* load old values */ + u32 mf_cfg = bp->mf_config[BP_VN(bp)]; + + if (value != bnx2x_extract_max_cfg(bp, mf_cfg)) { + /* leave all but MAX value */ + mf_cfg &= ~FUNC_MF_CFG_MAX_BW_MASK; + + /* set new MAX value */ + mf_cfg |= (value << FUNC_MF_CFG_MAX_BW_SHIFT) + & FUNC_MF_CFG_MAX_BW_MASK; + + bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW, mf_cfg); + } +} + +/** + * bnx2x_free_msix_irqs - free previously requested MSI-X IRQ vectors + * + * @bp: driver handle + * @nvecs: number of vectors to be released + */ +static void bnx2x_free_msix_irqs(struct bnx2x *bp, int nvecs) +{ + int i, offset = 0; + + if (nvecs == offset) + return; + free_irq(bp->msix_table[offset].vector, bp->dev); + DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n", + bp->msix_table[offset].vector); + offset++; +#ifdef BCM_CNIC + if (nvecs == offset) + return; + offset++; +#endif + + for_each_eth_queue(bp, i) { + if (nvecs == offset) + return; + DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d " + "irq\n", i, bp->msix_table[offset].vector); + + free_irq(bp->msix_table[offset++].vector, &bp->fp[i]); + } +} + +void bnx2x_free_irq(struct bnx2x *bp) +{ + if (bp->flags & USING_MSIX_FLAG) + bnx2x_free_msix_irqs(bp, BNX2X_NUM_ETH_QUEUES(bp) + + CNIC_PRESENT + 1); + else if (bp->flags & USING_MSI_FLAG) + free_irq(bp->pdev->irq, bp->dev); + else + free_irq(bp->pdev->irq, bp->dev); +} + +int bnx2x_enable_msix(struct bnx2x *bp) +{ + int msix_vec = 0, i, rc, req_cnt; + + bp->msix_table[msix_vec].entry = msix_vec; + DP(NETIF_MSG_IFUP, "msix_table[0].entry = %d (slowpath)\n", + bp->msix_table[0].entry); + msix_vec++; + +#ifdef BCM_CNIC + bp->msix_table[msix_vec].entry = msix_vec; + DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d (CNIC)\n", + bp->msix_table[msix_vec].entry, bp->msix_table[msix_vec].entry); + msix_vec++; +#endif + /* We need separate vectors for ETH queues only (not FCoE) */ + for_each_eth_queue(bp, i) { + bp->msix_table[msix_vec].entry = msix_vec; + DP(NETIF_MSG_IFUP, "msix_table[%d].entry = %d " + "(fastpath #%u)\n", msix_vec, msix_vec, i); + msix_vec++; + } + + req_cnt = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_PRESENT + 1; + + rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], req_cnt); + + /* + * reconfigure number of tx/rx queues according to available + * MSI-X vectors + */ + if (rc >= BNX2X_MIN_MSIX_VEC_CNT) { + /* how less vectors we will have? */ + int diff = req_cnt - rc; + + DP(NETIF_MSG_IFUP, + "Trying to use less MSI-X vectors: %d\n", rc); + + rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], rc); + + if (rc) { + DP(NETIF_MSG_IFUP, + "MSI-X is not attainable rc %d\n", rc); + return rc; + } + /* + * decrease number of queues by number of unallocated entries + */ + bp->num_queues -= diff; + + DP(NETIF_MSG_IFUP, "New queue configuration set: %d\n", + bp->num_queues); + } else if (rc) { + /* fall to INTx if not enough memory */ + if (rc == -ENOMEM) + bp->flags |= DISABLE_MSI_FLAG; + DP(NETIF_MSG_IFUP, "MSI-X is not attainable rc %d\n", rc); + return rc; + } + + bp->flags |= USING_MSIX_FLAG; + + return 0; +} + +static int bnx2x_req_msix_irqs(struct bnx2x *bp) +{ + int i, rc, offset = 0; + + rc = request_irq(bp->msix_table[offset++].vector, + bnx2x_msix_sp_int, 0, + bp->dev->name, bp->dev); + if (rc) { + BNX2X_ERR("request sp irq failed\n"); + return -EBUSY; + } + +#ifdef BCM_CNIC + offset++; +#endif + for_each_eth_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", + bp->dev->name, i); + + rc = request_irq(bp->msix_table[offset].vector, + bnx2x_msix_fp_int, 0, fp->name, fp); + if (rc) { + BNX2X_ERR("request fp #%d irq (%d) failed rc %d\n", i, + bp->msix_table[offset].vector, rc); + bnx2x_free_msix_irqs(bp, offset); + return -EBUSY; + } + + offset++; + } + + i = BNX2X_NUM_ETH_QUEUES(bp); + offset = 1 + CNIC_PRESENT; + netdev_info(bp->dev, "using MSI-X IRQs: sp %d fp[%d] %d" + " ... fp[%d] %d\n", + bp->msix_table[0].vector, + 0, bp->msix_table[offset].vector, + i - 1, bp->msix_table[offset + i - 1].vector); + + return 0; +} + +int bnx2x_enable_msi(struct bnx2x *bp) +{ + int rc; + + rc = pci_enable_msi(bp->pdev); + if (rc) { + DP(NETIF_MSG_IFUP, "MSI is not attainable\n"); + return -1; + } + bp->flags |= USING_MSI_FLAG; + + return 0; +} + +static int bnx2x_req_irq(struct bnx2x *bp) +{ + unsigned long flags; + int rc; + + if (bp->flags & USING_MSI_FLAG) + flags = 0; + else + flags = IRQF_SHARED; + + rc = request_irq(bp->pdev->irq, bnx2x_interrupt, flags, + bp->dev->name, bp->dev); + return rc; +} + +static inline int bnx2x_setup_irqs(struct bnx2x *bp) +{ + int rc = 0; + if (bp->flags & USING_MSIX_FLAG) { + rc = bnx2x_req_msix_irqs(bp); + if (rc) + return rc; + } else { + bnx2x_ack_int(bp); + rc = bnx2x_req_irq(bp); + if (rc) { + BNX2X_ERR("IRQ request failed rc %d, aborting\n", rc); + return rc; + } + if (bp->flags & USING_MSI_FLAG) { + bp->dev->irq = bp->pdev->irq; + netdev_info(bp->dev, "using MSI IRQ %d\n", + bp->pdev->irq); + } + } + + return 0; +} + +static inline void bnx2x_napi_enable(struct bnx2x *bp) +{ + int i; + + for_each_rx_queue(bp, i) + napi_enable(&bnx2x_fp(bp, i, napi)); +} + +static inline void bnx2x_napi_disable(struct bnx2x *bp) +{ + int i; + + for_each_rx_queue(bp, i) + napi_disable(&bnx2x_fp(bp, i, napi)); +} + +void bnx2x_netif_start(struct bnx2x *bp) +{ + if (netif_running(bp->dev)) { + bnx2x_napi_enable(bp); + bnx2x_int_enable(bp); + if (bp->state == BNX2X_STATE_OPEN) + netif_tx_wake_all_queues(bp->dev); + } +} + +void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw) +{ + bnx2x_int_disable_sync(bp, disable_hw); + bnx2x_napi_disable(bp); +} + +u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + struct bnx2x *bp = netdev_priv(dev); +#ifdef BCM_CNIC + if (NO_FCOE(bp)) + return skb_tx_hash(dev, skb); + else { + struct ethhdr *hdr = (struct ethhdr *)skb->data; + u16 ether_type = ntohs(hdr->h_proto); + + /* Skip VLAN tag if present */ + if (ether_type == ETH_P_8021Q) { + struct vlan_ethhdr *vhdr = + (struct vlan_ethhdr *)skb->data; + + ether_type = ntohs(vhdr->h_vlan_encapsulated_proto); + } + + /* If ethertype is FCoE or FIP - use FCoE ring */ + if ((ether_type == ETH_P_FCOE) || (ether_type == ETH_P_FIP)) + return bnx2x_fcoe_tx(bp, txq_index); + } +#endif + /* Select a none-FCoE queue: if FCoE is enabled, exclude FCoE L2 ring + */ + return __skb_tx_hash(dev, skb, BNX2X_NUM_ETH_QUEUES(bp)); +} + +void bnx2x_set_num_queues(struct bnx2x *bp) +{ + switch (bp->multi_mode) { + case ETH_RSS_MODE_DISABLED: + bp->num_queues = 1; + break; + case ETH_RSS_MODE_REGULAR: + bp->num_queues = bnx2x_calc_num_queues(bp); + break; + + default: + bp->num_queues = 1; + break; + } + + /* Add special queues */ + bp->num_queues += NON_ETH_CONTEXT_USE; +} + +static inline int bnx2x_set_real_num_queues(struct bnx2x *bp) +{ + int rc, tx, rx; + + tx = MAX_TXQS_PER_COS * bp->max_cos; + rx = BNX2X_NUM_ETH_QUEUES(bp); + +/* account for fcoe queue */ +#ifdef BCM_CNIC + if (!NO_FCOE(bp)) { + rx += FCOE_PRESENT; + tx += FCOE_PRESENT; + } +#endif + + rc = netif_set_real_num_tx_queues(bp->dev, tx); + if (rc) { + BNX2X_ERR("Failed to set real number of Tx queues: %d\n", rc); + return rc; + } + rc = netif_set_real_num_rx_queues(bp->dev, rx); + if (rc) { + BNX2X_ERR("Failed to set real number of Rx queues: %d\n", rc); + return rc; + } + + DP(NETIF_MSG_DRV, "Setting real num queues to (tx, rx) (%d, %d)\n", + tx, rx); + + return rc; +} + +static inline void bnx2x_set_rx_buf_size(struct bnx2x *bp) +{ + int i; + + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + /* Always use a mini-jumbo MTU for the FCoE L2 ring */ + if (IS_FCOE_IDX(i)) + /* + * Although there are no IP frames expected to arrive to + * this ring we still want to add an + * IP_HEADER_ALIGNMENT_PADDING to prevent a buffer + * overrun attack. + */ + fp->rx_buf_size = + BNX2X_FCOE_MINI_JUMBO_MTU + ETH_OVREHEAD + + BNX2X_FW_RX_ALIGN + IP_HEADER_ALIGNMENT_PADDING; + else + fp->rx_buf_size = + bp->dev->mtu + ETH_OVREHEAD + + BNX2X_FW_RX_ALIGN + IP_HEADER_ALIGNMENT_PADDING; + } +} + +static inline int bnx2x_init_rss_pf(struct bnx2x *bp) +{ + int i; + u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; + u8 num_eth_queues = BNX2X_NUM_ETH_QUEUES(bp); + + /* + * Prepare the inital contents fo the indirection table if RSS is + * enabled + */ + if (bp->multi_mode != ETH_RSS_MODE_DISABLED) { + for (i = 0; i < sizeof(ind_table); i++) + ind_table[i] = + bp->fp->cl_id + (i % num_eth_queues); + } + + /* + * For 57710 and 57711 SEARCHER configuration (rss_keys) is + * per-port, so if explicit configuration is needed , do it only + * for a PMF. + * + * For 57712 and newer on the other hand it's a per-function + * configuration. + */ + return bnx2x_config_rss_pf(bp, ind_table, + bp->port.pmf || !CHIP_IS_E1x(bp)); +} + +int bnx2x_config_rss_pf(struct bnx2x *bp, u8 *ind_table, bool config_hash) +{ + struct bnx2x_config_rss_params params = {0}; + int i; + + /* Although RSS is meaningless when there is a single HW queue we + * still need it enabled in order to have HW Rx hash generated. + * + * if (!is_eth_multi(bp)) + * bp->multi_mode = ETH_RSS_MODE_DISABLED; + */ + + params.rss_obj = &bp->rss_conf_obj; + + __set_bit(RAMROD_COMP_WAIT, ¶ms.ramrod_flags); + + /* RSS mode */ + switch (bp->multi_mode) { + case ETH_RSS_MODE_DISABLED: + __set_bit(BNX2X_RSS_MODE_DISABLED, ¶ms.rss_flags); + break; + case ETH_RSS_MODE_REGULAR: + __set_bit(BNX2X_RSS_MODE_REGULAR, ¶ms.rss_flags); + break; + case ETH_RSS_MODE_VLAN_PRI: + __set_bit(BNX2X_RSS_MODE_VLAN_PRI, ¶ms.rss_flags); + break; + case ETH_RSS_MODE_E1HOV_PRI: + __set_bit(BNX2X_RSS_MODE_E1HOV_PRI, ¶ms.rss_flags); + break; + case ETH_RSS_MODE_IP_DSCP: + __set_bit(BNX2X_RSS_MODE_IP_DSCP, ¶ms.rss_flags); + break; + default: + BNX2X_ERR("Unknown multi_mode: %d\n", bp->multi_mode); + return -EINVAL; + } + + /* If RSS is enabled */ + if (bp->multi_mode != ETH_RSS_MODE_DISABLED) { + /* RSS configuration */ + __set_bit(BNX2X_RSS_IPV4, ¶ms.rss_flags); + __set_bit(BNX2X_RSS_IPV4_TCP, ¶ms.rss_flags); + __set_bit(BNX2X_RSS_IPV6, ¶ms.rss_flags); + __set_bit(BNX2X_RSS_IPV6_TCP, ¶ms.rss_flags); + + /* Hash bits */ + params.rss_result_mask = MULTI_MASK; + + memcpy(params.ind_table, ind_table, sizeof(params.ind_table)); + + if (config_hash) { + /* RSS keys */ + for (i = 0; i < sizeof(params.rss_key) / 4; i++) + params.rss_key[i] = random32(); + + __set_bit(BNX2X_RSS_SET_SRCH, ¶ms.rss_flags); + } + } + + return bnx2x_config_rss(bp, ¶ms); +} + +static inline int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) +{ + struct bnx2x_func_state_params func_params = {0}; + + /* Prepare parameters for function state transitions */ + __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags); + + func_params.f_obj = &bp->func_obj; + func_params.cmd = BNX2X_F_CMD_HW_INIT; + + func_params.params.hw_init.load_phase = load_code; + + return bnx2x_func_state_change(bp, &func_params); +} + +/* + * Cleans the object that have internal lists without sending + * ramrods. Should be run when interrutps are disabled. + */ +static void bnx2x_squeeze_objects(struct bnx2x *bp) +{ + int rc; + unsigned long ramrod_flags = 0, vlan_mac_flags = 0; + struct bnx2x_mcast_ramrod_params rparam = {0}; + struct bnx2x_vlan_mac_obj *mac_obj = &bp->fp->mac_obj; + + /***************** Cleanup MACs' object first *************************/ + + /* Wait for completion of requested */ + __set_bit(RAMROD_COMP_WAIT, &ramrod_flags); + /* Perform a dry cleanup */ + __set_bit(RAMROD_DRV_CLR_ONLY, &ramrod_flags); + + /* Clean ETH primary MAC */ + __set_bit(BNX2X_ETH_MAC, &vlan_mac_flags); + rc = mac_obj->delete_all(bp, &bp->fp->mac_obj, &vlan_mac_flags, + &ramrod_flags); + if (rc != 0) + BNX2X_ERR("Failed to clean ETH MACs: %d\n", rc); + + /* Cleanup UC list */ + vlan_mac_flags = 0; + __set_bit(BNX2X_UC_LIST_MAC, &vlan_mac_flags); + rc = mac_obj->delete_all(bp, mac_obj, &vlan_mac_flags, + &ramrod_flags); + if (rc != 0) + BNX2X_ERR("Failed to clean UC list MACs: %d\n", rc); + + /***************** Now clean mcast object *****************************/ + rparam.mcast_obj = &bp->mcast_obj; + __set_bit(RAMROD_DRV_CLR_ONLY, &rparam.ramrod_flags); + + /* Add a DEL command... */ + rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL); + if (rc < 0) + BNX2X_ERR("Failed to add a new DEL command to a multi-cast " + "object: %d\n", rc); + + /* ...and wait until all pending commands are cleared */ + rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT); + while (rc != 0) { + if (rc < 0) { + BNX2X_ERR("Failed to clean multi-cast object: %d\n", + rc); + return; + } + + rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT); + } +} + +#ifndef BNX2X_STOP_ON_ERROR +#define LOAD_ERROR_EXIT(bp, label) \ + do { \ + (bp)->state = BNX2X_STATE_ERROR; \ + goto label; \ + } while (0) +#else +#define LOAD_ERROR_EXIT(bp, label) \ + do { \ + (bp)->state = BNX2X_STATE_ERROR; \ + (bp)->panic = 1; \ + return -EBUSY; \ + } while (0) +#endif + +/* must be called with rtnl_lock */ +int bnx2x_nic_load(struct bnx2x *bp, int load_mode) +{ + int port = BP_PORT(bp); + u32 load_code; + int i, rc; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return -EPERM; +#endif + + bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD; + + /* Set the initial link reported state to link down */ + bnx2x_acquire_phy_lock(bp); + memset(&bp->last_reported_link, 0, sizeof(bp->last_reported_link)); + __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, + &bp->last_reported_link.link_report_flags); + bnx2x_release_phy_lock(bp); + + /* must be called before memory allocation and HW init */ + bnx2x_ilt_set_info(bp); + + /* + * Zero fastpath structures preserving invariants like napi, which are + * allocated only once, fp index, max_cos, bp pointer. + * Also set fp->disable_tpa. + */ + for_each_queue(bp, i) + bnx2x_bz_fp(bp, i); + + + /* Set the receive queues buffer size */ + bnx2x_set_rx_buf_size(bp); + + if (bnx2x_alloc_mem(bp)) + return -ENOMEM; + + /* As long as bnx2x_alloc_mem() may possibly update + * bp->num_queues, bnx2x_set_real_num_queues() should always + * come after it. + */ + rc = bnx2x_set_real_num_queues(bp); + if (rc) { + BNX2X_ERR("Unable to set real_num_queues\n"); + LOAD_ERROR_EXIT(bp, load_error0); + } + + /* configure multi cos mappings in kernel. + * this configuration may be overriden by a multi class queue discipline + * or by a dcbx negotiation result. + */ + bnx2x_setup_tc(bp->dev, bp->max_cos); + + bnx2x_napi_enable(bp); + + /* Send LOAD_REQUEST command to MCP + * Returns the type of LOAD command: + * if it is the first port to be initialized + * common blocks should be initialized, otherwise - not + */ + if (!BP_NOMCP(bp)) { + load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ, 0); + if (!load_code) { + BNX2X_ERR("MCP response failure, aborting\n"); + rc = -EBUSY; + LOAD_ERROR_EXIT(bp, load_error1); + } + if (load_code == FW_MSG_CODE_DRV_LOAD_REFUSED) { + rc = -EBUSY; /* other port in diagnostic mode */ + LOAD_ERROR_EXIT(bp, load_error1); + } + + } else { + int path = BP_PATH(bp); + + DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d] %d, %d, %d\n", + path, load_count[path][0], load_count[path][1], + load_count[path][2]); + load_count[path][0]++; + load_count[path][1 + port]++; + DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d] %d, %d, %d\n", + path, load_count[path][0], load_count[path][1], + load_count[path][2]); + if (load_count[path][0] == 1) + load_code = FW_MSG_CODE_DRV_LOAD_COMMON; + else if (load_count[path][1 + port] == 1) + load_code = FW_MSG_CODE_DRV_LOAD_PORT; + else + load_code = FW_MSG_CODE_DRV_LOAD_FUNCTION; + } + + if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) || + (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) || + (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) { + bp->port.pmf = 1; + /* + * We need the barrier to ensure the ordering between the + * writing to bp->port.pmf here and reading it from the + * bnx2x_periodic_task(). + */ + smp_mb(); + queue_delayed_work(bnx2x_wq, &bp->period_task, 0); + } else + bp->port.pmf = 0; + + DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf); + + /* Init Function state controlling object */ + bnx2x__init_func_obj(bp); + + /* Initialize HW */ + rc = bnx2x_init_hw(bp, load_code); + if (rc) { + BNX2X_ERR("HW init failed, aborting\n"); + bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0); + LOAD_ERROR_EXIT(bp, load_error2); + } + + /* Connect to IRQs */ + rc = bnx2x_setup_irqs(bp); + if (rc) { + bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0); + LOAD_ERROR_EXIT(bp, load_error2); + } + + /* Setup NIC internals and enable interrupts */ + bnx2x_nic_init(bp, load_code); + + /* Init per-function objects */ + bnx2x_init_bp_objs(bp); + + if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) || + (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) && + (bp->common.shmem2_base)) { + if (SHMEM2_HAS(bp, dcc_support)) + SHMEM2_WR(bp, dcc_support, + (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV | + SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV)); + } + + bp->state = BNX2X_STATE_OPENING_WAIT4_PORT; + rc = bnx2x_func_start(bp); + if (rc) { + BNX2X_ERR("Function start failed!\n"); + bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0); + LOAD_ERROR_EXIT(bp, load_error3); + } + + /* Send LOAD_DONE command to MCP */ + if (!BP_NOMCP(bp)) { + load_code = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0); + if (!load_code) { + BNX2X_ERR("MCP response failure, aborting\n"); + rc = -EBUSY; + LOAD_ERROR_EXIT(bp, load_error3); + } + } + + rc = bnx2x_setup_leading(bp); + if (rc) { + BNX2X_ERR("Setup leading failed!\n"); + LOAD_ERROR_EXIT(bp, load_error3); + } + +#ifdef BCM_CNIC + /* Enable Timer scan */ + REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1); +#endif + + for_each_nondefault_queue(bp, i) { + rc = bnx2x_setup_queue(bp, &bp->fp[i], 0); + if (rc) + LOAD_ERROR_EXIT(bp, load_error4); + } + + rc = bnx2x_init_rss_pf(bp); + if (rc) + LOAD_ERROR_EXIT(bp, load_error4); + + /* Now when Clients are configured we are ready to work */ + bp->state = BNX2X_STATE_OPEN; + + /* Configure a ucast MAC */ + rc = bnx2x_set_eth_mac(bp, true); + if (rc) + LOAD_ERROR_EXIT(bp, load_error4); + + if (bp->pending_max) { + bnx2x_update_max_mf_config(bp, bp->pending_max); + bp->pending_max = 0; + } + + if (bp->port.pmf) + bnx2x_initial_phy_init(bp, load_mode); + + /* Start fast path */ + + /* Initialize Rx filter. */ + netif_addr_lock_bh(bp->dev); + bnx2x_set_rx_mode(bp->dev); + netif_addr_unlock_bh(bp->dev); + + /* Start the Tx */ + switch (load_mode) { + case LOAD_NORMAL: + /* Tx queue should be only reenabled */ + netif_tx_wake_all_queues(bp->dev); + break; + + case LOAD_OPEN: + netif_tx_start_all_queues(bp->dev); + smp_mb__after_clear_bit(); + break; + + case LOAD_DIAG: + bp->state = BNX2X_STATE_DIAG; + break; + + default: + break; + } + + if (!bp->port.pmf) + bnx2x__link_status_update(bp); + + /* start the timer */ + mod_timer(&bp->timer, jiffies + bp->current_interval); + +#ifdef BCM_CNIC + bnx2x_setup_cnic_irq_info(bp); + if (bp->state == BNX2X_STATE_OPEN) + bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD); +#endif + bnx2x_inc_load_cnt(bp); + + /* Wait for all pending SP commands to complete */ + if (!bnx2x_wait_sp_comp(bp, ~0x0UL)) { + BNX2X_ERR("Timeout waiting for SP elements to complete\n"); + bnx2x_nic_unload(bp, UNLOAD_CLOSE); + return -EBUSY; + } + + bnx2x_dcbx_init(bp); + return 0; + +#ifndef BNX2X_STOP_ON_ERROR +load_error4: +#ifdef BCM_CNIC + /* Disable Timer scan */ + REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 0); +#endif +load_error3: + bnx2x_int_disable_sync(bp, 1); + + /* Clean queueable objects */ + bnx2x_squeeze_objects(bp); + + /* Free SKBs, SGEs, TPA pool and driver internals */ + bnx2x_free_skbs(bp); + for_each_rx_queue(bp, i) + bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); + + /* Release IRQs */ + bnx2x_free_irq(bp); +load_error2: + if (!BP_NOMCP(bp)) { + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0); + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0); + } + + bp->port.pmf = 0; +load_error1: + bnx2x_napi_disable(bp); +load_error0: + bnx2x_free_mem(bp); + + return rc; +#endif /* ! BNX2X_STOP_ON_ERROR */ +} + +/* must be called with rtnl_lock */ +int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode) +{ + int i; + bool global = false; + + if ((bp->state == BNX2X_STATE_CLOSED) || + (bp->state == BNX2X_STATE_ERROR)) { + /* We can get here if the driver has been unloaded + * during parity error recovery and is either waiting for a + * leader to complete or for other functions to unload and + * then ifdown has been issued. In this case we want to + * unload and let other functions to complete a recovery + * process. + */ + bp->recovery_state = BNX2X_RECOVERY_DONE; + bp->is_leader = 0; + bnx2x_release_leader_lock(bp); + smp_mb(); + + DP(NETIF_MSG_HW, "Releasing a leadership...\n"); + + return -EINVAL; + } + + /* + * It's important to set the bp->state to the value different from + * BNX2X_STATE_OPEN and only then stop the Tx. Otherwise bnx2x_tx_int() + * may restart the Tx from the NAPI context (see bnx2x_tx_int()). + */ + bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; + smp_mb(); + + /* Stop Tx */ + bnx2x_tx_disable(bp); + +#ifdef BCM_CNIC + bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD); +#endif + + bp->rx_mode = BNX2X_RX_MODE_NONE; + + del_timer_sync(&bp->timer); + + /* Set ALWAYS_ALIVE bit in shmem */ + bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE; + + bnx2x_drv_pulse(bp); + + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + + /* Cleanup the chip if needed */ + if (unload_mode != UNLOAD_RECOVERY) + bnx2x_chip_cleanup(bp, unload_mode); + else { + /* Send the UNLOAD_REQUEST to the MCP */ + bnx2x_send_unload_req(bp, unload_mode); + + /* + * Prevent transactions to host from the functions on the + * engine that doesn't reset global blocks in case of global + * attention once gloabl blocks are reset and gates are opened + * (the engine which leader will perform the recovery + * last). + */ + if (!CHIP_IS_E1x(bp)) + bnx2x_pf_disable(bp); + + /* Disable HW interrupts, NAPI */ + bnx2x_netif_stop(bp, 1); + + /* Release IRQs */ + bnx2x_free_irq(bp); + + /* Report UNLOAD_DONE to MCP */ + bnx2x_send_unload_done(bp); + } + + /* + * At this stage no more interrupts will arrive so we may safly clean + * the queueable objects here in case they failed to get cleaned so far. + */ + bnx2x_squeeze_objects(bp); + + /* There should be no more pending SP commands at this stage */ + bp->sp_state = 0; + + bp->port.pmf = 0; + + /* Free SKBs, SGEs, TPA pool and driver internals */ + bnx2x_free_skbs(bp); + for_each_rx_queue(bp, i) + bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); + + bnx2x_free_mem(bp); + + bp->state = BNX2X_STATE_CLOSED; + + /* Check if there are pending parity attentions. If there are - set + * RECOVERY_IN_PROGRESS. + */ + if (bnx2x_chk_parity_attn(bp, &global, false)) { + bnx2x_set_reset_in_progress(bp); + + /* Set RESET_IS_GLOBAL if needed */ + if (global) + bnx2x_set_reset_global(bp); + } + + + /* The last driver must disable a "close the gate" if there is no + * parity attention or "process kill" pending. + */ + if (!bnx2x_dec_load_cnt(bp) && bnx2x_reset_is_done(bp, BP_PATH(bp))) + bnx2x_disable_close_the_gate(bp); + + return 0; +} + +int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state) +{ + u16 pmcsr; + + /* If there is no power capability, silently succeed */ + if (!bp->pm_cap) { + DP(NETIF_MSG_HW, "No power capability. Breaking.\n"); + return 0; + } + + pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr); + + switch (state) { + case PCI_D0: + pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, + ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) | + PCI_PM_CTRL_PME_STATUS)); + + if (pmcsr & PCI_PM_CTRL_STATE_MASK) + /* delay required during transition out of D3hot */ + msleep(20); + break; + + case PCI_D3hot: + /* If there are other clients above don't + shut down the power */ + if (atomic_read(&bp->pdev->enable_cnt) != 1) + return 0; + /* Don't shut down the power for emulation and FPGA */ + if (CHIP_REV_IS_SLOW(bp)) + return 0; + + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + pmcsr |= 3; + + if (bp->wol) + pmcsr |= PCI_PM_CTRL_PME_ENABLE; + + pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, + pmcsr); + + /* No more memory access after this point until + * device is brought back to D0. + */ + break; + + default: + return -EINVAL; + } + return 0; +} + +/* + * net_device service functions + */ +int bnx2x_poll(struct napi_struct *napi, int budget) +{ + int work_done = 0; + u8 cos; + struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath, + napi); + struct bnx2x *bp = fp->bp; + + while (1) { +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) { + napi_complete(napi); + return 0; + } +#endif + + for_each_cos_in_tx_queue(fp, cos) + if (bnx2x_tx_queue_has_work(&fp->txdata[cos])) + bnx2x_tx_int(bp, &fp->txdata[cos]); + + + if (bnx2x_has_rx_work(fp)) { + work_done += bnx2x_rx_int(fp, budget - work_done); + + /* must not complete if we consumed full budget */ + if (work_done >= budget) + break; + } + + /* Fall out from the NAPI loop if needed */ + if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) { +#ifdef BCM_CNIC + /* No need to update SB for FCoE L2 ring as long as + * it's connected to the default SB and the SB + * has been updated when NAPI was scheduled. + */ + if (IS_FCOE_FP(fp)) { + napi_complete(napi); + break; + } +#endif + + bnx2x_update_fpsb_idx(fp); + /* bnx2x_has_rx_work() reads the status block, + * thus we need to ensure that status block indices + * have been actually read (bnx2x_update_fpsb_idx) + * prior to this check (bnx2x_has_rx_work) so that + * we won't write the "newer" value of the status block + * to IGU (if there was a DMA right after + * bnx2x_has_rx_work and if there is no rmb, the memory + * reading (bnx2x_update_fpsb_idx) may be postponed + * to right before bnx2x_ack_sb). In this case there + * will never be another interrupt until there is + * another update of the status block, while there + * is still unhandled work. + */ + rmb(); + + if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) { + napi_complete(napi); + /* Re-enable interrupts */ + DP(NETIF_MSG_HW, + "Update index to %d\n", fp->fp_hc_idx); + bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, + le16_to_cpu(fp->fp_hc_idx), + IGU_INT_ENABLE, 1); + break; + } + } + } + + return work_done; +} + +/* we split the first BD into headers and data BDs + * to ease the pain of our fellow microcode engineers + * we use one mapping for both BDs + * So far this has only been observed to happen + * in Other Operating Systems(TM) + */ +static noinline u16 bnx2x_tx_split(struct bnx2x *bp, + struct bnx2x_fp_txdata *txdata, + struct sw_tx_bd *tx_buf, + struct eth_tx_start_bd **tx_bd, u16 hlen, + u16 bd_prod, int nbd) +{ + struct eth_tx_start_bd *h_tx_bd = *tx_bd; + struct eth_tx_bd *d_tx_bd; + dma_addr_t mapping; + int old_len = le16_to_cpu(h_tx_bd->nbytes); + + /* first fix first BD */ + h_tx_bd->nbd = cpu_to_le16(nbd); + h_tx_bd->nbytes = cpu_to_le16(hlen); + + DP(NETIF_MSG_TX_QUEUED, "TSO split header size is %d " + "(%x:%x) nbd %d\n", h_tx_bd->nbytes, h_tx_bd->addr_hi, + h_tx_bd->addr_lo, h_tx_bd->nbd); + + /* now get a new data BD + * (after the pbd) and fill it */ + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + d_tx_bd = &txdata->tx_desc_ring[bd_prod].reg_bd; + + mapping = HILO_U64(le32_to_cpu(h_tx_bd->addr_hi), + le32_to_cpu(h_tx_bd->addr_lo)) + hlen; + + d_tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + d_tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + d_tx_bd->nbytes = cpu_to_le16(old_len - hlen); + + /* this marks the BD as one that has no individual mapping */ + tx_buf->flags |= BNX2X_TSO_SPLIT_BD; + + DP(NETIF_MSG_TX_QUEUED, + "TSO split data size is %d (%x:%x)\n", + d_tx_bd->nbytes, d_tx_bd->addr_hi, d_tx_bd->addr_lo); + + /* update tx_bd */ + *tx_bd = (struct eth_tx_start_bd *)d_tx_bd; + + return bd_prod; +} + +static inline u16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix) +{ + if (fix > 0) + csum = (u16) ~csum_fold(csum_sub(csum, + csum_partial(t_header - fix, fix, 0))); + + else if (fix < 0) + csum = (u16) ~csum_fold(csum_add(csum, + csum_partial(t_header, -fix, 0))); + + return swab16(csum); +} + +static inline u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb) +{ + u32 rc; + + if (skb->ip_summed != CHECKSUM_PARTIAL) + rc = XMIT_PLAIN; + + else { + if (vlan_get_protocol(skb) == htons(ETH_P_IPV6)) { + rc = XMIT_CSUM_V6; + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + rc |= XMIT_CSUM_TCP; + + } else { + rc = XMIT_CSUM_V4; + if (ip_hdr(skb)->protocol == IPPROTO_TCP) + rc |= XMIT_CSUM_TCP; + } + } + + if (skb_is_gso_v6(skb)) + rc |= XMIT_GSO_V6 | XMIT_CSUM_TCP | XMIT_CSUM_V6; + else if (skb_is_gso(skb)) + rc |= XMIT_GSO_V4 | XMIT_CSUM_V4 | XMIT_CSUM_TCP; + + return rc; +} + +#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3) +/* check if packet requires linearization (packet is too fragmented) + no need to check fragmentation if page size > 8K (there will be no + violation to FW restrictions) */ +static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb, + u32 xmit_type) +{ + int to_copy = 0; + int hlen = 0; + int first_bd_sz = 0; + + /* 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */ + if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - 3)) { + + if (xmit_type & XMIT_GSO) { + unsigned short lso_mss = skb_shinfo(skb)->gso_size; + /* Check if LSO packet needs to be copied: + 3 = 1 (for headers BD) + 2 (for PBD and last BD) */ + int wnd_size = MAX_FETCH_BD - 3; + /* Number of windows to check */ + int num_wnds = skb_shinfo(skb)->nr_frags - wnd_size; + int wnd_idx = 0; + int frag_idx = 0; + u32 wnd_sum = 0; + + /* Headers length */ + hlen = (int)(skb_transport_header(skb) - skb->data) + + tcp_hdrlen(skb); + + /* Amount of data (w/o headers) on linear part of SKB*/ + first_bd_sz = skb_headlen(skb) - hlen; + + wnd_sum = first_bd_sz; + + /* Calculate the first sum - it's special */ + for (frag_idx = 0; frag_idx < wnd_size - 1; frag_idx++) + wnd_sum += + skb_shinfo(skb)->frags[frag_idx].size; + + /* If there was data on linear skb data - check it */ + if (first_bd_sz > 0) { + if (unlikely(wnd_sum < lso_mss)) { + to_copy = 1; + goto exit_lbl; + } + + wnd_sum -= first_bd_sz; + } + + /* Others are easier: run through the frag list and + check all windows */ + for (wnd_idx = 0; wnd_idx <= num_wnds; wnd_idx++) { + wnd_sum += + skb_shinfo(skb)->frags[wnd_idx + wnd_size - 1].size; + + if (unlikely(wnd_sum < lso_mss)) { + to_copy = 1; + break; + } + wnd_sum -= + skb_shinfo(skb)->frags[wnd_idx].size; + } + } else { + /* in non-LSO too fragmented packet should always + be linearized */ + to_copy = 1; + } + } + +exit_lbl: + if (unlikely(to_copy)) + DP(NETIF_MSG_TX_QUEUED, + "Linearization IS REQUIRED for %s packet. " + "num_frags %d hlen %d first_bd_sz %d\n", + (xmit_type & XMIT_GSO) ? "LSO" : "non-LSO", + skb_shinfo(skb)->nr_frags, hlen, first_bd_sz); + + return to_copy; +} +#endif + +static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data, + u32 xmit_type) +{ + *parsing_data |= (skb_shinfo(skb)->gso_size << + ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) & + ETH_TX_PARSE_BD_E2_LSO_MSS; + if ((xmit_type & XMIT_GSO_V6) && + (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6)) + *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR; +} + +/** + * bnx2x_set_pbd_gso - update PBD in GSO case. + * + * @skb: packet skb + * @pbd: parse BD + * @xmit_type: xmit flags + */ +static inline void bnx2x_set_pbd_gso(struct sk_buff *skb, + struct eth_tx_parse_bd_e1x *pbd, + u32 xmit_type) +{ + pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size); + pbd->tcp_send_seq = swab32(tcp_hdr(skb)->seq); + pbd->tcp_flags = pbd_tcp_flags(skb); + + if (xmit_type & XMIT_GSO_V4) { + pbd->ip_id = swab16(ip_hdr(skb)->id); + pbd->tcp_pseudo_csum = + swab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr, + ip_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0)); + + } else + pbd->tcp_pseudo_csum = + swab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, + 0, IPPROTO_TCP, 0)); + + pbd->global_data |= ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN; +} + +/** + * bnx2x_set_pbd_csum_e2 - update PBD with checksum and return header length + * + * @bp: driver handle + * @skb: packet skb + * @parsing_data: data to be updated + * @xmit_type: xmit flags + * + * 57712 related + */ +static inline u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, + u32 *parsing_data, u32 xmit_type) +{ + *parsing_data |= + ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) << + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W; + + if (xmit_type & XMIT_CSUM_TCP) { + *parsing_data |= ((tcp_hdrlen(skb) / 4) << + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & + ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; + + return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; + } else + /* We support checksum offload for TCP and UDP only. + * No need to pass the UDP header length - it's a constant. + */ + return skb_transport_header(skb) + + sizeof(struct udphdr) - skb->data; +} + +static inline void bnx2x_set_sbd_csum(struct bnx2x *bp, struct sk_buff *skb, + struct eth_tx_start_bd *tx_start_bd, u32 xmit_type) +{ + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM; + + if (xmit_type & XMIT_CSUM_V4) + tx_start_bd->bd_flags.as_bitfield |= + ETH_TX_BD_FLAGS_IP_CSUM; + else + tx_start_bd->bd_flags.as_bitfield |= + ETH_TX_BD_FLAGS_IPV6; + + if (!(xmit_type & XMIT_CSUM_TCP)) + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IS_UDP; +} + +/** + * bnx2x_set_pbd_csum - update PBD with checksum and return header length + * + * @bp: driver handle + * @skb: packet skb + * @pbd: parse BD to be updated + * @xmit_type: xmit flags + */ +static inline u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, + struct eth_tx_parse_bd_e1x *pbd, + u32 xmit_type) +{ + u8 hlen = (skb_network_header(skb) - skb->data) >> 1; + + /* for now NS flag is not used in Linux */ + pbd->global_data = + (hlen | ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) << + ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT)); + + pbd->ip_hlen_w = (skb_transport_header(skb) - + skb_network_header(skb)) >> 1; + + hlen += pbd->ip_hlen_w; + + /* We support checksum offload for TCP and UDP only */ + if (xmit_type & XMIT_CSUM_TCP) + hlen += tcp_hdrlen(skb) / 2; + else + hlen += sizeof(struct udphdr) / 2; + + pbd->total_hlen_w = cpu_to_le16(hlen); + hlen = hlen*2; + + if (xmit_type & XMIT_CSUM_TCP) { + pbd->tcp_pseudo_csum = swab16(tcp_hdr(skb)->check); + + } else { + s8 fix = SKB_CS_OFF(skb); /* signed! */ + + DP(NETIF_MSG_TX_QUEUED, + "hlen %d fix %d csum before fix %x\n", + le16_to_cpu(pbd->total_hlen_w), fix, SKB_CS(skb)); + + /* HW bug: fixup the CSUM */ + pbd->tcp_pseudo_csum = + bnx2x_csum_fix(skb_transport_header(skb), + SKB_CS(skb), fix); + + DP(NETIF_MSG_TX_QUEUED, "csum after fix %x\n", + pbd->tcp_pseudo_csum); + } + + return hlen; +} + +/* called with netif_tx_lock + * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call + * netif_wake_queue() + */ +netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + struct bnx2x_fastpath *fp; + struct netdev_queue *txq; + struct bnx2x_fp_txdata *txdata; + struct sw_tx_bd *tx_buf; + struct eth_tx_start_bd *tx_start_bd, *first_bd; + struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL; + struct eth_tx_parse_bd_e1x *pbd_e1x = NULL; + struct eth_tx_parse_bd_e2 *pbd_e2 = NULL; + u32 pbd_e2_parsing_data = 0; + u16 pkt_prod, bd_prod; + int nbd, txq_index, fp_index, txdata_index; + dma_addr_t mapping; + u32 xmit_type = bnx2x_xmit_type(bp, skb); + int i; + u8 hlen = 0; + __le16 pkt_size = 0; + struct ethhdr *eth; + u8 mac_type = UNICAST_ADDRESS; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return NETDEV_TX_BUSY; +#endif + + txq_index = skb_get_queue_mapping(skb); + txq = netdev_get_tx_queue(dev, txq_index); + + BUG_ON(txq_index >= MAX_ETH_TXQ_IDX(bp) + FCOE_PRESENT); + + /* decode the fastpath index and the cos index from the txq */ + fp_index = TXQ_TO_FP(txq_index); + txdata_index = TXQ_TO_COS(txq_index); + +#ifdef BCM_CNIC + /* + * Override the above for the FCoE queue: + * - FCoE fp entry is right after the ETH entries. + * - FCoE L2 queue uses bp->txdata[0] only. + */ + if (unlikely(!NO_FCOE(bp) && (txq_index == + bnx2x_fcoe_tx(bp, txq_index)))) { + fp_index = FCOE_IDX; + txdata_index = 0; + } +#endif + + /* enable this debug print to view the transmission queue being used + DP(BNX2X_MSG_FP, "indices: txq %d, fp %d, txdata %d", + txq_index, fp_index, txdata_index); */ + + /* locate the fastpath and the txdata */ + fp = &bp->fp[fp_index]; + txdata = &fp->txdata[txdata_index]; + + /* enable this debug print to view the tranmission details + DP(BNX2X_MSG_FP,"transmitting packet cid %d fp index %d txdata_index %d" + " tx_data ptr %p fp pointer %p", + txdata->cid, fp_index, txdata_index, txdata, fp); */ + + if (unlikely(bnx2x_tx_avail(bp, txdata) < + (skb_shinfo(skb)->nr_frags + 3))) { + fp->eth_q_stats.driver_xoff++; + netif_tx_stop_queue(txq); + BNX2X_ERR("BUG! Tx ring full when queue awake!\n"); + return NETDEV_TX_BUSY; + } + + DP(NETIF_MSG_TX_QUEUED, "queue[%d]: SKB: summed %x protocol %x " + "protocol(%x,%x) gso type %x xmit_type %x\n", + txq_index, skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr, + ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type); + + eth = (struct ethhdr *)skb->data; + + /* set flag according to packet type (UNICAST_ADDRESS is default)*/ + if (unlikely(is_multicast_ether_addr(eth->h_dest))) { + if (is_broadcast_ether_addr(eth->h_dest)) + mac_type = BROADCAST_ADDRESS; + else + mac_type = MULTICAST_ADDRESS; + } + +#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3) + /* First, check if we need to linearize the skb (due to FW + restrictions). No need to check fragmentation if page size > 8K + (there will be no violation to FW restrictions) */ + if (bnx2x_pkt_req_lin(bp, skb, xmit_type)) { + /* Statistics of linearization */ + bp->lin_cnt++; + if (skb_linearize(skb) != 0) { + DP(NETIF_MSG_TX_QUEUED, "SKB linearization failed - " + "silently dropping this SKB\n"); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + } +#endif + /* Map skb linear data for DMA */ + mapping = dma_map_single(&bp->pdev->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { + DP(NETIF_MSG_TX_QUEUED, "SKB mapping failed - " + "silently dropping this SKB\n"); + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; + } + /* + Please read carefully. First we use one BD which we mark as start, + then we have a parsing info BD (used for TSO or xsum), + and only then we have the rest of the TSO BDs. + (don't forget to mark the last one as last, + and to unmap only AFTER you write to the BD ...) + And above all, all pdb sizes are in words - NOT DWORDS! + */ + + /* get current pkt produced now - advance it just before sending packet + * since mapping of pages may fail and cause packet to be dropped + */ + pkt_prod = txdata->tx_pkt_prod; + bd_prod = TX_BD(txdata->tx_bd_prod); + + /* get a tx_buf and first BD + * tx_start_bd may be changed during SPLIT, + * but first_bd will always stay first + */ + tx_buf = &txdata->tx_buf_ring[TX_BD(pkt_prod)]; + tx_start_bd = &txdata->tx_desc_ring[bd_prod].start_bd; + first_bd = tx_start_bd; + + tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; + SET_FLAG(tx_start_bd->general_data, ETH_TX_START_BD_ETH_ADDR_TYPE, + mac_type); + + /* header nbd */ + SET_FLAG(tx_start_bd->general_data, ETH_TX_START_BD_HDR_NBDS, 1); + + /* remember the first BD of the packet */ + tx_buf->first_bd = txdata->tx_bd_prod; + tx_buf->skb = skb; + tx_buf->flags = 0; + + DP(NETIF_MSG_TX_QUEUED, + "sending pkt %u @%p next_idx %u bd %u @%p\n", + pkt_prod, tx_buf, txdata->tx_pkt_prod, bd_prod, tx_start_bd); + + if (vlan_tx_tag_present(skb)) { + tx_start_bd->vlan_or_ethertype = + cpu_to_le16(vlan_tx_tag_get(skb)); + tx_start_bd->bd_flags.as_bitfield |= + (X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT); + } else + tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod); + + /* turn on parsing and get a BD */ + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + + if (xmit_type & XMIT_CSUM) + bnx2x_set_sbd_csum(bp, skb, tx_start_bd, xmit_type); + + if (!CHIP_IS_E1x(bp)) { + pbd_e2 = &txdata->tx_desc_ring[bd_prod].parse_bd_e2; + memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2)); + /* Set PBD in checksum offload case */ + if (xmit_type & XMIT_CSUM) + hlen = bnx2x_set_pbd_csum_e2(bp, skb, + &pbd_e2_parsing_data, + xmit_type); + if (IS_MF_SI(bp)) { + /* + * fill in the MAC addresses in the PBD - for local + * switching + */ + bnx2x_set_fw_mac_addr(&pbd_e2->src_mac_addr_hi, + &pbd_e2->src_mac_addr_mid, + &pbd_e2->src_mac_addr_lo, + eth->h_source); + bnx2x_set_fw_mac_addr(&pbd_e2->dst_mac_addr_hi, + &pbd_e2->dst_mac_addr_mid, + &pbd_e2->dst_mac_addr_lo, + eth->h_dest); + } + } else { + pbd_e1x = &txdata->tx_desc_ring[bd_prod].parse_bd_e1x; + memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x)); + /* Set PBD in checksum offload case */ + if (xmit_type & XMIT_CSUM) + hlen = bnx2x_set_pbd_csum(bp, skb, pbd_e1x, xmit_type); + + } + + /* Setup the data pointer of the first BD of the packet */ + tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + nbd = 2; /* start_bd + pbd + frags (updated when pages are mapped) */ + tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb)); + pkt_size = tx_start_bd->nbytes; + + DP(NETIF_MSG_TX_QUEUED, "first bd @%p addr (%x:%x) nbd %d" + " nbytes %d flags %x vlan %x\n", + tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo, + le16_to_cpu(tx_start_bd->nbd), le16_to_cpu(tx_start_bd->nbytes), + tx_start_bd->bd_flags.as_bitfield, + le16_to_cpu(tx_start_bd->vlan_or_ethertype)); + + if (xmit_type & XMIT_GSO) { + + DP(NETIF_MSG_TX_QUEUED, + "TSO packet len %d hlen %d total len %d tso size %d\n", + skb->len, hlen, skb_headlen(skb), + skb_shinfo(skb)->gso_size); + + tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO; + + if (unlikely(skb_headlen(skb) > hlen)) + bd_prod = bnx2x_tx_split(bp, txdata, tx_buf, + &tx_start_bd, hlen, + bd_prod, ++nbd); + if (!CHIP_IS_E1x(bp)) + bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data, + xmit_type); + else + bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type); + } + + /* Set the PBD's parsing_data field if not zero + * (for the chips newer than 57711). + */ + if (pbd_e2_parsing_data) + pbd_e2->parsing_data = cpu_to_le32(pbd_e2_parsing_data); + + tx_data_bd = (struct eth_tx_bd *)tx_start_bd; + + /* Handle fragmented skb */ + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + mapping = dma_map_page(&bp->pdev->dev, frag->page, + frag->page_offset, frag->size, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { + + DP(NETIF_MSG_TX_QUEUED, "Unable to map page - " + "dropping packet...\n"); + + /* we need unmap all buffers already mapped + * for this SKB; + * first_bd->nbd need to be properly updated + * before call to bnx2x_free_tx_pkt + */ + first_bd->nbd = cpu_to_le16(nbd); + bnx2x_free_tx_pkt(bp, txdata, + TX_BD(txdata->tx_pkt_prod)); + return NETDEV_TX_OK; + } + + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + tx_data_bd = &txdata->tx_desc_ring[bd_prod].reg_bd; + if (total_pkt_bd == NULL) + total_pkt_bd = &txdata->tx_desc_ring[bd_prod].reg_bd; + + tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + tx_data_bd->nbytes = cpu_to_le16(frag->size); + le16_add_cpu(&pkt_size, frag->size); + nbd++; + + DP(NETIF_MSG_TX_QUEUED, + "frag %d bd @%p addr (%x:%x) nbytes %d\n", + i, tx_data_bd, tx_data_bd->addr_hi, tx_data_bd->addr_lo, + le16_to_cpu(tx_data_bd->nbytes)); + } + + DP(NETIF_MSG_TX_QUEUED, "last bd @%p\n", tx_data_bd); + + /* update with actual num BDs */ + first_bd->nbd = cpu_to_le16(nbd); + + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + + /* now send a tx doorbell, counting the next BD + * if the packet contains or ends with it + */ + if (TX_BD_POFF(bd_prod) < nbd) + nbd++; + + /* total_pkt_bytes should be set on the first data BD if + * it's not an LSO packet and there is more than one + * data BD. In this case pkt_size is limited by an MTU value. + * However we prefer to set it for an LSO packet (while we don't + * have to) in order to save some CPU cycles in a none-LSO + * case, when we much more care about them. + */ + if (total_pkt_bd != NULL) + total_pkt_bd->total_pkt_bytes = pkt_size; + + if (pbd_e1x) + DP(NETIF_MSG_TX_QUEUED, + "PBD (E1X) @%p ip_data %x ip_hlen %u ip_id %u lso_mss %u" + " tcp_flags %x xsum %x seq %u hlen %u\n", + pbd_e1x, pbd_e1x->global_data, pbd_e1x->ip_hlen_w, + pbd_e1x->ip_id, pbd_e1x->lso_mss, pbd_e1x->tcp_flags, + pbd_e1x->tcp_pseudo_csum, pbd_e1x->tcp_send_seq, + le16_to_cpu(pbd_e1x->total_hlen_w)); + if (pbd_e2) + DP(NETIF_MSG_TX_QUEUED, + "PBD (E2) @%p dst %x %x %x src %x %x %x parsing_data %x\n", + pbd_e2, pbd_e2->dst_mac_addr_hi, pbd_e2->dst_mac_addr_mid, + pbd_e2->dst_mac_addr_lo, pbd_e2->src_mac_addr_hi, + pbd_e2->src_mac_addr_mid, pbd_e2->src_mac_addr_lo, + pbd_e2->parsing_data); + DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d bd %u\n", nbd, bd_prod); + + txdata->tx_pkt_prod++; + /* + * Make sure that the BD data is updated before updating the producer + * since FW might read the BD right after the producer is updated. + * This is only applicable for weak-ordered memory model archs such + * as IA-64. The following barrier is also mandatory since FW will + * assumes packets must have BDs. + */ + wmb(); + + txdata->tx_db.data.prod += nbd; + barrier(); + + DOORBELL(bp, txdata->cid, txdata->tx_db.raw); + + mmiowb(); + + txdata->tx_bd_prod += nbd; + + if (unlikely(bnx2x_tx_avail(bp, txdata) < MAX_SKB_FRAGS + 3)) { + netif_tx_stop_queue(txq); + + /* paired memory barrier is in bnx2x_tx_int(), we have to keep + * ordering of set_bit() in netif_tx_stop_queue() and read of + * fp->bd_tx_cons */ + smp_mb(); + + fp->eth_q_stats.driver_xoff++; + if (bnx2x_tx_avail(bp, txdata) >= MAX_SKB_FRAGS + 3) + netif_tx_wake_queue(txq); + } + txdata->tx_pkt++; + + return NETDEV_TX_OK; +} + +/** + * bnx2x_setup_tc - routine to configure net_device for multi tc + * + * @netdev: net device to configure + * @tc: number of traffic classes to enable + * + * callback connected to the ndo_setup_tc function pointer + */ +int bnx2x_setup_tc(struct net_device *dev, u8 num_tc) +{ + int cos, prio, count, offset; + struct bnx2x *bp = netdev_priv(dev); + + /* setup tc must be called under rtnl lock */ + ASSERT_RTNL(); + + /* no traffic classes requested. aborting */ + if (!num_tc) { + netdev_reset_tc(dev); + return 0; + } + + /* requested to support too many traffic classes */ + if (num_tc > bp->max_cos) { + DP(NETIF_MSG_TX_ERR, "support for too many traffic classes" + " requested: %d. max supported is %d", + num_tc, bp->max_cos); + return -EINVAL; + } + + /* declare amount of supported traffic classes */ + if (netdev_set_num_tc(dev, num_tc)) { + DP(NETIF_MSG_TX_ERR, "failed to declare %d traffic classes", + num_tc); + return -EINVAL; + } + + /* configure priority to traffic class mapping */ + for (prio = 0; prio < BNX2X_MAX_PRIORITY; prio++) { + netdev_set_prio_tc_map(dev, prio, bp->prio_to_cos[prio]); + DP(BNX2X_MSG_SP, "mapping priority %d to tc %d", + prio, bp->prio_to_cos[prio]); + } + + + /* Use this configuration to diffrentiate tc0 from other COSes + This can be used for ets or pfc, and save the effort of setting + up a multio class queue disc or negotiating DCBX with a switch + netdev_set_prio_tc_map(dev, 0, 0); + DP(BNX2X_MSG_SP, "mapping priority %d to tc %d", 0, 0); + for (prio = 1; prio < 16; prio++) { + netdev_set_prio_tc_map(dev, prio, 1); + DP(BNX2X_MSG_SP, "mapping priority %d to tc %d", prio, 1); + } */ + + /* configure traffic class to transmission queue mapping */ + for (cos = 0; cos < bp->max_cos; cos++) { + count = BNX2X_NUM_ETH_QUEUES(bp); + offset = cos * MAX_TXQS_PER_COS; + netdev_set_tc_queue(dev, cos, count, offset); + DP(BNX2X_MSG_SP, "mapping tc %d to offset %d count %d", + cos, offset, count); + } + + return 0; +} + +/* called with rtnl_lock */ +int bnx2x_change_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + struct bnx2x *bp = netdev_priv(dev); + int rc = 0; + + if (!is_valid_ether_addr((u8 *)(addr->sa_data))) + return -EINVAL; + + if (netif_running(dev)) { + rc = bnx2x_set_eth_mac(bp, false); + if (rc) + return rc; + } + + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + + if (netif_running(dev)) + rc = bnx2x_set_eth_mac(bp, true); + + return rc; +} + +static void bnx2x_free_fp_mem_at(struct bnx2x *bp, int fp_index) +{ + union host_hc_status_block *sb = &bnx2x_fp(bp, fp_index, status_blk); + struct bnx2x_fastpath *fp = &bp->fp[fp_index]; + u8 cos; + + /* Common */ +#ifdef BCM_CNIC + if (IS_FCOE_IDX(fp_index)) { + memset(sb, 0, sizeof(union host_hc_status_block)); + fp->status_blk_mapping = 0; + + } else { +#endif + /* status blocks */ + if (!CHIP_IS_E1x(bp)) + BNX2X_PCI_FREE(sb->e2_sb, + bnx2x_fp(bp, fp_index, + status_blk_mapping), + sizeof(struct host_hc_status_block_e2)); + else + BNX2X_PCI_FREE(sb->e1x_sb, + bnx2x_fp(bp, fp_index, + status_blk_mapping), + sizeof(struct host_hc_status_block_e1x)); +#ifdef BCM_CNIC + } +#endif + /* Rx */ + if (!skip_rx_queue(bp, fp_index)) { + bnx2x_free_rx_bds(fp); + + /* fastpath rx rings: rx_buf rx_desc rx_comp */ + BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_buf_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_desc_ring), + bnx2x_fp(bp, fp_index, rx_desc_mapping), + sizeof(struct eth_rx_bd) * NUM_RX_BD); + + BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_comp_ring), + bnx2x_fp(bp, fp_index, rx_comp_mapping), + sizeof(struct eth_fast_path_rx_cqe) * + NUM_RCQ_BD); + + /* SGE ring */ + BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_page_ring)); + BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_sge_ring), + bnx2x_fp(bp, fp_index, rx_sge_mapping), + BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); + } + + /* Tx */ + if (!skip_tx_queue(bp, fp_index)) { + /* fastpath tx rings: tx_buf tx_desc */ + for_each_cos_in_tx_queue(fp, cos) { + struct bnx2x_fp_txdata *txdata = &fp->txdata[cos]; + + DP(BNX2X_MSG_SP, + "freeing tx memory of fp %d cos %d cid %d", + fp_index, cos, txdata->cid); + + BNX2X_FREE(txdata->tx_buf_ring); + BNX2X_PCI_FREE(txdata->tx_desc_ring, + txdata->tx_desc_mapping, + sizeof(union eth_tx_bd_types) * NUM_TX_BD); + } + } + /* end of fastpath */ +} + +void bnx2x_free_fp_mem(struct bnx2x *bp) +{ + int i; + for_each_queue(bp, i) + bnx2x_free_fp_mem_at(bp, i); +} + +static inline void set_sb_shortcuts(struct bnx2x *bp, int index) +{ + union host_hc_status_block status_blk = bnx2x_fp(bp, index, status_blk); + if (!CHIP_IS_E1x(bp)) { + bnx2x_fp(bp, index, sb_index_values) = + (__le16 *)status_blk.e2_sb->sb.index_values; + bnx2x_fp(bp, index, sb_running_index) = + (__le16 *)status_blk.e2_sb->sb.running_index; + } else { + bnx2x_fp(bp, index, sb_index_values) = + (__le16 *)status_blk.e1x_sb->sb.index_values; + bnx2x_fp(bp, index, sb_running_index) = + (__le16 *)status_blk.e1x_sb->sb.running_index; + } +} + +static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index) +{ + union host_hc_status_block *sb; + struct bnx2x_fastpath *fp = &bp->fp[index]; + int ring_size = 0; + u8 cos; + + /* if rx_ring_size specified - use it */ + int rx_ring_size = bp->rx_ring_size ? bp->rx_ring_size : + MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp); + + /* allocate at least number of buffers required by FW */ + rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA : + MIN_RX_SIZE_TPA, + rx_ring_size); + + /* Common */ + sb = &bnx2x_fp(bp, index, status_blk); +#ifdef BCM_CNIC + if (!IS_FCOE_IDX(index)) { +#endif + /* status blocks */ + if (!CHIP_IS_E1x(bp)) + BNX2X_PCI_ALLOC(sb->e2_sb, + &bnx2x_fp(bp, index, status_blk_mapping), + sizeof(struct host_hc_status_block_e2)); + else + BNX2X_PCI_ALLOC(sb->e1x_sb, + &bnx2x_fp(bp, index, status_blk_mapping), + sizeof(struct host_hc_status_block_e1x)); +#ifdef BCM_CNIC + } +#endif + + /* FCoE Queue uses Default SB and doesn't ACK the SB, thus no need to + * set shortcuts for it. + */ + if (!IS_FCOE_IDX(index)) + set_sb_shortcuts(bp, index); + + /* Tx */ + if (!skip_tx_queue(bp, index)) { + /* fastpath tx rings: tx_buf tx_desc */ + for_each_cos_in_tx_queue(fp, cos) { + struct bnx2x_fp_txdata *txdata = &fp->txdata[cos]; + + DP(BNX2X_MSG_SP, "allocating tx memory of " + "fp %d cos %d", + index, cos); + + BNX2X_ALLOC(txdata->tx_buf_ring, + sizeof(struct sw_tx_bd) * NUM_TX_BD); + BNX2X_PCI_ALLOC(txdata->tx_desc_ring, + &txdata->tx_desc_mapping, + sizeof(union eth_tx_bd_types) * NUM_TX_BD); + } + } + + /* Rx */ + if (!skip_rx_queue(bp, index)) { + /* fastpath rx rings: rx_buf rx_desc rx_comp */ + BNX2X_ALLOC(bnx2x_fp(bp, index, rx_buf_ring), + sizeof(struct sw_rx_bd) * NUM_RX_BD); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_desc_ring), + &bnx2x_fp(bp, index, rx_desc_mapping), + sizeof(struct eth_rx_bd) * NUM_RX_BD); + + BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_comp_ring), + &bnx2x_fp(bp, index, rx_comp_mapping), + sizeof(struct eth_fast_path_rx_cqe) * + NUM_RCQ_BD); + + /* SGE ring */ + BNX2X_ALLOC(bnx2x_fp(bp, index, rx_page_ring), + sizeof(struct sw_rx_page) * NUM_RX_SGE); + BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_sge_ring), + &bnx2x_fp(bp, index, rx_sge_mapping), + BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); + /* RX BD ring */ + bnx2x_set_next_page_rx_bd(fp); + + /* CQ ring */ + bnx2x_set_next_page_rx_cq(fp); + + /* BDs */ + ring_size = bnx2x_alloc_rx_bds(fp, rx_ring_size); + if (ring_size < rx_ring_size) + goto alloc_mem_err; + } + + return 0; + +/* handles low memory cases */ +alloc_mem_err: + BNX2X_ERR("Unable to allocate full memory for queue %d (size %d)\n", + index, ring_size); + /* FW will drop all packets if queue is not big enough, + * In these cases we disable the queue + * Min size is different for OOO, TPA and non-TPA queues + */ + if (ring_size < (fp->disable_tpa ? + MIN_RX_SIZE_NONTPA : MIN_RX_SIZE_TPA)) { + /* release memory allocated for this queue */ + bnx2x_free_fp_mem_at(bp, index); + return -ENOMEM; + } + return 0; +} + +int bnx2x_alloc_fp_mem(struct bnx2x *bp) +{ + int i; + + /** + * 1. Allocate FP for leading - fatal if error + * 2. {CNIC} Allocate FCoE FP - fatal if error + * 3. {CNIC} Allocate OOO + FWD - disable OOO if error + * 4. Allocate RSS - fix number of queues if error + */ + + /* leading */ + if (bnx2x_alloc_fp_mem_at(bp, 0)) + return -ENOMEM; + +#ifdef BCM_CNIC + if (!NO_FCOE(bp)) + /* FCoE */ + if (bnx2x_alloc_fp_mem_at(bp, FCOE_IDX)) + /* we will fail load process instead of mark + * NO_FCOE_FLAG + */ + return -ENOMEM; +#endif + + /* RSS */ + for_each_nondefault_eth_queue(bp, i) + if (bnx2x_alloc_fp_mem_at(bp, i)) + break; + + /* handle memory failures */ + if (i != BNX2X_NUM_ETH_QUEUES(bp)) { + int delta = BNX2X_NUM_ETH_QUEUES(bp) - i; + + WARN_ON(delta < 0); +#ifdef BCM_CNIC + /** + * move non eth FPs next to last eth FP + * must be done in that order + * FCOE_IDX < FWD_IDX < OOO_IDX + */ + + /* move FCoE fp even NO_FCOE_FLAG is on */ + bnx2x_move_fp(bp, FCOE_IDX, FCOE_IDX - delta); +#endif + bp->num_queues -= delta; + BNX2X_ERR("Adjusted num of queues from %d to %d\n", + bp->num_queues + delta, bp->num_queues); + } + + return 0; +} + +void bnx2x_free_mem_bp(struct bnx2x *bp) +{ + kfree(bp->fp); + kfree(bp->msix_table); + kfree(bp->ilt); +} + +int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp) +{ + struct bnx2x_fastpath *fp; + struct msix_entry *tbl; + struct bnx2x_ilt *ilt; + int msix_table_size = 0; + + /* + * The biggest MSI-X table we might need is as a maximum number of fast + * path IGU SBs plus default SB (for PF). + */ + msix_table_size = bp->igu_sb_cnt + 1; + + /* fp array: RSS plus CNIC related L2 queues */ + fp = kzalloc((BNX2X_MAX_RSS_COUNT(bp) + NON_ETH_CONTEXT_USE) * + sizeof(*fp), GFP_KERNEL); + if (!fp) + goto alloc_err; + bp->fp = fp; + + /* msix table */ + tbl = kzalloc(msix_table_size * sizeof(*tbl), GFP_KERNEL); + if (!tbl) + goto alloc_err; + bp->msix_table = tbl; + + /* ilt */ + ilt = kzalloc(sizeof(*ilt), GFP_KERNEL); + if (!ilt) + goto alloc_err; + bp->ilt = ilt; + + return 0; +alloc_err: + bnx2x_free_mem_bp(bp); + return -ENOMEM; + +} + +int bnx2x_reload_if_running(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (unlikely(!netif_running(dev))) + return 0; + + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + return bnx2x_nic_load(bp, LOAD_NORMAL); +} + +int bnx2x_get_cur_phy_idx(struct bnx2x *bp) +{ + u32 sel_phy_idx = 0; + if (bp->link_params.num_phys <= 1) + return INT_PHY; + + if (bp->link_vars.link_up) { + sel_phy_idx = EXT_PHY1; + /* In case link is SERDES, check if the EXT_PHY2 is the one */ + if ((bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) && + (bp->link_params.phy[EXT_PHY2].supported & SUPPORTED_FIBRE)) + sel_phy_idx = EXT_PHY2; + } else { + + switch (bnx2x_phy_selection(&bp->link_params)) { + case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY: + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: + sel_phy_idx = EXT_PHY1; + break; + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY: + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: + sel_phy_idx = EXT_PHY2; + break; + } + } + + return sel_phy_idx; + +} +int bnx2x_get_link_cfg_idx(struct bnx2x *bp) +{ + u32 sel_phy_idx = bnx2x_get_cur_phy_idx(bp); + /* + * The selected actived PHY is always after swapping (in case PHY + * swapping is enabled). So when swapping is enabled, we need to reverse + * the configuration + */ + + if (bp->link_params.multi_phy_config & + PORT_HW_CFG_PHY_SWAPPED_ENABLED) { + if (sel_phy_idx == EXT_PHY1) + sel_phy_idx = EXT_PHY2; + else if (sel_phy_idx == EXT_PHY2) + sel_phy_idx = EXT_PHY1; + } + return LINK_CONFIG_IDX(sel_phy_idx); +} + +#if defined(NETDEV_FCOE_WWNN) && defined(BCM_CNIC) +int bnx2x_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type) +{ + struct bnx2x *bp = netdev_priv(dev); + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + + switch (type) { + case NETDEV_FCOE_WWNN: + *wwn = HILO_U64(cp->fcoe_wwn_node_name_hi, + cp->fcoe_wwn_node_name_lo); + break; + case NETDEV_FCOE_WWPN: + *wwn = HILO_U64(cp->fcoe_wwn_port_name_hi, + cp->fcoe_wwn_port_name_lo); + break; + default: + return -EINVAL; + } + + return 0; +} +#endif + +/* called with rtnl_lock */ +int bnx2x_change_mtu(struct net_device *dev, int new_mtu) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (bp->recovery_state != BNX2X_RECOVERY_DONE) { + printk(KERN_ERR "Handling parity error recovery. Try again later\n"); + return -EAGAIN; + } + + if ((new_mtu > ETH_MAX_JUMBO_PACKET_SIZE) || + ((new_mtu + ETH_HLEN) < ETH_MIN_PACKET_SIZE)) + return -EINVAL; + + /* This does not race with packet allocation + * because the actual alloc size is + * only updated as part of load + */ + dev->mtu = new_mtu; + + return bnx2x_reload_if_running(dev); +} + +u32 bnx2x_fix_features(struct net_device *dev, u32 features) +{ + struct bnx2x *bp = netdev_priv(dev); + + /* TPA requires Rx CSUM offloading */ + if (!(features & NETIF_F_RXCSUM) || bp->disable_tpa) + features &= ~NETIF_F_LRO; + + return features; +} + +int bnx2x_set_features(struct net_device *dev, u32 features) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 flags = bp->flags; + bool bnx2x_reload = false; + + if (features & NETIF_F_LRO) + flags |= TPA_ENABLE_FLAG; + else + flags &= ~TPA_ENABLE_FLAG; + + if (features & NETIF_F_LOOPBACK) { + if (bp->link_params.loopback_mode != LOOPBACK_BMAC) { + bp->link_params.loopback_mode = LOOPBACK_BMAC; + bnx2x_reload = true; + } + } else { + if (bp->link_params.loopback_mode != LOOPBACK_NONE) { + bp->link_params.loopback_mode = LOOPBACK_NONE; + bnx2x_reload = true; + } + } + + if (flags ^ bp->flags) { + bp->flags = flags; + bnx2x_reload = true; + } + + if (bnx2x_reload) { + if (bp->recovery_state == BNX2X_RECOVERY_DONE) + return bnx2x_reload_if_running(dev); + /* else: bnx2x_nic_load() will be called at end of recovery */ + } + + return 0; +} + +void bnx2x_tx_timeout(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + +#ifdef BNX2X_STOP_ON_ERROR + if (!bp->panic) + bnx2x_panic(); +#endif + + smp_mb__before_clear_bit(); + set_bit(BNX2X_SP_RTNL_TX_TIMEOUT, &bp->sp_rtnl_state); + smp_mb__after_clear_bit(); + + /* This allows the netif to be shutdown gracefully before resetting */ + schedule_delayed_work(&bp->sp_rtnl_task, 0); +} + +int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp; + + if (!dev) { + dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n"); + return -ENODEV; + } + bp = netdev_priv(dev); + + rtnl_lock(); + + pci_save_state(pdev); + + if (!netif_running(dev)) { + rtnl_unlock(); + return 0; + } + + netif_device_detach(dev); + + bnx2x_nic_unload(bp, UNLOAD_CLOSE); + + bnx2x_set_power_state(bp, pci_choose_state(pdev, state)); + + rtnl_unlock(); + + return 0; +} + +int bnx2x_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp; + int rc; + + if (!dev) { + dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n"); + return -ENODEV; + } + bp = netdev_priv(dev); + + if (bp->recovery_state != BNX2X_RECOVERY_DONE) { + printk(KERN_ERR "Handling parity error recovery. Try again later\n"); + return -EAGAIN; + } + + rtnl_lock(); + + pci_restore_state(pdev); + + if (!netif_running(dev)) { + rtnl_unlock(); + return 0; + } + + bnx2x_set_power_state(bp, PCI_D0); + netif_device_attach(dev); + + /* Since the chip was reset, clear the FW sequence number */ + bp->fw_seq = 0; + rc = bnx2x_nic_load(bp, LOAD_OPEN); + + rtnl_unlock(); + + return rc; +} + + +void bnx2x_set_ctx_validation(struct bnx2x *bp, struct eth_context *cxt, + u32 cid) +{ + /* ustorm cxt validation */ + cxt->ustorm_ag_context.cdu_usage = + CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, cid), + CDU_REGION_NUMBER_UCM_AG, ETH_CONNECTION_TYPE); + /* xcontext validation */ + cxt->xstorm_ag_context.cdu_reserved = + CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, cid), + CDU_REGION_NUMBER_XCM_AG, ETH_CONNECTION_TYPE); +} + +static inline void storm_memset_hc_timeout(struct bnx2x *bp, u8 port, + u8 fw_sb_id, u8 sb_index, + u8 ticks) +{ + + u32 addr = BAR_CSTRORM_INTMEM + + CSTORM_STATUS_BLOCK_DATA_TIMEOUT_OFFSET(fw_sb_id, sb_index); + REG_WR8(bp, addr, ticks); + DP(NETIF_MSG_HW, "port %x fw_sb_id %d sb_index %d ticks %d\n", + port, fw_sb_id, sb_index, ticks); +} + +static inline void storm_memset_hc_disable(struct bnx2x *bp, u8 port, + u16 fw_sb_id, u8 sb_index, + u8 disable) +{ + u32 enable_flag = disable ? 0 : (1 << HC_INDEX_DATA_HC_ENABLED_SHIFT); + u32 addr = BAR_CSTRORM_INTMEM + + CSTORM_STATUS_BLOCK_DATA_FLAGS_OFFSET(fw_sb_id, sb_index); + u16 flags = REG_RD16(bp, addr); + /* clear and set */ + flags &= ~HC_INDEX_DATA_HC_ENABLED; + flags |= enable_flag; + REG_WR16(bp, addr, flags); + DP(NETIF_MSG_HW, "port %x fw_sb_id %d sb_index %d disable %d\n", + port, fw_sb_id, sb_index, disable); +} + +void bnx2x_update_coalesce_sb_index(struct bnx2x *bp, u8 fw_sb_id, + u8 sb_index, u8 disable, u16 usec) +{ + int port = BP_PORT(bp); + u8 ticks = usec / BNX2X_BTR; + + storm_memset_hc_timeout(bp, port, fw_sb_id, sb_index, ticks); + + disable = disable ? 1 : (usec ? 0 : 1); + storm_memset_hc_disable(bp, port, fw_sb_id, sb_index, disable); +} diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h new file mode 100644 index 000000000000..223bfeebc597 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -0,0 +1,1491 @@ +/* bnx2x_cmn.h: Broadcom Everest network driver. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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: Eilon Greenstein + * 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 + * + */ +#ifndef BNX2X_CMN_H +#define BNX2X_CMN_H + +#include +#include +#include + + +#include "bnx2x.h" + +/* This is used as a replacement for an MCP if it's not present */ +extern int load_count[2][3]; /* per-path: 0-common, 1-port0, 2-port1 */ + +extern int num_queues; + +/************************ Macros ********************************/ +#define BNX2X_PCI_FREE(x, y, size) \ + do { \ + if (x) { \ + dma_free_coherent(&bp->pdev->dev, size, (void *)x, y); \ + x = NULL; \ + y = 0; \ + } \ + } while (0) + +#define BNX2X_FREE(x) \ + do { \ + if (x) { \ + kfree((void *)x); \ + x = NULL; \ + } \ + } while (0) + +#define BNX2X_PCI_ALLOC(x, y, size) \ + do { \ + x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ + if (x == NULL) \ + goto alloc_mem_err; \ + memset((void *)x, 0, size); \ + } while (0) + +#define BNX2X_ALLOC(x, size) \ + do { \ + x = kzalloc(size, GFP_KERNEL); \ + if (x == NULL) \ + goto alloc_mem_err; \ + } while (0) + +/*********************** Interfaces **************************** + * Functions that need to be implemented by each driver version + */ +/* Init */ + +/** + * bnx2x_send_unload_req - request unload mode from the MCP. + * + * @bp: driver handle + * @unload_mode: requested function's unload mode + * + * Return unload mode returned by the MCP: COMMON, PORT or FUNC. + */ +u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode); + +/** + * bnx2x_send_unload_done - send UNLOAD_DONE command to the MCP. + * + * @bp: driver handle + */ +void bnx2x_send_unload_done(struct bnx2x *bp); + +/** + * bnx2x_config_rss_pf - configure RSS parameters. + * + * @bp: driver handle + * @ind_table: indirection table to configure + * @config_hash: re-configure RSS hash keys configuration + */ +int bnx2x_config_rss_pf(struct bnx2x *bp, u8 *ind_table, bool config_hash); + +/** + * bnx2x__init_func_obj - init function object + * + * @bp: driver handle + * + * Initializes the Function Object with the appropriate + * parameters which include a function slow path driver + * interface. + */ +void bnx2x__init_func_obj(struct bnx2x *bp); + +/** + * bnx2x_setup_queue - setup eth queue. + * + * @bp: driver handle + * @fp: pointer to the fastpath structure + * @leading: boolean + * + */ +int bnx2x_setup_queue(struct bnx2x *bp, struct bnx2x_fastpath *fp, + bool leading); + +/** + * bnx2x_setup_leading - bring up a leading eth queue. + * + * @bp: driver handle + */ +int bnx2x_setup_leading(struct bnx2x *bp); + +/** + * bnx2x_fw_command - send the MCP a request + * + * @bp: driver handle + * @command: request + * @param: request's parameter + * + * block until there is a reply + */ +u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param); + +/** + * bnx2x_initial_phy_init - initialize link parameters structure variables. + * + * @bp: driver handle + * @load_mode: current mode + */ +u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode); + +/** + * bnx2x_link_set - configure hw according to link parameters structure. + * + * @bp: driver handle + */ +void bnx2x_link_set(struct bnx2x *bp); + +/** + * bnx2x_link_test - query link status. + * + * @bp: driver handle + * @is_serdes: bool + * + * Returns 0 if link is UP. + */ +u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes); + +/** + * bnx2x_drv_pulse - write driver pulse to shmem + * + * @bp: driver handle + * + * writes the value in bp->fw_drv_pulse_wr_seq to drv_pulse mbox + * in the shmem. + */ +void bnx2x_drv_pulse(struct bnx2x *bp); + +/** + * bnx2x_igu_ack_sb - update IGU with current SB value + * + * @bp: driver handle + * @igu_sb_id: SB id + * @segment: SB segment + * @index: SB index + * @op: SB operation + * @update: is HW update required + */ +void bnx2x_igu_ack_sb(struct bnx2x *bp, u8 igu_sb_id, u8 segment, + u16 index, u8 op, u8 update); + +/* Disable transactions from chip to host */ +void bnx2x_pf_disable(struct bnx2x *bp); + +/** + * bnx2x__link_status_update - handles link status change. + * + * @bp: driver handle + */ +void bnx2x__link_status_update(struct bnx2x *bp); + +/** + * bnx2x_link_report - report link status to upper layer. + * + * @bp: driver handle + */ +void bnx2x_link_report(struct bnx2x *bp); + +/* None-atomic version of bnx2x_link_report() */ +void __bnx2x_link_report(struct bnx2x *bp); + +/** + * bnx2x_get_mf_speed - calculate MF speed. + * + * @bp: driver handle + * + * Takes into account current linespeed and MF configuration. + */ +u16 bnx2x_get_mf_speed(struct bnx2x *bp); + +/** + * bnx2x_msix_sp_int - MSI-X slowpath interrupt handler + * + * @irq: irq number + * @dev_instance: private instance + */ +irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance); + +/** + * bnx2x_interrupt - non MSI-X interrupt handler + * + * @irq: irq number + * @dev_instance: private instance + */ +irqreturn_t bnx2x_interrupt(int irq, void *dev_instance); +#ifdef BCM_CNIC + +/** + * bnx2x_cnic_notify - send command to cnic driver + * + * @bp: driver handle + * @cmd: command + */ +int bnx2x_cnic_notify(struct bnx2x *bp, int cmd); + +/** + * bnx2x_setup_cnic_irq_info - provides cnic with IRQ information + * + * @bp: driver handle + */ +void bnx2x_setup_cnic_irq_info(struct bnx2x *bp); +#endif + +/** + * bnx2x_int_enable - enable HW interrupts. + * + * @bp: driver handle + */ +void bnx2x_int_enable(struct bnx2x *bp); + +/** + * bnx2x_int_disable_sync - disable interrupts. + * + * @bp: driver handle + * @disable_hw: true, disable HW interrupts. + * + * This function ensures that there are no + * ISRs or SP DPCs (sp_task) are running after it returns. + */ +void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw); + +/** + * bnx2x_nic_init - init driver internals. + * + * @bp: driver handle + * @load_code: COMMON, PORT or FUNCTION + * + * Initializes: + * - rings + * - status blocks + * - etc. + */ +void bnx2x_nic_init(struct bnx2x *bp, u32 load_code); + +/** + * bnx2x_alloc_mem - allocate driver's memory. + * + * @bp: driver handle + */ +int bnx2x_alloc_mem(struct bnx2x *bp); + +/** + * bnx2x_free_mem - release driver's memory. + * + * @bp: driver handle + */ +void bnx2x_free_mem(struct bnx2x *bp); + +/** + * bnx2x_set_num_queues - set number of queues according to mode. + * + * @bp: driver handle + */ +void bnx2x_set_num_queues(struct bnx2x *bp); + +/** + * bnx2x_chip_cleanup - cleanup chip internals. + * + * @bp: driver handle + * @unload_mode: COMMON, PORT, FUNCTION + * + * - Cleanup MAC configuration. + * - Closes clients. + * - etc. + */ +void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode); + +/** + * bnx2x_acquire_hw_lock - acquire HW lock. + * + * @bp: driver handle + * @resource: resource bit which was locked + */ +int bnx2x_acquire_hw_lock(struct bnx2x *bp, u32 resource); + +/** + * bnx2x_release_hw_lock - release HW lock. + * + * @bp: driver handle + * @resource: resource bit which was locked + */ +int bnx2x_release_hw_lock(struct bnx2x *bp, u32 resource); + +/** + * bnx2x_release_leader_lock - release recovery leader lock + * + * @bp: driver handle + */ +int bnx2x_release_leader_lock(struct bnx2x *bp); + +/** + * bnx2x_set_eth_mac - configure eth MAC address in the HW + * + * @bp: driver handle + * @set: set or clear + * + * Configures according to the value in netdev->dev_addr. + */ +int bnx2x_set_eth_mac(struct bnx2x *bp, bool set); + +/** + * bnx2x_set_rx_mode - set MAC filtering configurations. + * + * @dev: netdevice + * + * called with netif_tx_lock from dev_mcast.c + * If bp->state is OPEN, should be called with + * netif_addr_lock_bh() + */ +void bnx2x_set_rx_mode(struct net_device *dev); + +/** + * bnx2x_set_storm_rx_mode - configure MAC filtering rules in a FW. + * + * @bp: driver handle + * + * If bp->state is OPEN, should be called with + * netif_addr_lock_bh(). + */ +void bnx2x_set_storm_rx_mode(struct bnx2x *bp); + +/** + * bnx2x_set_q_rx_mode - configures rx_mode for a single queue. + * + * @bp: driver handle + * @cl_id: client id + * @rx_mode_flags: rx mode configuration + * @rx_accept_flags: rx accept configuration + * @tx_accept_flags: tx accept configuration (tx switch) + * @ramrod_flags: ramrod configuration + */ +void bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id, + unsigned long rx_mode_flags, + unsigned long rx_accept_flags, + unsigned long tx_accept_flags, + unsigned long ramrod_flags); + +/* Parity errors related */ +void bnx2x_inc_load_cnt(struct bnx2x *bp); +u32 bnx2x_dec_load_cnt(struct bnx2x *bp); +bool bnx2x_chk_parity_attn(struct bnx2x *bp, bool *global, bool print); +bool bnx2x_reset_is_done(struct bnx2x *bp, int engine); +void bnx2x_set_reset_in_progress(struct bnx2x *bp); +void bnx2x_set_reset_global(struct bnx2x *bp); +void bnx2x_disable_close_the_gate(struct bnx2x *bp); + +/** + * bnx2x_sp_event - handle ramrods completion. + * + * @fp: fastpath handle for the event + * @rr_cqe: eth_rx_cqe + */ +void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe); + +/** + * bnx2x_ilt_set_info - prepare ILT configurations. + * + * @bp: driver handle + */ +void bnx2x_ilt_set_info(struct bnx2x *bp); + +/** + * bnx2x_dcbx_init - initialize dcbx protocol. + * + * @bp: driver handle + */ +void bnx2x_dcbx_init(struct bnx2x *bp); + +/** + * bnx2x_set_power_state - set power state to the requested value. + * + * @bp: driver handle + * @state: required state D0 or D3hot + * + * Currently only D0 and D3hot are supported. + */ +int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state); + +/** + * bnx2x_update_max_mf_config - update MAX part of MF configuration in HW. + * + * @bp: driver handle + * @value: new value + */ +void bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value); +/* Error handling */ +void bnx2x_panic_dump(struct bnx2x *bp); + +void bnx2x_fw_dump_lvl(struct bnx2x *bp, const char *lvl); + +/* dev_close main block */ +int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode); + +/* dev_open main block */ +int bnx2x_nic_load(struct bnx2x *bp, int load_mode); + +/* hard_xmit callback */ +netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev); + +/* setup_tc callback */ +int bnx2x_setup_tc(struct net_device *dev, u8 num_tc); + +/* select_queue callback */ +u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb); + +/* reload helper */ +int bnx2x_reload_if_running(struct net_device *dev); + +int bnx2x_change_mac_addr(struct net_device *dev, void *p); + +/* NAPI poll Rx part */ +int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget); + +void bnx2x_update_rx_prod(struct bnx2x *bp, struct bnx2x_fastpath *fp, + u16 bd_prod, u16 rx_comp_prod, u16 rx_sge_prod); + +/* NAPI poll Tx part */ +int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata); + +/* suspend/resume callbacks */ +int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state); +int bnx2x_resume(struct pci_dev *pdev); + +/* Release IRQ vectors */ +void bnx2x_free_irq(struct bnx2x *bp); + +void bnx2x_free_fp_mem(struct bnx2x *bp); +int bnx2x_alloc_fp_mem(struct bnx2x *bp); +void bnx2x_init_rx_rings(struct bnx2x *bp); +void bnx2x_free_skbs(struct bnx2x *bp); +void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw); +void bnx2x_netif_start(struct bnx2x *bp); + +/** + * bnx2x_enable_msix - set msix configuration. + * + * @bp: driver handle + * + * fills msix_table, requests vectors, updates num_queues + * according to number of available vectors. + */ +int bnx2x_enable_msix(struct bnx2x *bp); + +/** + * bnx2x_enable_msi - request msi mode from OS, updated internals accordingly + * + * @bp: driver handle + */ +int bnx2x_enable_msi(struct bnx2x *bp); + +/** + * bnx2x_poll - NAPI callback + * + * @napi: napi structure + * @budget: + * + */ +int bnx2x_poll(struct napi_struct *napi, int budget); + +/** + * bnx2x_alloc_mem_bp - allocate memories outsize main driver structure + * + * @bp: driver handle + */ +int __devinit bnx2x_alloc_mem_bp(struct bnx2x *bp); + +/** + * bnx2x_free_mem_bp - release memories outsize main driver structure + * + * @bp: driver handle + */ +void bnx2x_free_mem_bp(struct bnx2x *bp); + +/** + * bnx2x_change_mtu - change mtu netdev callback + * + * @dev: net device + * @new_mtu: requested mtu + * + */ +int bnx2x_change_mtu(struct net_device *dev, int new_mtu); + +#if defined(BCM_CNIC) && (defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE)) +/** + * bnx2x_fcoe_get_wwn - return the requested WWN value for this port + * + * @dev: net_device + * @wwn: output buffer + * @type: WWN type: NETDEV_FCOE_WWNN (node) or NETDEV_FCOE_WWPN (port) + * + */ +int bnx2x_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type); +#endif +u32 bnx2x_fix_features(struct net_device *dev, u32 features); +int bnx2x_set_features(struct net_device *dev, u32 features); + +/** + * bnx2x_tx_timeout - tx timeout netdev callback + * + * @dev: net device + */ +void bnx2x_tx_timeout(struct net_device *dev); + +/*********************** Inlines **********************************/ +/*********************** Fast path ********************************/ +static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp) +{ + barrier(); /* status block is written to by the chip */ + fp->fp_hc_idx = fp->sb_running_index[SM_RX_ID]; +} + +static inline void bnx2x_update_rx_prod_gen(struct bnx2x *bp, + struct bnx2x_fastpath *fp, u16 bd_prod, + u16 rx_comp_prod, u16 rx_sge_prod, u32 start) +{ + struct ustorm_eth_rx_producers rx_prods = {0}; + u32 i; + + /* Update producers */ + rx_prods.bd_prod = bd_prod; + rx_prods.cqe_prod = rx_comp_prod; + rx_prods.sge_prod = rx_sge_prod; + + /* + * Make sure that the BD and SGE data is updated before updating the + * producers since FW might read the BD/SGE right after the producer + * is updated. + * This is only applicable for weak-ordered memory model archs such + * as IA-64. The following barrier is also mandatory since FW will + * assumes BDs must have buffers. + */ + wmb(); + + for (i = 0; i < sizeof(rx_prods)/4; i++) + REG_WR(bp, start + i*4, ((u32 *)&rx_prods)[i]); + + mmiowb(); /* keep prod updates ordered */ + + DP(NETIF_MSG_RX_STATUS, + "queue[%d]: wrote bd_prod %u cqe_prod %u sge_prod %u\n", + fp->index, bd_prod, rx_comp_prod, rx_sge_prod); +} + +static inline void bnx2x_igu_ack_sb_gen(struct bnx2x *bp, u8 igu_sb_id, + u8 segment, u16 index, u8 op, + u8 update, u32 igu_addr) +{ + struct igu_regular cmd_data = {0}; + + cmd_data.sb_id_and_flags = + ((index << IGU_REGULAR_SB_INDEX_SHIFT) | + (segment << IGU_REGULAR_SEGMENT_ACCESS_SHIFT) | + (update << IGU_REGULAR_BUPDATE_SHIFT) | + (op << IGU_REGULAR_ENABLE_INT_SHIFT)); + + DP(NETIF_MSG_HW, "write 0x%08x to IGU addr 0x%x\n", + cmd_data.sb_id_and_flags, igu_addr); + REG_WR(bp, igu_addr, cmd_data.sb_id_and_flags); + + /* Make sure that ACK is written */ + mmiowb(); + barrier(); +} + +static inline void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, + u8 idu_sb_id, bool is_Pf) +{ + u32 data, ctl, cnt = 100; + u32 igu_addr_data = IGU_REG_COMMAND_REG_32LSB_DATA; + u32 igu_addr_ctl = IGU_REG_COMMAND_REG_CTRL; + u32 igu_addr_ack = IGU_REG_CSTORM_TYPE_0_SB_CLEANUP + (idu_sb_id/32)*4; + u32 sb_bit = 1 << (idu_sb_id%32); + u32 func_encode = func | + ((is_Pf == true ? 1 : 0) << IGU_FID_ENCODE_IS_PF_SHIFT); + u32 addr_encode = IGU_CMD_E2_PROD_UPD_BASE + idu_sb_id; + + /* Not supported in BC mode */ + if (CHIP_INT_MODE_IS_BC(bp)) + return; + + data = (IGU_USE_REGISTER_cstorm_type_0_sb_cleanup + << IGU_REGULAR_CLEANUP_TYPE_SHIFT) | + IGU_REGULAR_CLEANUP_SET | + IGU_REGULAR_BCLEANUP; + + ctl = addr_encode << IGU_CTRL_REG_ADDRESS_SHIFT | + func_encode << IGU_CTRL_REG_FID_SHIFT | + IGU_CTRL_CMD_TYPE_WR << IGU_CTRL_REG_TYPE_SHIFT; + + DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n", + data, igu_addr_data); + REG_WR(bp, igu_addr_data, data); + mmiowb(); + barrier(); + DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n", + ctl, igu_addr_ctl); + REG_WR(bp, igu_addr_ctl, ctl); + mmiowb(); + barrier(); + + /* wait for clean up to finish */ + while (!(REG_RD(bp, igu_addr_ack) & sb_bit) && --cnt) + msleep(20); + + + if (!(REG_RD(bp, igu_addr_ack) & sb_bit)) { + DP(NETIF_MSG_HW, "Unable to finish IGU cleanup: " + "idu_sb_id %d offset %d bit %d (cnt %d)\n", + idu_sb_id, idu_sb_id/32, idu_sb_id%32, cnt); + } +} + +static inline void bnx2x_hc_ack_sb(struct bnx2x *bp, u8 sb_id, + u8 storm, u16 index, u8 op, u8 update) +{ + u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 + + COMMAND_REG_INT_ACK); + struct igu_ack_register igu_ack; + + igu_ack.status_block_index = index; + igu_ack.sb_id_and_flags = + ((sb_id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) | + (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) | + (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) | + (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT)); + + DP(BNX2X_MSG_OFF, "write 0x%08x to HC addr 0x%x\n", + (*(u32 *)&igu_ack), hc_addr); + REG_WR(bp, hc_addr, (*(u32 *)&igu_ack)); + + /* Make sure that ACK is written */ + mmiowb(); + barrier(); +} + +static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 igu_sb_id, u8 storm, + u16 index, u8 op, u8 update) +{ + if (bp->common.int_block == INT_BLOCK_HC) + bnx2x_hc_ack_sb(bp, igu_sb_id, storm, index, op, update); + else { + u8 segment; + + if (CHIP_INT_MODE_IS_BC(bp)) + segment = storm; + else if (igu_sb_id != bp->igu_dsb_id) + segment = IGU_SEG_ACCESS_DEF; + else if (storm == ATTENTION_ID) + segment = IGU_SEG_ACCESS_ATTN; + else + segment = IGU_SEG_ACCESS_DEF; + bnx2x_igu_ack_sb(bp, igu_sb_id, segment, index, op, update); + } +} + +static inline u16 bnx2x_hc_ack_int(struct bnx2x *bp) +{ + u32 hc_addr = (HC_REG_COMMAND_REG + BP_PORT(bp)*32 + + COMMAND_REG_SIMD_MASK); + u32 result = REG_RD(bp, hc_addr); + + DP(BNX2X_MSG_OFF, "read 0x%08x from HC addr 0x%x\n", + result, hc_addr); + + barrier(); + return result; +} + +static inline u16 bnx2x_igu_ack_int(struct bnx2x *bp) +{ + u32 igu_addr = (BAR_IGU_INTMEM + IGU_REG_SISR_MDPC_WMASK_LSB_UPPER*8); + u32 result = REG_RD(bp, igu_addr); + + DP(NETIF_MSG_HW, "read 0x%08x from IGU addr 0x%x\n", + result, igu_addr); + + barrier(); + return result; +} + +static inline u16 bnx2x_ack_int(struct bnx2x *bp) +{ + barrier(); + if (bp->common.int_block == INT_BLOCK_HC) + return bnx2x_hc_ack_int(bp); + else + return bnx2x_igu_ack_int(bp); +} + +static inline int bnx2x_has_tx_work_unload(struct bnx2x_fp_txdata *txdata) +{ + /* Tell compiler that consumer and producer can change */ + barrier(); + return txdata->tx_pkt_prod != txdata->tx_pkt_cons; +} + +static inline u16 bnx2x_tx_avail(struct bnx2x *bp, + struct bnx2x_fp_txdata *txdata) +{ + s16 used; + u16 prod; + u16 cons; + + prod = txdata->tx_bd_prod; + cons = txdata->tx_bd_cons; + + /* NUM_TX_RINGS = number of "next-page" entries + It will be used as a threshold */ + used = SUB_S16(prod, cons) + (s16)NUM_TX_RINGS; + +#ifdef BNX2X_STOP_ON_ERROR + WARN_ON(used < 0); + WARN_ON(used > bp->tx_ring_size); + WARN_ON((bp->tx_ring_size - used) > MAX_TX_AVAIL); +#endif + + return (s16)(bp->tx_ring_size) - used; +} + +static inline int bnx2x_tx_queue_has_work(struct bnx2x_fp_txdata *txdata) +{ + u16 hw_cons; + + /* Tell compiler that status block fields can change */ + barrier(); + hw_cons = le16_to_cpu(*txdata->tx_cons_sb); + return hw_cons != txdata->tx_pkt_cons; +} + +static inline bool bnx2x_has_tx_work(struct bnx2x_fastpath *fp) +{ + u8 cos; + for_each_cos_in_tx_queue(fp, cos) + if (bnx2x_tx_queue_has_work(&fp->txdata[cos])) + return true; + return false; +} + +static inline int bnx2x_has_rx_work(struct bnx2x_fastpath *fp) +{ + u16 rx_cons_sb; + + /* Tell compiler that status block fields can change */ + barrier(); + rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb); + if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT) + rx_cons_sb++; + return (fp->rx_comp_cons != rx_cons_sb); +} + +/** + * bnx2x_tx_disable - disables tx from stack point of view + * + * @bp: driver handle + */ +static inline void bnx2x_tx_disable(struct bnx2x *bp) +{ + netif_tx_disable(bp->dev); + netif_carrier_off(bp->dev); +} + +static inline void bnx2x_free_rx_sge(struct bnx2x *bp, + struct bnx2x_fastpath *fp, u16 index) +{ + struct sw_rx_page *sw_buf = &fp->rx_page_ring[index]; + struct page *page = sw_buf->page; + struct eth_rx_sge *sge = &fp->rx_sge_ring[index]; + + /* Skip "next page" elements */ + if (!page) + return; + + dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(sw_buf, mapping), + SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE); + __free_pages(page, PAGES_PER_SGE_SHIFT); + + sw_buf->page = NULL; + sge->addr_hi = 0; + sge->addr_lo = 0; +} + +static inline void bnx2x_add_all_napi(struct bnx2x *bp) +{ + int i; + + /* Add NAPI objects */ + for_each_rx_queue(bp, i) + netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), + bnx2x_poll, BNX2X_NAPI_WEIGHT); +} + +static inline void bnx2x_del_all_napi(struct bnx2x *bp) +{ + int i; + + for_each_rx_queue(bp, i) + netif_napi_del(&bnx2x_fp(bp, i, napi)); +} + +static inline void bnx2x_disable_msi(struct bnx2x *bp) +{ + if (bp->flags & USING_MSIX_FLAG) { + pci_disable_msix(bp->pdev); + bp->flags &= ~USING_MSIX_FLAG; + } else if (bp->flags & USING_MSI_FLAG) { + pci_disable_msi(bp->pdev); + bp->flags &= ~USING_MSI_FLAG; + } +} + +static inline int bnx2x_calc_num_queues(struct bnx2x *bp) +{ + return num_queues ? + min_t(int, num_queues, BNX2X_MAX_QUEUES(bp)) : + min_t(int, num_online_cpus(), BNX2X_MAX_QUEUES(bp)); +} + +static inline void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp) +{ + int i, j; + + for (i = 1; i <= NUM_RX_SGE_PAGES; i++) { + int idx = RX_SGE_CNT * i - 1; + + for (j = 0; j < 2; j++) { + BIT_VEC64_CLEAR_BIT(fp->sge_mask, idx); + idx--; + } + } +} + +static inline void bnx2x_init_sge_ring_bit_mask(struct bnx2x_fastpath *fp) +{ + /* Set the mask to all 1-s: it's faster to compare to 0 than to 0xf-s */ + memset(fp->sge_mask, 0xff, + (NUM_RX_SGE >> BIT_VEC64_ELEM_SHIFT)*sizeof(u64)); + + /* Clear the two last indices in the page to 1: + these are the indices that correspond to the "next" element, + hence will never be indicated and should be removed from + the calculations. */ + bnx2x_clear_sge_mask_next_elems(fp); +} + +static inline int bnx2x_alloc_rx_sge(struct bnx2x *bp, + struct bnx2x_fastpath *fp, u16 index) +{ + struct page *page = alloc_pages(GFP_ATOMIC, PAGES_PER_SGE_SHIFT); + struct sw_rx_page *sw_buf = &fp->rx_page_ring[index]; + struct eth_rx_sge *sge = &fp->rx_sge_ring[index]; + dma_addr_t mapping; + + if (unlikely(page == NULL)) + return -ENOMEM; + + mapping = dma_map_page(&bp->pdev->dev, page, 0, + SGE_PAGE_SIZE*PAGES_PER_SGE, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { + __free_pages(page, PAGES_PER_SGE_SHIFT); + return -ENOMEM; + } + + sw_buf->page = page; + dma_unmap_addr_set(sw_buf, mapping, mapping); + + sge->addr_hi = cpu_to_le32(U64_HI(mapping)); + sge->addr_lo = cpu_to_le32(U64_LO(mapping)); + + return 0; +} + +static inline int bnx2x_alloc_rx_skb(struct bnx2x *bp, + struct bnx2x_fastpath *fp, u16 index) +{ + struct sk_buff *skb; + struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index]; + struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index]; + dma_addr_t mapping; + + skb = netdev_alloc_skb(bp->dev, fp->rx_buf_size); + if (unlikely(skb == NULL)) + return -ENOMEM; + + mapping = dma_map_single(&bp->pdev->dev, skb->data, fp->rx_buf_size, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { + dev_kfree_skb_any(skb); + return -ENOMEM; + } + + rx_buf->skb = skb; + dma_unmap_addr_set(rx_buf, mapping, mapping); + + rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + + return 0; +} + +/* note that we are not allocating a new skb, + * we are just moving one from cons to prod + * we are not creating a new mapping, + * so there is no need to check for dma_mapping_error(). + */ +static inline void bnx2x_reuse_rx_skb(struct bnx2x_fastpath *fp, + u16 cons, u16 prod) +{ + struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons]; + struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod]; + struct eth_rx_bd *cons_bd = &fp->rx_desc_ring[cons]; + struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod]; + + dma_unmap_addr_set(prod_rx_buf, mapping, + dma_unmap_addr(cons_rx_buf, mapping)); + prod_rx_buf->skb = cons_rx_buf->skb; + *prod_bd = *cons_bd; +} + +/************************* Init ******************************************/ + +/** + * bnx2x_func_start - init function + * + * @bp: driver handle + * + * Must be called before sending CLIENT_SETUP for the first client. + */ +static inline int bnx2x_func_start(struct bnx2x *bp) +{ + struct bnx2x_func_state_params func_params = {0}; + struct bnx2x_func_start_params *start_params = + &func_params.params.start; + + /* Prepare parameters for function state transitions */ + __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags); + + func_params.f_obj = &bp->func_obj; + func_params.cmd = BNX2X_F_CMD_START; + + /* Function parameters */ + start_params->mf_mode = bp->mf_mode; + start_params->sd_vlan_tag = bp->mf_ov; + if (CHIP_IS_E1x(bp)) + start_params->network_cos_mode = OVERRIDE_COS; + else + start_params->network_cos_mode = STATIC_COS; + + return bnx2x_func_state_change(bp, &func_params); +} + + +/** + * bnx2x_set_fw_mac_addr - fill in a MAC address in FW format + * + * @fw_hi: pointer to upper part + * @fw_mid: pointer to middle part + * @fw_lo: pointer to lower part + * @mac: pointer to MAC address + */ +static inline void bnx2x_set_fw_mac_addr(u16 *fw_hi, u16 *fw_mid, u16 *fw_lo, + u8 *mac) +{ + ((u8 *)fw_hi)[0] = mac[1]; + ((u8 *)fw_hi)[1] = mac[0]; + ((u8 *)fw_mid)[0] = mac[3]; + ((u8 *)fw_mid)[1] = mac[2]; + ((u8 *)fw_lo)[0] = mac[5]; + ((u8 *)fw_lo)[1] = mac[4]; +} + +static inline void bnx2x_free_rx_sge_range(struct bnx2x *bp, + struct bnx2x_fastpath *fp, int last) +{ + int i; + + if (fp->disable_tpa) + return; + + for (i = 0; i < last; i++) + bnx2x_free_rx_sge(bp, fp, i); +} + +static inline void bnx2x_free_tpa_pool(struct bnx2x *bp, + struct bnx2x_fastpath *fp, int last) +{ + int i; + + for (i = 0; i < last; i++) { + struct bnx2x_agg_info *tpa_info = &fp->tpa_info[i]; + struct sw_rx_bd *first_buf = &tpa_info->first_buf; + struct sk_buff *skb = first_buf->skb; + + if (skb == NULL) { + DP(NETIF_MSG_IFDOWN, "tpa bin %d empty on free\n", i); + continue; + } + if (tpa_info->tpa_state == BNX2X_TPA_START) + dma_unmap_single(&bp->pdev->dev, + dma_unmap_addr(first_buf, mapping), + fp->rx_buf_size, DMA_FROM_DEVICE); + dev_kfree_skb(skb); + first_buf->skb = NULL; + } +} + +static inline void bnx2x_init_tx_ring_one(struct bnx2x_fp_txdata *txdata) +{ + int i; + + for (i = 1; i <= NUM_TX_RINGS; i++) { + struct eth_tx_next_bd *tx_next_bd = + &txdata->tx_desc_ring[TX_DESC_CNT * i - 1].next_bd; + + tx_next_bd->addr_hi = + cpu_to_le32(U64_HI(txdata->tx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + tx_next_bd->addr_lo = + cpu_to_le32(U64_LO(txdata->tx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_TX_RINGS))); + } + + SET_FLAG(txdata->tx_db.data.header.header, DOORBELL_HDR_DB_TYPE, 1); + txdata->tx_db.data.zero_fill1 = 0; + txdata->tx_db.data.prod = 0; + + txdata->tx_pkt_prod = 0; + txdata->tx_pkt_cons = 0; + txdata->tx_bd_prod = 0; + txdata->tx_bd_cons = 0; + txdata->tx_pkt = 0; +} + +static inline void bnx2x_init_tx_rings(struct bnx2x *bp) +{ + int i; + u8 cos; + + for_each_tx_queue(bp, i) + for_each_cos_in_tx_queue(&bp->fp[i], cos) + bnx2x_init_tx_ring_one(&bp->fp[i].txdata[cos]); +} + +static inline void bnx2x_set_next_page_rx_bd(struct bnx2x_fastpath *fp) +{ + int i; + + for (i = 1; i <= NUM_RX_RINGS; i++) { + struct eth_rx_bd *rx_bd; + + rx_bd = &fp->rx_desc_ring[RX_DESC_CNT * i - 2]; + rx_bd->addr_hi = + cpu_to_le32(U64_HI(fp->rx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); + rx_bd->addr_lo = + cpu_to_le32(U64_LO(fp->rx_desc_mapping + + BCM_PAGE_SIZE*(i % NUM_RX_RINGS))); + } +} + +static inline void bnx2x_set_next_page_sgl(struct bnx2x_fastpath *fp) +{ + int i; + + for (i = 1; i <= NUM_RX_SGE_PAGES; i++) { + struct eth_rx_sge *sge; + + sge = &fp->rx_sge_ring[RX_SGE_CNT * i - 2]; + sge->addr_hi = + cpu_to_le32(U64_HI(fp->rx_sge_mapping + + BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES))); + + sge->addr_lo = + cpu_to_le32(U64_LO(fp->rx_sge_mapping + + BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES))); + } +} + +static inline void bnx2x_set_next_page_rx_cq(struct bnx2x_fastpath *fp) +{ + int i; + for (i = 1; i <= NUM_RCQ_RINGS; i++) { + struct eth_rx_cqe_next_page *nextpg; + + nextpg = (struct eth_rx_cqe_next_page *) + &fp->rx_comp_ring[RCQ_DESC_CNT * i - 1]; + nextpg->addr_hi = + cpu_to_le32(U64_HI(fp->rx_comp_mapping + + BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); + nextpg->addr_lo = + cpu_to_le32(U64_LO(fp->rx_comp_mapping + + BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); + } +} + +/* Returns the number of actually allocated BDs */ +static inline int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp, + int rx_ring_size) +{ + struct bnx2x *bp = fp->bp; + u16 ring_prod, cqe_ring_prod; + int i; + + fp->rx_comp_cons = 0; + cqe_ring_prod = ring_prod = 0; + + /* This routine is called only during fo init so + * fp->eth_q_stats.rx_skb_alloc_failed = 0 + */ + for (i = 0; i < rx_ring_size; i++) { + if (bnx2x_alloc_rx_skb(bp, fp, ring_prod) < 0) { + fp->eth_q_stats.rx_skb_alloc_failed++; + continue; + } + ring_prod = NEXT_RX_IDX(ring_prod); + cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod); + WARN_ON(ring_prod <= (i - fp->eth_q_stats.rx_skb_alloc_failed)); + } + + if (fp->eth_q_stats.rx_skb_alloc_failed) + BNX2X_ERR("was only able to allocate " + "%d rx skbs on queue[%d]\n", + (i - fp->eth_q_stats.rx_skb_alloc_failed), fp->index); + + fp->rx_bd_prod = ring_prod; + /* Limit the CQE producer by the CQE ring size */ + fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT, + cqe_ring_prod); + fp->rx_pkt = fp->rx_calls = 0; + + return i - fp->eth_q_stats.rx_skb_alloc_failed; +} + +/* Statistics ID are global per chip/path, while Client IDs for E1x are per + * port. + */ +static inline u8 bnx2x_stats_id(struct bnx2x_fastpath *fp) +{ + if (!CHIP_IS_E1x(fp->bp)) + return fp->cl_id; + else + return fp->cl_id + BP_PORT(fp->bp) * FP_SB_MAX_E1x; +} + +static inline void bnx2x_init_vlan_mac_fp_objs(struct bnx2x_fastpath *fp, + bnx2x_obj_type obj_type) +{ + struct bnx2x *bp = fp->bp; + + /* Configure classification DBs */ + bnx2x_init_mac_obj(bp, &fp->mac_obj, fp->cl_id, fp->cid, + BP_FUNC(bp), bnx2x_sp(bp, mac_rdata), + bnx2x_sp_mapping(bp, mac_rdata), + BNX2X_FILTER_MAC_PENDING, + &bp->sp_state, obj_type, + &bp->macs_pool); +} + +/** + * bnx2x_get_path_func_num - get number of active functions + * + * @bp: driver handle + * + * Calculates the number of active (not hidden) functions on the + * current path. + */ +static inline u8 bnx2x_get_path_func_num(struct bnx2x *bp) +{ + u8 func_num = 0, i; + + /* 57710 has only one function per-port */ + if (CHIP_IS_E1(bp)) + return 1; + + /* Calculate a number of functions enabled on the current + * PATH/PORT. + */ + if (CHIP_REV_IS_SLOW(bp)) { + if (IS_MF(bp)) + func_num = 4; + else + func_num = 2; + } else { + for (i = 0; i < E1H_FUNC_MAX / 2; i++) { + u32 func_config = + MF_CFG_RD(bp, + func_mf_config[BP_PORT(bp) + 2 * i]. + config); + func_num += + ((func_config & FUNC_MF_CFG_FUNC_HIDE) ? 0 : 1); + } + } + + WARN_ON(!func_num); + + return func_num; +} + +static inline void bnx2x_init_bp_objs(struct bnx2x *bp) +{ + /* RX_MODE controlling object */ + bnx2x_init_rx_mode_obj(bp, &bp->rx_mode_obj); + + /* multicast configuration controlling object */ + bnx2x_init_mcast_obj(bp, &bp->mcast_obj, bp->fp->cl_id, bp->fp->cid, + BP_FUNC(bp), BP_FUNC(bp), + bnx2x_sp(bp, mcast_rdata), + bnx2x_sp_mapping(bp, mcast_rdata), + BNX2X_FILTER_MCAST_PENDING, &bp->sp_state, + BNX2X_OBJ_TYPE_RX); + + /* Setup CAM credit pools */ + bnx2x_init_mac_credit_pool(bp, &bp->macs_pool, BP_FUNC(bp), + bnx2x_get_path_func_num(bp)); + + /* RSS configuration object */ + bnx2x_init_rss_config_obj(bp, &bp->rss_conf_obj, bp->fp->cl_id, + bp->fp->cid, BP_FUNC(bp), BP_FUNC(bp), + bnx2x_sp(bp, rss_rdata), + bnx2x_sp_mapping(bp, rss_rdata), + BNX2X_FILTER_RSS_CONF_PENDING, &bp->sp_state, + BNX2X_OBJ_TYPE_RX); +} + +static inline u8 bnx2x_fp_qzone_id(struct bnx2x_fastpath *fp) +{ + if (CHIP_IS_E1x(fp->bp)) + return fp->cl_id + BP_PORT(fp->bp) * ETH_MAX_RX_CLIENTS_E1H; + else + return fp->cl_id; +} + +static inline u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp) +{ + struct bnx2x *bp = fp->bp; + + if (!CHIP_IS_E1x(bp)) + return USTORM_RX_PRODS_E2_OFFSET(fp->cl_qzone_id); + else + return USTORM_RX_PRODS_E1X_OFFSET(BP_PORT(bp), fp->cl_id); +} + +static inline void bnx2x_init_txdata(struct bnx2x *bp, + struct bnx2x_fp_txdata *txdata, u32 cid, int txq_index, + __le16 *tx_cons_sb) +{ + txdata->cid = cid; + txdata->txq_index = txq_index; + txdata->tx_cons_sb = tx_cons_sb; + + DP(BNX2X_MSG_SP, "created tx data cid %d, txq %d", + txdata->cid, txdata->txq_index); +} + +#ifdef BCM_CNIC +static inline u8 bnx2x_cnic_eth_cl_id(struct bnx2x *bp, u8 cl_idx) +{ + return bp->cnic_base_cl_id + cl_idx + + (bp->pf_num >> 1) * NON_ETH_CONTEXT_USE; +} + +static inline u8 bnx2x_cnic_fw_sb_id(struct bnx2x *bp) +{ + + /* the 'first' id is allocated for the cnic */ + return bp->base_fw_ndsb; +} + +static inline u8 bnx2x_cnic_igu_sb_id(struct bnx2x *bp) +{ + return bp->igu_base_sb; +} + + +static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp) +{ + struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp); + unsigned long q_type = 0; + + bnx2x_fcoe(bp, cl_id) = bnx2x_cnic_eth_cl_id(bp, + BNX2X_FCOE_ETH_CL_ID_IDX); + /** Current BNX2X_FCOE_ETH_CID deffinition implies not more than + * 16 ETH clients per function when CNIC is enabled! + * + * Fix it ASAP!!! + */ + bnx2x_fcoe(bp, cid) = BNX2X_FCOE_ETH_CID; + bnx2x_fcoe(bp, fw_sb_id) = DEF_SB_ID; + bnx2x_fcoe(bp, igu_sb_id) = bp->igu_dsb_id; + bnx2x_fcoe(bp, rx_cons_sb) = BNX2X_FCOE_L2_RX_INDEX; + + bnx2x_init_txdata(bp, &bnx2x_fcoe(bp, txdata[0]), + fp->cid, FCOE_TXQ_IDX(bp), BNX2X_FCOE_L2_TX_INDEX); + + DP(BNX2X_MSG_SP, "created fcoe tx data (fp index %d)", fp->index); + + /* qZone id equals to FW (per path) client id */ + bnx2x_fcoe(bp, cl_qzone_id) = bnx2x_fp_qzone_id(fp); + /* init shortcut */ + bnx2x_fcoe(bp, ustorm_rx_prods_offset) = + bnx2x_rx_ustorm_prods_offset(fp); + + /* Configure Queue State object */ + __set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type); + __set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type); + + /* No multi-CoS for FCoE L2 client */ + BUG_ON(fp->max_cos != 1); + + bnx2x_init_queue_obj(bp, &fp->q_obj, fp->cl_id, &fp->cid, 1, + BP_FUNC(bp), bnx2x_sp(bp, q_rdata), + bnx2x_sp_mapping(bp, q_rdata), q_type); + + DP(NETIF_MSG_IFUP, "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d fw_sb %d " + "igu_sb %d\n", + fp->index, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id, + fp->igu_sb_id); +} +#endif + +static inline int bnx2x_clean_tx_queue(struct bnx2x *bp, + struct bnx2x_fp_txdata *txdata) +{ + int cnt = 1000; + + while (bnx2x_has_tx_work_unload(txdata)) { + if (!cnt) { + BNX2X_ERR("timeout waiting for queue[%d]: " + "txdata->tx_pkt_prod(%d) != txdata->tx_pkt_cons(%d)\n", + txdata->txq_index, txdata->tx_pkt_prod, + txdata->tx_pkt_cons); +#ifdef BNX2X_STOP_ON_ERROR + bnx2x_panic(); + return -EBUSY; +#else + break; +#endif + } + cnt--; + usleep_range(1000, 1000); + } + + return 0; +} + +int bnx2x_get_link_cfg_idx(struct bnx2x *bp); + +static inline void __storm_memset_struct(struct bnx2x *bp, + u32 addr, size_t size, u32 *data) +{ + int i; + for (i = 0; i < size/4; i++) + REG_WR(bp, addr + (i * 4), data[i]); +} + +static inline void storm_memset_func_cfg(struct bnx2x *bp, + struct tstorm_eth_function_common_config *tcfg, + u16 abs_fid) +{ + size_t size = sizeof(struct tstorm_eth_function_common_config); + + u32 addr = BAR_TSTRORM_INTMEM + + TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(abs_fid); + + __storm_memset_struct(bp, addr, size, (u32 *)tcfg); +} + +static inline void storm_memset_cmng(struct bnx2x *bp, + struct cmng_struct_per_port *cmng, + u8 port) +{ + size_t size = sizeof(struct cmng_struct_per_port); + + u32 addr = BAR_XSTRORM_INTMEM + + XSTORM_CMNG_PER_PORT_VARS_OFFSET(port); + + __storm_memset_struct(bp, addr, size, (u32 *)cmng); +} + +/** + * bnx2x_wait_sp_comp - wait for the outstanding SP commands. + * + * @bp: driver handle + * @mask: bits that need to be cleared + */ +static inline bool bnx2x_wait_sp_comp(struct bnx2x *bp, unsigned long mask) +{ + int tout = 5000; /* Wait for 5 secs tops */ + + while (tout--) { + smp_mb(); + netif_addr_lock_bh(bp->dev); + if (!(bp->sp_state & mask)) { + netif_addr_unlock_bh(bp->dev); + return true; + } + netif_addr_unlock_bh(bp->dev); + + usleep_range(1000, 1000); + } + + smp_mb(); + + netif_addr_lock_bh(bp->dev); + if (bp->sp_state & mask) { + BNX2X_ERR("Filtering completion timed out. sp_state 0x%lx, " + "mask 0x%lx\n", bp->sp_state, mask); + netif_addr_unlock_bh(bp->dev); + return false; + } + netif_addr_unlock_bh(bp->dev); + + return true; +} + +/** + * bnx2x_set_ctx_validation - set CDU context validation values + * + * @bp: driver handle + * @cxt: context of the connection on the host memory + * @cid: SW CID of the connection to be configured + */ +void bnx2x_set_ctx_validation(struct bnx2x *bp, struct eth_context *cxt, + u32 cid); + +void bnx2x_update_coalesce_sb_index(struct bnx2x *bp, u8 fw_sb_id, + u8 sb_index, u8 disable, u16 usec); +void bnx2x_acquire_phy_lock(struct bnx2x *bp); +void bnx2x_release_phy_lock(struct bnx2x *bp); + +/** + * bnx2x_extract_max_cfg - extract MAX BW part from MF configuration. + * + * @bp: driver handle + * @mf_cfg: MF configuration + * + */ +static inline u16 bnx2x_extract_max_cfg(struct bnx2x *bp, u32 mf_cfg) +{ + u16 max_cfg = (mf_cfg & FUNC_MF_CFG_MAX_BW_MASK) >> + FUNC_MF_CFG_MAX_BW_SHIFT; + if (!max_cfg) { + BNX2X_ERR("Illegal configuration detected for Max BW - " + "using 100 instead\n"); + max_cfg = 100; + } + return max_cfg; +} + +#endif /* BNX2X_CMN_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c new file mode 100644 index 000000000000..a4ea35f6a456 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c @@ -0,0 +1,2507 @@ +/* bnx2x_dcb.c: Broadcom Everest network driver. + * + * Copyright 2009-2011 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + * + * Maintained by: Eilon Greenstein + * Written by: Dmitry Kravkov + * + */ +#include +#include +#include +#include +#include + +#include "bnx2x.h" +#include "bnx2x_cmn.h" +#include "bnx2x_dcb.h" + +/* forward declarations of dcbx related functions */ +static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp); +static void bnx2x_pfc_set_pfc(struct bnx2x *bp); +static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp); +static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp); +static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp, + u32 *set_configuration_ets_pg, + u32 *pri_pg_tbl); +static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp, + u32 *pg_pri_orginal_spread, + struct pg_help_data *help_data); +static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp, + struct pg_help_data *help_data, + struct dcbx_ets_feature *ets, + u32 *pg_pri_orginal_spread); +static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp, + struct cos_help_data *cos_data, + u32 *pg_pri_orginal_spread, + struct dcbx_ets_feature *ets); +static void bnx2x_dcbx_fw_struct(struct bnx2x *bp, + struct bnx2x_func_tx_start_params*); + +/* helpers: read/write len bytes from addr into buff by REG_RD/REG_WR */ +static void bnx2x_read_data(struct bnx2x *bp, u32 *buff, + u32 addr, u32 len) +{ + int i; + for (i = 0; i < len; i += 4, buff++) + *buff = REG_RD(bp, addr + i); +} + +static void bnx2x_write_data(struct bnx2x *bp, u32 *buff, + u32 addr, u32 len) +{ + int i; + for (i = 0; i < len; i += 4, buff++) + REG_WR(bp, addr + i, *buff); +} + +static void bnx2x_pfc_set(struct bnx2x *bp) +{ + struct bnx2x_nig_brb_pfc_port_params pfc_params = {0}; + u32 pri_bit, val = 0; + int i; + + pfc_params.num_of_rx_cos_priority_mask = + bp->dcbx_port_params.ets.num_of_cos; + + /* Tx COS configuration */ + for (i = 0; i < bp->dcbx_port_params.ets.num_of_cos; i++) + /* + * We configure only the pauseable bits (non pauseable aren't + * configured at all) it's done to avoid false pauses from + * network + */ + pfc_params.rx_cos_priority_mask[i] = + bp->dcbx_port_params.ets.cos_params[i].pri_bitmask + & DCBX_PFC_PRI_PAUSE_MASK(bp); + + /* + * Rx COS configuration + * Changing PFC RX configuration . + * In RX COS0 will always be configured to lossy and COS1 to lossless + */ + for (i = 0 ; i < MAX_PFC_PRIORITIES ; i++) { + pri_bit = 1 << i; + + if (pri_bit & DCBX_PFC_PRI_PAUSE_MASK(bp)) + val |= 1 << (i * 4); + } + + pfc_params.pkt_priority_to_cos = val; + + /* RX COS0 */ + pfc_params.llfc_low_priority_classes = 0; + /* RX COS1 */ + pfc_params.llfc_high_priority_classes = DCBX_PFC_PRI_PAUSE_MASK(bp); + + /* BRB configuration */ + pfc_params.cos0_pauseable = false; + pfc_params.cos1_pauseable = true; + + bnx2x_acquire_phy_lock(bp); + bp->link_params.feature_config_flags |= FEATURE_CONFIG_PFC_ENABLED; + bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &pfc_params); + bnx2x_release_phy_lock(bp); +} + +static void bnx2x_pfc_clear(struct bnx2x *bp) +{ + struct bnx2x_nig_brb_pfc_port_params nig_params = {0}; + nig_params.pause_enable = 1; +#ifdef BNX2X_SAFC + if (bp->flags & SAFC_TX_FLAG) { + u32 high = 0, low = 0; + int i; + + for (i = 0; i < BNX2X_MAX_PRIORITY; i++) { + if (bp->pri_map[i] == 1) + high |= (1 << i); + if (bp->pri_map[i] == 0) + low |= (1 << i); + } + + nig_params.llfc_low_priority_classes = high; + nig_params.llfc_low_priority_classes = low; + + nig_params.pause_enable = 0; + nig_params.llfc_enable = 1; + nig_params.llfc_out_en = 1; + } +#endif /* BNX2X_SAFC */ + bnx2x_acquire_phy_lock(bp); + bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_PFC_ENABLED; + bnx2x_update_pfc(&bp->link_params, &bp->link_vars, &nig_params); + bnx2x_release_phy_lock(bp); +} + +static void bnx2x_dump_dcbx_drv_param(struct bnx2x *bp, + struct dcbx_features *features, + u32 error) +{ + u8 i = 0; + DP(NETIF_MSG_LINK, "local_mib.error %x\n", error); + + /* PG */ + DP(NETIF_MSG_LINK, + "local_mib.features.ets.enabled %x\n", features->ets.enabled); + for (i = 0; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++) + DP(NETIF_MSG_LINK, + "local_mib.features.ets.pg_bw_tbl[%d] %d\n", i, + DCBX_PG_BW_GET(features->ets.pg_bw_tbl, i)); + for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) + DP(NETIF_MSG_LINK, + "local_mib.features.ets.pri_pg_tbl[%d] %d\n", i, + DCBX_PRI_PG_GET(features->ets.pri_pg_tbl, i)); + + /* pfc */ + DP(NETIF_MSG_LINK, "dcbx_features.pfc.pri_en_bitmap %x\n", + features->pfc.pri_en_bitmap); + DP(NETIF_MSG_LINK, "dcbx_features.pfc.pfc_caps %x\n", + features->pfc.pfc_caps); + DP(NETIF_MSG_LINK, "dcbx_features.pfc.enabled %x\n", + features->pfc.enabled); + + DP(NETIF_MSG_LINK, "dcbx_features.app.default_pri %x\n", + features->app.default_pri); + DP(NETIF_MSG_LINK, "dcbx_features.app.tc_supported %x\n", + features->app.tc_supported); + DP(NETIF_MSG_LINK, "dcbx_features.app.enabled %x\n", + features->app.enabled); + for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) { + DP(NETIF_MSG_LINK, + "dcbx_features.app.app_pri_tbl[%x].app_id %x\n", + i, features->app.app_pri_tbl[i].app_id); + DP(NETIF_MSG_LINK, + "dcbx_features.app.app_pri_tbl[%x].pri_bitmap %x\n", + i, features->app.app_pri_tbl[i].pri_bitmap); + DP(NETIF_MSG_LINK, + "dcbx_features.app.app_pri_tbl[%x].appBitfield %x\n", + i, features->app.app_pri_tbl[i].appBitfield); + } +} + +static void bnx2x_dcbx_get_ap_priority(struct bnx2x *bp, + u8 pri_bitmap, + u8 llfc_traf_type) +{ + u32 pri = MAX_PFC_PRIORITIES; + u32 index = MAX_PFC_PRIORITIES - 1; + u32 pri_mask; + u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; + + /* Choose the highest priority */ + while ((MAX_PFC_PRIORITIES == pri) && (0 != index)) { + pri_mask = 1 << index; + if (GET_FLAGS(pri_bitmap, pri_mask)) + pri = index ; + index--; + } + + if (pri < MAX_PFC_PRIORITIES) + ttp[llfc_traf_type] = max_t(u32, ttp[llfc_traf_type], pri); +} + +static void bnx2x_dcbx_get_ap_feature(struct bnx2x *bp, + struct dcbx_app_priority_feature *app, + u32 error) { + u8 index; + u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; + + if (GET_FLAGS(error, DCBX_LOCAL_APP_ERROR)) + DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_ERROR\n"); + + if (GET_FLAGS(error, DCBX_LOCAL_APP_MISMATCH)) + DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_MISMATCH\n"); + + if (app->enabled && + !GET_FLAGS(error, DCBX_LOCAL_APP_ERROR | DCBX_LOCAL_APP_MISMATCH)) { + + bp->dcbx_port_params.app.enabled = true; + + for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++) + ttp[index] = 0; + + if (app->default_pri < MAX_PFC_PRIORITIES) + ttp[LLFC_TRAFFIC_TYPE_NW] = app->default_pri; + + for (index = 0 ; index < DCBX_MAX_APP_PROTOCOL; index++) { + struct dcbx_app_priority_entry *entry = + app->app_pri_tbl; + + if (GET_FLAGS(entry[index].appBitfield, + DCBX_APP_SF_ETH_TYPE) && + ETH_TYPE_FCOE == entry[index].app_id) + bnx2x_dcbx_get_ap_priority(bp, + entry[index].pri_bitmap, + LLFC_TRAFFIC_TYPE_FCOE); + + if (GET_FLAGS(entry[index].appBitfield, + DCBX_APP_SF_PORT) && + TCP_PORT_ISCSI == entry[index].app_id) + bnx2x_dcbx_get_ap_priority(bp, + entry[index].pri_bitmap, + LLFC_TRAFFIC_TYPE_ISCSI); + } + } else { + DP(NETIF_MSG_LINK, "DCBX_LOCAL_APP_DISABLED\n"); + bp->dcbx_port_params.app.enabled = false; + for (index = 0 ; index < LLFC_DRIVER_TRAFFIC_TYPE_MAX; index++) + ttp[index] = INVALID_TRAFFIC_TYPE_PRIORITY; + } +} + +static void bnx2x_dcbx_get_ets_feature(struct bnx2x *bp, + struct dcbx_ets_feature *ets, + u32 error) { + int i = 0; + u32 pg_pri_orginal_spread[DCBX_MAX_NUM_PG_BW_ENTRIES] = {0}; + struct pg_help_data pg_help_data; + struct bnx2x_dcbx_cos_params *cos_params = + bp->dcbx_port_params.ets.cos_params; + + memset(&pg_help_data, 0, sizeof(struct pg_help_data)); + + + if (GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR)) + DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_ERROR\n"); + + + /* Clean up old settings of ets on COS */ + for (i = 0; i < ARRAY_SIZE(bp->dcbx_port_params.ets.cos_params) ; i++) { + cos_params[i].pauseable = false; + cos_params[i].strict = BNX2X_DCBX_STRICT_INVALID; + cos_params[i].bw_tbl = DCBX_INVALID_COS_BW; + cos_params[i].pri_bitmask = 0; + } + + if (bp->dcbx_port_params.app.enabled && + !GET_FLAGS(error, DCBX_LOCAL_ETS_ERROR) && + ets->enabled) { + DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_ENABLE\n"); + bp->dcbx_port_params.ets.enabled = true; + + bnx2x_dcbx_get_ets_pri_pg_tbl(bp, + pg_pri_orginal_spread, + ets->pri_pg_tbl); + + bnx2x_dcbx_get_num_pg_traf_type(bp, + pg_pri_orginal_spread, + &pg_help_data); + + bnx2x_dcbx_fill_cos_params(bp, &pg_help_data, + ets, pg_pri_orginal_spread); + + } else { + DP(NETIF_MSG_LINK, "DCBX_LOCAL_ETS_DISABLED\n"); + bp->dcbx_port_params.ets.enabled = false; + ets->pri_pg_tbl[0] = 0; + + for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES ; i++) + DCBX_PG_BW_SET(ets->pg_bw_tbl, i, 1); + } +} + +static void bnx2x_dcbx_get_pfc_feature(struct bnx2x *bp, + struct dcbx_pfc_feature *pfc, u32 error) +{ + + if (GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR)) + DP(NETIF_MSG_LINK, "DCBX_LOCAL_PFC_ERROR\n"); + + if (bp->dcbx_port_params.app.enabled && + !GET_FLAGS(error, DCBX_LOCAL_PFC_ERROR | DCBX_LOCAL_PFC_MISMATCH) && + pfc->enabled) { + bp->dcbx_port_params.pfc.enabled = true; + bp->dcbx_port_params.pfc.priority_non_pauseable_mask = + ~(pfc->pri_en_bitmap); + } else { + DP(NETIF_MSG_LINK, "DCBX_LOCAL_PFC_DISABLED\n"); + bp->dcbx_port_params.pfc.enabled = false; + bp->dcbx_port_params.pfc.priority_non_pauseable_mask = 0; + } +} + +/* maps unmapped priorities to to the same COS as L2 */ +static void bnx2x_dcbx_map_nw(struct bnx2x *bp) +{ + int i; + u32 unmapped = (1 << MAX_PFC_PRIORITIES) - 1; /* all ones */ + u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; + u32 nw_prio = 1 << ttp[LLFC_TRAFFIC_TYPE_NW]; + struct bnx2x_dcbx_cos_params *cos_params = + bp->dcbx_port_params.ets.cos_params; + + /* get unmapped priorities by clearing mapped bits */ + for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) + unmapped &= ~(1 << ttp[i]); + + /* find cos for nw prio and extend it with unmapped */ + for (i = 0; i < ARRAY_SIZE(bp->dcbx_port_params.ets.cos_params); i++) { + if (cos_params[i].pri_bitmask & nw_prio) { + /* extend the bitmask with unmapped */ + DP(NETIF_MSG_LINK, + "cos %d extended with 0x%08x", i, unmapped); + cos_params[i].pri_bitmask |= unmapped; + break; + } + } +} + +static void bnx2x_get_dcbx_drv_param(struct bnx2x *bp, + struct dcbx_features *features, + u32 error) +{ + bnx2x_dcbx_get_ap_feature(bp, &features->app, error); + + bnx2x_dcbx_get_pfc_feature(bp, &features->pfc, error); + + bnx2x_dcbx_get_ets_feature(bp, &features->ets, error); + + bnx2x_dcbx_map_nw(bp); +} + +#define DCBX_LOCAL_MIB_MAX_TRY_READ (100) +static int bnx2x_dcbx_read_mib(struct bnx2x *bp, + u32 *base_mib_addr, + u32 offset, + int read_mib_type) +{ + int max_try_read = 0; + u32 mib_size, prefix_seq_num, suffix_seq_num; + struct lldp_remote_mib *remote_mib ; + struct lldp_local_mib *local_mib; + + + switch (read_mib_type) { + case DCBX_READ_LOCAL_MIB: + mib_size = sizeof(struct lldp_local_mib); + break; + case DCBX_READ_REMOTE_MIB: + mib_size = sizeof(struct lldp_remote_mib); + break; + default: + return 1; /*error*/ + } + + offset += BP_PORT(bp) * mib_size; + + do { + bnx2x_read_data(bp, base_mib_addr, offset, mib_size); + + max_try_read++; + + switch (read_mib_type) { + case DCBX_READ_LOCAL_MIB: + local_mib = (struct lldp_local_mib *) base_mib_addr; + prefix_seq_num = local_mib->prefix_seq_num; + suffix_seq_num = local_mib->suffix_seq_num; + break; + case DCBX_READ_REMOTE_MIB: + remote_mib = (struct lldp_remote_mib *) base_mib_addr; + prefix_seq_num = remote_mib->prefix_seq_num; + suffix_seq_num = remote_mib->suffix_seq_num; + break; + default: + return 1; /*error*/ + } + } while ((prefix_seq_num != suffix_seq_num) && + (max_try_read < DCBX_LOCAL_MIB_MAX_TRY_READ)); + + if (max_try_read >= DCBX_LOCAL_MIB_MAX_TRY_READ) { + BNX2X_ERR("MIB could not be read\n"); + return 1; + } + + return 0; +} + +static void bnx2x_pfc_set_pfc(struct bnx2x *bp) +{ + if (bp->dcbx_port_params.pfc.enabled && + !(bp->dcbx_error & DCBX_REMOTE_MIB_ERROR)) + /* + * 1. Fills up common PFC structures if required + * 2. Configure NIG, MAC and BRB via the elink + */ + bnx2x_pfc_set(bp); + else + bnx2x_pfc_clear(bp); +} + +static int bnx2x_dcbx_stop_hw_tx(struct bnx2x *bp) +{ + struct bnx2x_func_state_params func_params = {0}; + + func_params.f_obj = &bp->func_obj; + func_params.cmd = BNX2X_F_CMD_TX_STOP; + + DP(NETIF_MSG_LINK, "STOP TRAFFIC\n"); + return bnx2x_func_state_change(bp, &func_params); +} + +static int bnx2x_dcbx_resume_hw_tx(struct bnx2x *bp) +{ + struct bnx2x_func_state_params func_params = {0}; + struct bnx2x_func_tx_start_params *tx_params = + &func_params.params.tx_start; + + func_params.f_obj = &bp->func_obj; + func_params.cmd = BNX2X_F_CMD_TX_START; + + bnx2x_dcbx_fw_struct(bp, tx_params); + + DP(NETIF_MSG_LINK, "START TRAFFIC\n"); + return bnx2x_func_state_change(bp, &func_params); +} + +static void bnx2x_dcbx_2cos_limit_update_ets_config(struct bnx2x *bp) +{ + struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets); + int rc = 0; + + if (ets->num_of_cos == 0 || ets->num_of_cos > DCBX_COS_MAX_NUM_E2) { + BNX2X_ERR("Illegal number of COSes %d\n", ets->num_of_cos); + return; + } + + /* valid COS entries */ + if (ets->num_of_cos == 1) /* no ETS */ + return; + + /* sanity */ + if (((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[0].strict) && + (DCBX_INVALID_COS_BW == ets->cos_params[0].bw_tbl)) || + ((BNX2X_DCBX_STRICT_INVALID == ets->cos_params[1].strict) && + (DCBX_INVALID_COS_BW == ets->cos_params[1].bw_tbl))) { + BNX2X_ERR("all COS should have at least bw_limit or strict" + "ets->cos_params[0].strict= %x" + "ets->cos_params[0].bw_tbl= %x" + "ets->cos_params[1].strict= %x" + "ets->cos_params[1].bw_tbl= %x", + ets->cos_params[0].strict, + ets->cos_params[0].bw_tbl, + ets->cos_params[1].strict, + ets->cos_params[1].bw_tbl); + return; + } + /* If we join a group and there is bw_tbl and strict then bw rules */ + if ((DCBX_INVALID_COS_BW != ets->cos_params[0].bw_tbl) && + (DCBX_INVALID_COS_BW != ets->cos_params[1].bw_tbl)) { + u32 bw_tbl_0 = ets->cos_params[0].bw_tbl; + u32 bw_tbl_1 = ets->cos_params[1].bw_tbl; + /* Do not allow 0-100 configuration + * since PBF does not support it + * force 1-99 instead + */ + if (bw_tbl_0 == 0) { + bw_tbl_0 = 1; + bw_tbl_1 = 99; + } else if (bw_tbl_1 == 0) { + bw_tbl_1 = 1; + bw_tbl_0 = 99; + } + + bnx2x_ets_bw_limit(&bp->link_params, bw_tbl_0, bw_tbl_1); + } else { + if (ets->cos_params[0].strict == BNX2X_DCBX_STRICT_COS_HIGHEST) + rc = bnx2x_ets_strict(&bp->link_params, 0); + else if (ets->cos_params[1].strict + == BNX2X_DCBX_STRICT_COS_HIGHEST) + rc = bnx2x_ets_strict(&bp->link_params, 1); + if (rc) + BNX2X_ERR("update_ets_params failed\n"); + } +} + +/* + * In E3B0 the configuration may have more than 2 COS. + */ +void bnx2x_dcbx_update_ets_config(struct bnx2x *bp) +{ + struct bnx2x_dcbx_pg_params *ets = &(bp->dcbx_port_params.ets); + struct bnx2x_ets_params ets_params = { 0 }; + u8 i; + + ets_params.num_of_cos = ets->num_of_cos; + + for (i = 0; i < ets->num_of_cos; i++) { + /* COS is SP */ + if (ets->cos_params[i].strict != BNX2X_DCBX_STRICT_INVALID) { + if (ets->cos_params[i].bw_tbl != DCBX_INVALID_COS_BW) { + BNX2X_ERR("COS can't be not BW and not SP\n"); + return; + } + + ets_params.cos[i].state = bnx2x_cos_state_strict; + ets_params.cos[i].params.sp_params.pri = + ets->cos_params[i].strict; + } else { /* COS is BW */ + if (ets->cos_params[i].bw_tbl == DCBX_INVALID_COS_BW) { + BNX2X_ERR("COS can't be not BW and not SP\n"); + return; + } + ets_params.cos[i].state = bnx2x_cos_state_bw; + ets_params.cos[i].params.bw_params.bw = + (u8)ets->cos_params[i].bw_tbl; + } + } + + /* Configure the ETS in HW */ + if (bnx2x_ets_e3b0_config(&bp->link_params, &bp->link_vars, + &ets_params)) { + BNX2X_ERR("bnx2x_ets_e3b0_config failed\n"); + bnx2x_ets_disabled(&bp->link_params, &bp->link_vars); + } +} + +static void bnx2x_dcbx_update_ets_params(struct bnx2x *bp) +{ + bnx2x_ets_disabled(&bp->link_params, &bp->link_vars); + + if (!bp->dcbx_port_params.ets.enabled || + (bp->dcbx_error & DCBX_REMOTE_MIB_ERROR)) + return; + + if (CHIP_IS_E3B0(bp)) + bnx2x_dcbx_update_ets_config(bp); + else + bnx2x_dcbx_2cos_limit_update_ets_config(bp); +} + +#ifdef BCM_DCBNL +static int bnx2x_dcbx_read_shmem_remote_mib(struct bnx2x *bp) +{ + struct lldp_remote_mib remote_mib = {0}; + u32 dcbx_remote_mib_offset = SHMEM2_RD(bp, dcbx_remote_mib_offset); + int rc; + + DP(NETIF_MSG_LINK, "dcbx_remote_mib_offset 0x%x\n", + dcbx_remote_mib_offset); + + if (SHMEM_DCBX_REMOTE_MIB_NONE == dcbx_remote_mib_offset) { + BNX2X_ERR("FW doesn't support dcbx_remote_mib_offset\n"); + return -EINVAL; + } + + rc = bnx2x_dcbx_read_mib(bp, (u32 *)&remote_mib, dcbx_remote_mib_offset, + DCBX_READ_REMOTE_MIB); + + if (rc) { + BNX2X_ERR("Faild to read remote mib from FW\n"); + return rc; + } + + /* save features and flags */ + bp->dcbx_remote_feat = remote_mib.features; + bp->dcbx_remote_flags = remote_mib.flags; + return 0; +} +#endif + +static int bnx2x_dcbx_read_shmem_neg_results(struct bnx2x *bp) +{ + struct lldp_local_mib local_mib = {0}; + u32 dcbx_neg_res_offset = SHMEM2_RD(bp, dcbx_neg_res_offset); + int rc; + + DP(NETIF_MSG_LINK, "dcbx_neg_res_offset 0x%x\n", dcbx_neg_res_offset); + + if (SHMEM_DCBX_NEG_RES_NONE == dcbx_neg_res_offset) { + BNX2X_ERR("FW doesn't support dcbx_neg_res_offset\n"); + return -EINVAL; + } + + rc = bnx2x_dcbx_read_mib(bp, (u32 *)&local_mib, dcbx_neg_res_offset, + DCBX_READ_LOCAL_MIB); + + if (rc) { + BNX2X_ERR("Faild to read local mib from FW\n"); + return rc; + } + + /* save features and error */ + bp->dcbx_local_feat = local_mib.features; + bp->dcbx_error = local_mib.error; + return 0; +} + + +#ifdef BCM_DCBNL +static inline +u8 bnx2x_dcbx_dcbnl_app_up(struct dcbx_app_priority_entry *ent) +{ + u8 pri; + + /* Choose the highest priority */ + for (pri = MAX_PFC_PRIORITIES - 1; pri > 0; pri--) + if (ent->pri_bitmap & (1 << pri)) + break; + return pri; +} + +static inline +u8 bnx2x_dcbx_dcbnl_app_idtype(struct dcbx_app_priority_entry *ent) +{ + return ((ent->appBitfield & DCBX_APP_ENTRY_SF_MASK) == + DCBX_APP_SF_PORT) ? DCB_APP_IDTYPE_PORTNUM : + DCB_APP_IDTYPE_ETHTYPE; +} + +int bnx2x_dcbnl_update_applist(struct bnx2x *bp, bool delall) +{ + int i, err = 0; + + for (i = 0; i < DCBX_MAX_APP_PROTOCOL && err == 0; i++) { + struct dcbx_app_priority_entry *ent = + &bp->dcbx_local_feat.app.app_pri_tbl[i]; + + if (ent->appBitfield & DCBX_APP_ENTRY_VALID) { + u8 up = bnx2x_dcbx_dcbnl_app_up(ent); + + /* avoid invalid user-priority */ + if (up) { + struct dcb_app app; + app.selector = bnx2x_dcbx_dcbnl_app_idtype(ent); + app.protocol = ent->app_id; + app.priority = delall ? 0 : up; + err = dcb_setapp(bp->dev, &app); + } + } + } + return err; +} +#endif + +static inline void bnx2x_update_drv_flags(struct bnx2x *bp, u32 flags, u32 set) +{ + if (SHMEM2_HAS(bp, drv_flags)) { + u32 drv_flags; + bnx2x_acquire_hw_lock(bp, HW_LOCK_DRV_FLAGS); + drv_flags = SHMEM2_RD(bp, drv_flags); + + if (set) + SET_FLAGS(drv_flags, flags); + else + RESET_FLAGS(drv_flags, flags); + + SHMEM2_WR(bp, drv_flags, drv_flags); + DP(NETIF_MSG_HW, "drv_flags 0x%08x\n", drv_flags); + bnx2x_release_hw_lock(bp, HW_LOCK_DRV_FLAGS); + } +} + +static inline void bnx2x_dcbx_update_tc_mapping(struct bnx2x *bp) +{ + u8 prio, cos; + for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++) { + for (prio = 0; prio < BNX2X_MAX_PRIORITY; prio++) { + if (bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask + & (1 << prio)) { + bp->prio_to_cos[prio] = cos; + DP(NETIF_MSG_LINK, + "tx_mapping %d --> %d\n", prio, cos); + } + } + } + + /* setup tc must be called under rtnl lock, but we can't take it here + * as we are handling an attetntion on a work queue which must be + * flushed at some rtnl-locked contexts (e.g. if down) + */ + if (!test_and_set_bit(BNX2X_SP_RTNL_SETUP_TC, &bp->sp_rtnl_state)) + schedule_delayed_work(&bp->sp_rtnl_task, 0); +} + +void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) +{ + switch (state) { + case BNX2X_DCBX_STATE_NEG_RECEIVED: + { + DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_NEG_RECEIVED\n"); +#ifdef BCM_DCBNL + /** + * Delete app tlvs from dcbnl before reading new + * negotiation results + */ + bnx2x_dcbnl_update_applist(bp, true); + + /* Read rmeote mib if dcbx is in the FW */ + if (bnx2x_dcbx_read_shmem_remote_mib(bp)) + return; +#endif + /* Read neg results if dcbx is in the FW */ + if (bnx2x_dcbx_read_shmem_neg_results(bp)) + return; + + bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat, + bp->dcbx_error); + + bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat, + bp->dcbx_error); + + /* mark DCBX result for PMF migration */ + bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 1); +#ifdef BCM_DCBNL + /** + * Add new app tlvs to dcbnl + */ + bnx2x_dcbnl_update_applist(bp, false); +#endif + bnx2x_dcbx_stop_hw_tx(bp); + + /* reconfigure the netdevice with the results of the new + * dcbx negotiation. + */ + bnx2x_dcbx_update_tc_mapping(bp); + + return; + } + case BNX2X_DCBX_STATE_TX_PAUSED: + DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_TX_PAUSED\n"); + bnx2x_pfc_set_pfc(bp); + + bnx2x_dcbx_update_ets_params(bp); + bnx2x_dcbx_resume_hw_tx(bp); + return; + case BNX2X_DCBX_STATE_TX_RELEASED: + DP(NETIF_MSG_LINK, "BNX2X_DCBX_STATE_TX_RELEASED\n"); + bnx2x_fw_command(bp, DRV_MSG_CODE_DCBX_PMF_DRV_OK, 0); +#ifdef BCM_DCBNL + /* + * Send a notification for the new negotiated parameters + */ + dcbnl_cee_notify(bp->dev, RTM_GETDCB, DCB_CMD_CEE_GET, 0, 0); +#endif + return; + default: + BNX2X_ERR("Unknown DCBX_STATE\n"); + } +} + +#define LLDP_ADMIN_MIB_OFFSET(bp) (PORT_MAX*sizeof(struct lldp_params) + \ + BP_PORT(bp)*sizeof(struct lldp_admin_mib)) + +static void bnx2x_dcbx_admin_mib_updated_params(struct bnx2x *bp, + u32 dcbx_lldp_params_offset) +{ + struct lldp_admin_mib admin_mib; + u32 i, other_traf_type = PREDEFINED_APP_IDX_MAX, traf_type = 0; + u32 offset = dcbx_lldp_params_offset + LLDP_ADMIN_MIB_OFFSET(bp); + + /*shortcuts*/ + struct dcbx_features *af = &admin_mib.features; + struct bnx2x_config_dcbx_params *dp = &bp->dcbx_config_params; + + memset(&admin_mib, 0, sizeof(struct lldp_admin_mib)); + + /* Read the data first */ + bnx2x_read_data(bp, (u32 *)&admin_mib, offset, + sizeof(struct lldp_admin_mib)); + + if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON) + SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_DCBX_ENABLED); + + if (dp->overwrite_settings == BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE) { + + RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_CEE_VERSION_MASK); + admin_mib.ver_cfg_flags |= + (dp->admin_dcbx_version << DCBX_CEE_VERSION_SHIFT) & + DCBX_CEE_VERSION_MASK; + + af->ets.enabled = (u8)dp->admin_ets_enable; + + af->pfc.enabled = (u8)dp->admin_pfc_enable; + + /* FOR IEEE dp->admin_tc_supported_tx_enable */ + if (dp->admin_ets_configuration_tx_enable) + SET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_ETS_CONFIG_TX_ENABLED); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_ETS_CONFIG_TX_ENABLED); + /* For IEEE admin_ets_recommendation_tx_enable */ + if (dp->admin_pfc_tx_enable) + SET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_PFC_CONFIG_TX_ENABLED); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_PFC_CONFIG_TX_ENABLED); + + if (dp->admin_application_priority_tx_enable) + SET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_APP_CONFIG_TX_ENABLED); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, + DCBX_APP_CONFIG_TX_ENABLED); + + if (dp->admin_ets_willing) + SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_ETS_WILLING); + /* For IEEE admin_ets_reco_valid */ + if (dp->admin_pfc_willing) + SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_PFC_WILLING); + + if (dp->admin_app_priority_willing) + SET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING); + else + RESET_FLAGS(admin_mib.ver_cfg_flags, DCBX_APP_WILLING); + + for (i = 0 ; i < DCBX_MAX_NUM_PG_BW_ENTRIES; i++) { + DCBX_PG_BW_SET(af->ets.pg_bw_tbl, i, + (u8)dp->admin_configuration_bw_precentage[i]); + + DP(NETIF_MSG_LINK, "pg_bw_tbl[%d] = %02x\n", + i, DCBX_PG_BW_GET(af->ets.pg_bw_tbl, i)); + } + + for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) { + DCBX_PRI_PG_SET(af->ets.pri_pg_tbl, i, + (u8)dp->admin_configuration_ets_pg[i]); + + DP(NETIF_MSG_LINK, "pri_pg_tbl[%d] = %02x\n", + i, DCBX_PRI_PG_GET(af->ets.pri_pg_tbl, i)); + } + + /*For IEEE admin_recommendation_bw_precentage + *For IEEE admin_recommendation_ets_pg */ + af->pfc.pri_en_bitmap = (u8)dp->admin_pfc_bitmap; + for (i = 0; i < 4; i++) { + if (dp->admin_priority_app_table[i].valid) { + struct bnx2x_admin_priority_app_table *table = + dp->admin_priority_app_table; + if ((ETH_TYPE_FCOE == table[i].app_id) && + (TRAFFIC_TYPE_ETH == table[i].traffic_type)) + traf_type = FCOE_APP_IDX; + else if ((TCP_PORT_ISCSI == table[i].app_id) && + (TRAFFIC_TYPE_PORT == table[i].traffic_type)) + traf_type = ISCSI_APP_IDX; + else + traf_type = other_traf_type++; + + af->app.app_pri_tbl[traf_type].app_id = + table[i].app_id; + + af->app.app_pri_tbl[traf_type].pri_bitmap = + (u8)(1 << table[i].priority); + + af->app.app_pri_tbl[traf_type].appBitfield = + (DCBX_APP_ENTRY_VALID); + + af->app.app_pri_tbl[traf_type].appBitfield |= + (TRAFFIC_TYPE_ETH == table[i].traffic_type) ? + DCBX_APP_SF_ETH_TYPE : DCBX_APP_SF_PORT; + } + } + + af->app.default_pri = (u8)dp->admin_default_priority; + + } + + /* Write the data. */ + bnx2x_write_data(bp, (u32 *)&admin_mib, offset, + sizeof(struct lldp_admin_mib)); + +} + +void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled) +{ + if (!CHIP_IS_E1x(bp)) { + bp->dcb_state = dcb_on; + bp->dcbx_enabled = dcbx_enabled; + } else { + bp->dcb_state = false; + bp->dcbx_enabled = BNX2X_DCBX_ENABLED_INVALID; + } + DP(NETIF_MSG_LINK, "DCB state [%s:%s]\n", + dcb_on ? "ON" : "OFF", + dcbx_enabled == BNX2X_DCBX_ENABLED_OFF ? "user-mode" : + dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF ? "on-chip static" : + dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_ON ? + "on-chip with negotiation" : "invalid"); +} + +void bnx2x_dcbx_init_params(struct bnx2x *bp) +{ + bp->dcbx_config_params.admin_dcbx_version = 0x0; /* 0 - CEE; 1 - IEEE */ + bp->dcbx_config_params.admin_ets_willing = 1; + bp->dcbx_config_params.admin_pfc_willing = 1; + bp->dcbx_config_params.overwrite_settings = 1; + bp->dcbx_config_params.admin_ets_enable = 1; + bp->dcbx_config_params.admin_pfc_enable = 1; + bp->dcbx_config_params.admin_tc_supported_tx_enable = 1; + bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1; + bp->dcbx_config_params.admin_pfc_tx_enable = 1; + bp->dcbx_config_params.admin_application_priority_tx_enable = 1; + bp->dcbx_config_params.admin_ets_reco_valid = 1; + bp->dcbx_config_params.admin_app_priority_willing = 1; + bp->dcbx_config_params.admin_configuration_bw_precentage[0] = 00; + bp->dcbx_config_params.admin_configuration_bw_precentage[1] = 50; + bp->dcbx_config_params.admin_configuration_bw_precentage[2] = 50; + bp->dcbx_config_params.admin_configuration_bw_precentage[3] = 0; + bp->dcbx_config_params.admin_configuration_bw_precentage[4] = 0; + bp->dcbx_config_params.admin_configuration_bw_precentage[5] = 0; + bp->dcbx_config_params.admin_configuration_bw_precentage[6] = 0; + bp->dcbx_config_params.admin_configuration_bw_precentage[7] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[0] = 1; + bp->dcbx_config_params.admin_configuration_ets_pg[1] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[2] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[3] = 2; + bp->dcbx_config_params.admin_configuration_ets_pg[4] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[5] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[6] = 0; + bp->dcbx_config_params.admin_configuration_ets_pg[7] = 0; + bp->dcbx_config_params.admin_recommendation_bw_precentage[0] = 0; + bp->dcbx_config_params.admin_recommendation_bw_precentage[1] = 1; + bp->dcbx_config_params.admin_recommendation_bw_precentage[2] = 2; + bp->dcbx_config_params.admin_recommendation_bw_precentage[3] = 0; + bp->dcbx_config_params.admin_recommendation_bw_precentage[4] = 7; + bp->dcbx_config_params.admin_recommendation_bw_precentage[5] = 5; + bp->dcbx_config_params.admin_recommendation_bw_precentage[6] = 6; + bp->dcbx_config_params.admin_recommendation_bw_precentage[7] = 7; + bp->dcbx_config_params.admin_recommendation_ets_pg[0] = 0; + bp->dcbx_config_params.admin_recommendation_ets_pg[1] = 1; + bp->dcbx_config_params.admin_recommendation_ets_pg[2] = 2; + bp->dcbx_config_params.admin_recommendation_ets_pg[3] = 3; + bp->dcbx_config_params.admin_recommendation_ets_pg[4] = 4; + bp->dcbx_config_params.admin_recommendation_ets_pg[5] = 5; + bp->dcbx_config_params.admin_recommendation_ets_pg[6] = 6; + bp->dcbx_config_params.admin_recommendation_ets_pg[7] = 7; + bp->dcbx_config_params.admin_pfc_bitmap = 0x8; /* FCoE(3) enable */ + bp->dcbx_config_params.admin_priority_app_table[0].valid = 1; + bp->dcbx_config_params.admin_priority_app_table[1].valid = 1; + bp->dcbx_config_params.admin_priority_app_table[2].valid = 0; + bp->dcbx_config_params.admin_priority_app_table[3].valid = 0; + bp->dcbx_config_params.admin_priority_app_table[0].priority = 3; + bp->dcbx_config_params.admin_priority_app_table[1].priority = 0; + bp->dcbx_config_params.admin_priority_app_table[2].priority = 0; + bp->dcbx_config_params.admin_priority_app_table[3].priority = 0; + bp->dcbx_config_params.admin_priority_app_table[0].traffic_type = 0; + bp->dcbx_config_params.admin_priority_app_table[1].traffic_type = 1; + bp->dcbx_config_params.admin_priority_app_table[2].traffic_type = 0; + bp->dcbx_config_params.admin_priority_app_table[3].traffic_type = 0; + bp->dcbx_config_params.admin_priority_app_table[0].app_id = 0x8906; + bp->dcbx_config_params.admin_priority_app_table[1].app_id = 3260; + bp->dcbx_config_params.admin_priority_app_table[2].app_id = 0; + bp->dcbx_config_params.admin_priority_app_table[3].app_id = 0; + bp->dcbx_config_params.admin_default_priority = + bp->dcbx_config_params.admin_priority_app_table[1].priority; +} + +void bnx2x_dcbx_init(struct bnx2x *bp) +{ + u32 dcbx_lldp_params_offset = SHMEM_LLDP_DCBX_PARAMS_NONE; + + if (bp->dcbx_enabled <= 0) + return; + + /* validate: + * chip of good for dcbx version, + * dcb is wanted + * the function is pmf + * shmem2 contains DCBX support fields + */ + DP(NETIF_MSG_LINK, "dcb_state %d bp->port.pmf %d\n", + bp->dcb_state, bp->port.pmf); + + if (bp->dcb_state == BNX2X_DCB_STATE_ON && bp->port.pmf && + SHMEM2_HAS(bp, dcbx_lldp_params_offset)) { + dcbx_lldp_params_offset = + SHMEM2_RD(bp, dcbx_lldp_params_offset); + + DP(NETIF_MSG_LINK, "dcbx_lldp_params_offset 0x%x\n", + dcbx_lldp_params_offset); + + bnx2x_update_drv_flags(bp, DRV_FLAGS_DCB_CONFIGURED, 0); + + if (SHMEM_LLDP_DCBX_PARAMS_NONE != dcbx_lldp_params_offset) { + bnx2x_dcbx_admin_mib_updated_params(bp, + dcbx_lldp_params_offset); + + /* Let HW start negotiation */ + bnx2x_fw_command(bp, + DRV_MSG_CODE_DCBX_ADMIN_PMF_MSG, 0); + } + } +} +static void +bnx2x_dcbx_print_cos_params(struct bnx2x *bp, + struct bnx2x_func_tx_start_params *pfc_fw_cfg) +{ + u8 pri = 0; + u8 cos = 0; + + DP(NETIF_MSG_LINK, + "pfc_fw_cfg->dcb_version %x\n", pfc_fw_cfg->dcb_version); + DP(NETIF_MSG_LINK, + "pdev->params.dcbx_port_params.pfc." + "priority_non_pauseable_mask %x\n", + bp->dcbx_port_params.pfc.priority_non_pauseable_mask); + + for (cos = 0 ; cos < bp->dcbx_port_params.ets.num_of_cos ; cos++) { + DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets." + "cos_params[%d].pri_bitmask %x\n", cos, + bp->dcbx_port_params.ets.cos_params[cos].pri_bitmask); + + DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets." + "cos_params[%d].bw_tbl %x\n", cos, + bp->dcbx_port_params.ets.cos_params[cos].bw_tbl); + + DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets." + "cos_params[%d].strict %x\n", cos, + bp->dcbx_port_params.ets.cos_params[cos].strict); + + DP(NETIF_MSG_LINK, "pdev->params.dcbx_port_params.ets." + "cos_params[%d].pauseable %x\n", cos, + bp->dcbx_port_params.ets.cos_params[cos].pauseable); + } + + for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) { + DP(NETIF_MSG_LINK, + "pfc_fw_cfg->traffic_type_to_priority_cos[%d]." + "priority %x\n", pri, + pfc_fw_cfg->traffic_type_to_priority_cos[pri].priority); + + DP(NETIF_MSG_LINK, + "pfc_fw_cfg->traffic_type_to_priority_cos[%d].cos %x\n", + pri, pfc_fw_cfg->traffic_type_to_priority_cos[pri].cos); + } +} + +/* fills help_data according to pg_info */ +static void bnx2x_dcbx_get_num_pg_traf_type(struct bnx2x *bp, + u32 *pg_pri_orginal_spread, + struct pg_help_data *help_data) +{ + bool pg_found = false; + u32 i, traf_type, add_traf_type, add_pg; + u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; + struct pg_entry_help_data *data = help_data->data; /*shotcut*/ + + /* Set to invalid */ + for (i = 0; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) + data[i].pg = DCBX_ILLEGAL_PG; + + for (add_traf_type = 0; + add_traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX; add_traf_type++) { + pg_found = false; + if (ttp[add_traf_type] < MAX_PFC_PRIORITIES) { + add_pg = (u8)pg_pri_orginal_spread[ttp[add_traf_type]]; + for (traf_type = 0; + traf_type < LLFC_DRIVER_TRAFFIC_TYPE_MAX; + traf_type++) { + if (data[traf_type].pg == add_pg) { + if (!(data[traf_type].pg_priority & + (1 << ttp[add_traf_type]))) + data[traf_type]. + num_of_dif_pri++; + data[traf_type].pg_priority |= + (1 << ttp[add_traf_type]); + pg_found = true; + break; + } + } + if (false == pg_found) { + data[help_data->num_of_pg].pg = add_pg; + data[help_data->num_of_pg].pg_priority = + (1 << ttp[add_traf_type]); + data[help_data->num_of_pg].num_of_dif_pri = 1; + help_data->num_of_pg++; + } + } + DP(NETIF_MSG_LINK, + "add_traf_type %d pg_found %s num_of_pg %d\n", + add_traf_type, (false == pg_found) ? "NO" : "YES", + help_data->num_of_pg); + } +} + +static void bnx2x_dcbx_ets_disabled_entry_data(struct bnx2x *bp, + struct cos_help_data *cos_data, + u32 pri_join_mask) +{ + /* Only one priority than only one COS */ + cos_data->data[0].pausable = + IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); + cos_data->data[0].pri_join_mask = pri_join_mask; + cos_data->data[0].cos_bw = 100; + cos_data->num_of_cos = 1; +} + +static inline void bnx2x_dcbx_add_to_cos_bw(struct bnx2x *bp, + struct cos_entry_help_data *data, + u8 pg_bw) +{ + if (data->cos_bw == DCBX_INVALID_COS_BW) + data->cos_bw = pg_bw; + else + data->cos_bw += pg_bw; +} + +static void bnx2x_dcbx_separate_pauseable_from_non(struct bnx2x *bp, + struct cos_help_data *cos_data, + u32 *pg_pri_orginal_spread, + struct dcbx_ets_feature *ets) +{ + u32 pri_tested = 0; + u8 i = 0; + u8 entry = 0; + u8 pg_entry = 0; + u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX; + + cos_data->data[0].pausable = true; + cos_data->data[1].pausable = false; + cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0; + + for (i = 0 ; i < num_of_pri ; i++) { + pri_tested = 1 << bp->dcbx_port_params. + app.traffic_type_priority[i]; + + if (pri_tested & DCBX_PFC_PRI_NON_PAUSE_MASK(bp)) { + cos_data->data[1].pri_join_mask |= pri_tested; + entry = 1; + } else { + cos_data->data[0].pri_join_mask |= pri_tested; + entry = 0; + } + pg_entry = (u8)pg_pri_orginal_spread[bp->dcbx_port_params. + app.traffic_type_priority[i]]; + /* There can be only one strict pg */ + if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES) + bnx2x_dcbx_add_to_cos_bw(bp, &cos_data->data[entry], + DCBX_PG_BW_GET(ets->pg_bw_tbl, pg_entry)); + else + /* If we join a group and one is strict + * than the bw rulls */ + cos_data->data[entry].strict = + BNX2X_DCBX_STRICT_COS_HIGHEST; + } + if ((0 == cos_data->data[0].pri_join_mask) && + (0 == cos_data->data[1].pri_join_mask)) + BNX2X_ERR("dcbx error: Both groups must have priorities\n"); +} + + +#ifndef POWER_OF_2 +#define POWER_OF_2(x) ((0 != x) && (0 == (x & (x-1)))) +#endif + +static void bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params(struct bnx2x *bp, + struct pg_help_data *pg_help_data, + struct cos_help_data *cos_data, + u32 pri_join_mask, + u8 num_of_dif_pri) +{ + u8 i = 0; + u32 pri_tested = 0; + u32 pri_mask_without_pri = 0; + u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; + /*debug*/ + if (num_of_dif_pri == 1) { + bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data, pri_join_mask); + return; + } + /* single priority group */ + if (pg_help_data->data[0].pg < DCBX_MAX_NUM_PG_BW_ENTRIES) { + /* If there are both pauseable and non-pauseable priorities, + * the pauseable priorities go to the first queue and + * the non-pauseable priorities go to the second queue. + */ + if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) { + /* Pauseable */ + cos_data->data[0].pausable = true; + /* Non pauseable.*/ + cos_data->data[1].pausable = false; + + if (2 == num_of_dif_pri) { + cos_data->data[0].cos_bw = 50; + cos_data->data[1].cos_bw = 50; + } + + if (3 == num_of_dif_pri) { + if (POWER_OF_2(DCBX_PFC_PRI_GET_PAUSE(bp, + pri_join_mask))) { + cos_data->data[0].cos_bw = 33; + cos_data->data[1].cos_bw = 67; + } else { + cos_data->data[0].cos_bw = 67; + cos_data->data[1].cos_bw = 33; + } + } + + } else if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask)) { + /* If there are only pauseable priorities, + * then one/two priorities go to the first queue + * and one priority goes to the second queue. + */ + if (2 == num_of_dif_pri) { + cos_data->data[0].cos_bw = 50; + cos_data->data[1].cos_bw = 50; + } else { + cos_data->data[0].cos_bw = 67; + cos_data->data[1].cos_bw = 33; + } + cos_data->data[1].pausable = true; + cos_data->data[0].pausable = true; + /* All priorities except FCOE */ + cos_data->data[0].pri_join_mask = (pri_join_mask & + ((u8)~(1 << ttp[LLFC_TRAFFIC_TYPE_FCOE]))); + /* Only FCOE priority.*/ + cos_data->data[1].pri_join_mask = + (1 << ttp[LLFC_TRAFFIC_TYPE_FCOE]); + } else + /* If there are only non-pauseable priorities, + * they will all go to the same queue. + */ + bnx2x_dcbx_ets_disabled_entry_data(bp, + cos_data, pri_join_mask); + } else { + /* priority group which is not BW limited (PG#15):*/ + if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) { + /* If there are both pauseable and non-pauseable + * priorities, the pauseable priorities go to the first + * queue and the non-pauseable priorities + * go to the second queue. + */ + if (DCBX_PFC_PRI_GET_PAUSE(bp, pri_join_mask) > + DCBX_PFC_PRI_GET_NON_PAUSE(bp, pri_join_mask)) { + cos_data->data[0].strict = + BNX2X_DCBX_STRICT_COS_HIGHEST; + cos_data->data[1].strict = + BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI( + BNX2X_DCBX_STRICT_COS_HIGHEST); + } else { + cos_data->data[0].strict = + BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI( + BNX2X_DCBX_STRICT_COS_HIGHEST); + cos_data->data[1].strict = + BNX2X_DCBX_STRICT_COS_HIGHEST; + } + /* Pauseable */ + cos_data->data[0].pausable = true; + /* Non pause-able.*/ + cos_data->data[1].pausable = false; + } else { + /* If there are only pauseable priorities or + * only non-pauseable,* the lower priorities go + * to the first queue and the higherpriorities go + * to the second queue. + */ + cos_data->data[0].pausable = + cos_data->data[1].pausable = + IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); + + for (i = 0 ; i < LLFC_DRIVER_TRAFFIC_TYPE_MAX; i++) { + pri_tested = 1 << bp->dcbx_port_params. + app.traffic_type_priority[i]; + /* Remove priority tested */ + pri_mask_without_pri = + (pri_join_mask & ((u8)(~pri_tested))); + if (pri_mask_without_pri < pri_tested) + break; + } + + if (i == LLFC_DRIVER_TRAFFIC_TYPE_MAX) + BNX2X_ERR("Invalid value for pri_join_mask -" + " could not find a priority\n"); + + cos_data->data[0].pri_join_mask = pri_mask_without_pri; + cos_data->data[1].pri_join_mask = pri_tested; + /* Both queues are strict priority, + * and that with the highest priority + * gets the highest strict priority in the arbiter. + */ + cos_data->data[0].strict = + BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI( + BNX2X_DCBX_STRICT_COS_HIGHEST); + cos_data->data[1].strict = + BNX2X_DCBX_STRICT_COS_HIGHEST; + } + } +} + +static void bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params( + struct bnx2x *bp, + struct pg_help_data *pg_help_data, + struct dcbx_ets_feature *ets, + struct cos_help_data *cos_data, + u32 *pg_pri_orginal_spread, + u32 pri_join_mask, + u8 num_of_dif_pri) +{ + u8 i = 0; + u8 pg[DCBX_COS_MAX_NUM_E2] = { 0 }; + + /* If there are both pauseable and non-pauseable priorities, + * the pauseable priorities go to the first queue and + * the non-pauseable priorities go to the second queue. + */ + if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) { + if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, + pg_help_data->data[0].pg_priority) || + IS_DCBX_PFC_PRI_MIX_PAUSE(bp, + pg_help_data->data[1].pg_priority)) { + /* If one PG contains both pauseable and + * non-pauseable priorities then ETS is disabled. + */ + bnx2x_dcbx_separate_pauseable_from_non(bp, cos_data, + pg_pri_orginal_spread, ets); + bp->dcbx_port_params.ets.enabled = false; + return; + } + + /* Pauseable */ + cos_data->data[0].pausable = true; + /* Non pauseable. */ + cos_data->data[1].pausable = false; + if (IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, + pg_help_data->data[0].pg_priority)) { + /* 0 is pauseable */ + cos_data->data[0].pri_join_mask = + pg_help_data->data[0].pg_priority; + pg[0] = pg_help_data->data[0].pg; + cos_data->data[1].pri_join_mask = + pg_help_data->data[1].pg_priority; + pg[1] = pg_help_data->data[1].pg; + } else {/* 1 is pauseable */ + cos_data->data[0].pri_join_mask = + pg_help_data->data[1].pg_priority; + pg[0] = pg_help_data->data[1].pg; + cos_data->data[1].pri_join_mask = + pg_help_data->data[0].pg_priority; + pg[1] = pg_help_data->data[0].pg; + } + } else { + /* If there are only pauseable priorities or + * only non-pauseable, each PG goes to a queue. + */ + cos_data->data[0].pausable = cos_data->data[1].pausable = + IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); + cos_data->data[0].pri_join_mask = + pg_help_data->data[0].pg_priority; + pg[0] = pg_help_data->data[0].pg; + cos_data->data[1].pri_join_mask = + pg_help_data->data[1].pg_priority; + pg[1] = pg_help_data->data[1].pg; + } + + /* There can be only one strict pg */ + for (i = 0 ; i < ARRAY_SIZE(pg); i++) { + if (pg[i] < DCBX_MAX_NUM_PG_BW_ENTRIES) + cos_data->data[i].cos_bw = + DCBX_PG_BW_GET(ets->pg_bw_tbl, pg[i]); + else + cos_data->data[i].strict = + BNX2X_DCBX_STRICT_COS_HIGHEST; + } +} + +static int bnx2x_dcbx_join_pgs( + struct bnx2x *bp, + struct dcbx_ets_feature *ets, + struct pg_help_data *pg_help_data, + u8 required_num_of_pg) +{ + u8 entry_joined = pg_help_data->num_of_pg - 1; + u8 entry_removed = entry_joined + 1; + u8 pg_joined = 0; + + if (required_num_of_pg == 0 || ARRAY_SIZE(pg_help_data->data) + <= pg_help_data->num_of_pg) { + + BNX2X_ERR("required_num_of_pg can't be zero\n"); + return -EINVAL; + } + + while (required_num_of_pg < pg_help_data->num_of_pg) { + entry_joined = pg_help_data->num_of_pg - 2; + entry_removed = entry_joined + 1; + /* protect index */ + entry_removed %= ARRAY_SIZE(pg_help_data->data); + + pg_help_data->data[entry_joined].pg_priority |= + pg_help_data->data[entry_removed].pg_priority; + + pg_help_data->data[entry_joined].num_of_dif_pri += + pg_help_data->data[entry_removed].num_of_dif_pri; + + if (pg_help_data->data[entry_joined].pg == DCBX_STRICT_PRI_PG || + pg_help_data->data[entry_removed].pg == DCBX_STRICT_PRI_PG) + /* Entries joined strict priority rules */ + pg_help_data->data[entry_joined].pg = + DCBX_STRICT_PRI_PG; + else { + /* Entries can be joined join BW */ + pg_joined = DCBX_PG_BW_GET(ets->pg_bw_tbl, + pg_help_data->data[entry_joined].pg) + + DCBX_PG_BW_GET(ets->pg_bw_tbl, + pg_help_data->data[entry_removed].pg); + + DCBX_PG_BW_SET(ets->pg_bw_tbl, + pg_help_data->data[entry_joined].pg, pg_joined); + } + /* Joined the entries */ + pg_help_data->num_of_pg--; + } + + return 0; +} + +static void bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params( + struct bnx2x *bp, + struct pg_help_data *pg_help_data, + struct dcbx_ets_feature *ets, + struct cos_help_data *cos_data, + u32 *pg_pri_orginal_spread, + u32 pri_join_mask, + u8 num_of_dif_pri) +{ + u8 i = 0; + u32 pri_tested = 0; + u8 entry = 0; + u8 pg_entry = 0; + bool b_found_strict = false; + u8 num_of_pri = LLFC_DRIVER_TRAFFIC_TYPE_MAX; + + cos_data->data[0].pri_join_mask = cos_data->data[1].pri_join_mask = 0; + /* If there are both pauseable and non-pauseable priorities, + * the pauseable priorities go to the first queue and the + * non-pauseable priorities go to the second queue. + */ + if (IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pri_join_mask)) + bnx2x_dcbx_separate_pauseable_from_non(bp, + cos_data, pg_pri_orginal_spread, ets); + else { + /* If two BW-limited PG-s were combined to one queue, + * the BW is their sum. + * + * If there are only pauseable priorities or only non-pauseable, + * and there are both BW-limited and non-BW-limited PG-s, + * the BW-limited PG/s go to one queue and the non-BW-limited + * PG/s go to the second queue. + * + * If there are only pauseable priorities or only non-pauseable + * and all are BW limited, then two priorities go to the first + * queue and one priority goes to the second queue. + * + * We will join this two cases: + * if one is BW limited it will go to the secoend queue + * otherwise the last priority will get it + */ + + cos_data->data[0].pausable = cos_data->data[1].pausable = + IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pri_join_mask); + + for (i = 0 ; i < num_of_pri; i++) { + pri_tested = 1 << bp->dcbx_port_params. + app.traffic_type_priority[i]; + pg_entry = (u8)pg_pri_orginal_spread[bp-> + dcbx_port_params.app.traffic_type_priority[i]]; + + if (pg_entry < DCBX_MAX_NUM_PG_BW_ENTRIES) { + entry = 0; + + if (i == (num_of_pri-1) && + false == b_found_strict) + /* last entry will be handled separately + * If no priority is strict than last + * enty goes to last queue.*/ + entry = 1; + cos_data->data[entry].pri_join_mask |= + pri_tested; + bnx2x_dcbx_add_to_cos_bw(bp, + &cos_data->data[entry], + DCBX_PG_BW_GET(ets->pg_bw_tbl, + pg_entry)); + } else { + b_found_strict = true; + cos_data->data[1].pri_join_mask |= pri_tested; + /* If we join a group and one is strict + * than the bw rulls */ + cos_data->data[1].strict = + BNX2X_DCBX_STRICT_COS_HIGHEST; + } + } + } +} + + +static void bnx2x_dcbx_2cos_limit_cee_fill_cos_params(struct bnx2x *bp, + struct pg_help_data *help_data, + struct dcbx_ets_feature *ets, + struct cos_help_data *cos_data, + u32 *pg_pri_orginal_spread, + u32 pri_join_mask, + u8 num_of_dif_pri) +{ + + /* default E2 settings */ + cos_data->num_of_cos = DCBX_COS_MAX_NUM_E2; + + switch (help_data->num_of_pg) { + case 1: + bnx2x_dcbx_2cos_limit_cee_single_pg_to_cos_params( + bp, + help_data, + cos_data, + pri_join_mask, + num_of_dif_pri); + break; + case 2: + bnx2x_dcbx_2cos_limit_cee_two_pg_to_cos_params( + bp, + help_data, + ets, + cos_data, + pg_pri_orginal_spread, + pri_join_mask, + num_of_dif_pri); + break; + + case 3: + bnx2x_dcbx_2cos_limit_cee_three_pg_to_cos_params( + bp, + help_data, + ets, + cos_data, + pg_pri_orginal_spread, + pri_join_mask, + num_of_dif_pri); + break; + default: + BNX2X_ERR("Wrong pg_help_data.num_of_pg\n"); + bnx2x_dcbx_ets_disabled_entry_data(bp, + cos_data, pri_join_mask); + } +} + +static int bnx2x_dcbx_spread_strict_pri(struct bnx2x *bp, + struct cos_help_data *cos_data, + u8 entry, + u8 num_spread_of_entries, + u8 strict_app_pris) +{ + u8 strict_pri = BNX2X_DCBX_STRICT_COS_HIGHEST; + u8 num_of_app_pri = MAX_PFC_PRIORITIES; + u8 app_pri_bit = 0; + + while (num_spread_of_entries && num_of_app_pri > 0) { + app_pri_bit = 1 << (num_of_app_pri - 1); + if (app_pri_bit & strict_app_pris) { + struct cos_entry_help_data *data = &cos_data-> + data[entry]; + num_spread_of_entries--; + if (num_spread_of_entries == 0) { + /* last entry needed put all the entries left */ + data->cos_bw = DCBX_INVALID_COS_BW; + data->strict = strict_pri; + data->pri_join_mask = strict_app_pris; + data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp, + data->pri_join_mask); + } else { + strict_app_pris &= ~app_pri_bit; + + data->cos_bw = DCBX_INVALID_COS_BW; + data->strict = strict_pri; + data->pri_join_mask = app_pri_bit; + data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp, + data->pri_join_mask); + } + + strict_pri = + BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(strict_pri); + entry++; + } + + num_of_app_pri--; + } + + if (num_spread_of_entries) + return -EINVAL; + + return 0; +} + +static u8 bnx2x_dcbx_cee_fill_strict_pri(struct bnx2x *bp, + struct cos_help_data *cos_data, + u8 entry, + u8 num_spread_of_entries, + u8 strict_app_pris) +{ + + if (bnx2x_dcbx_spread_strict_pri(bp, cos_data, entry, + num_spread_of_entries, + strict_app_pris)) { + struct cos_entry_help_data *data = &cos_data-> + data[entry]; + /* Fill BW entry */ + data->cos_bw = DCBX_INVALID_COS_BW; + data->strict = BNX2X_DCBX_STRICT_COS_HIGHEST; + data->pri_join_mask = strict_app_pris; + data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp, + data->pri_join_mask); + return 1; + } + + return num_spread_of_entries; +} + +static void bnx2x_dcbx_cee_fill_cos_params(struct bnx2x *bp, + struct pg_help_data *help_data, + struct dcbx_ets_feature *ets, + struct cos_help_data *cos_data, + u32 pri_join_mask) + +{ + u8 need_num_of_entries = 0; + u8 i = 0; + u8 entry = 0; + + /* + * if the number of requested PG-s in CEE is greater than 3 + * then the results are not determined since this is a violation + * of the standard. + */ + if (help_data->num_of_pg > DCBX_COS_MAX_NUM_E3B0) { + if (bnx2x_dcbx_join_pgs(bp, ets, help_data, + DCBX_COS_MAX_NUM_E3B0)) { + BNX2X_ERR("Unable to reduce the number of PGs -" + "we will disables ETS\n"); + bnx2x_dcbx_ets_disabled_entry_data(bp, cos_data, + pri_join_mask); + return; + } + } + + for (i = 0 ; i < help_data->num_of_pg; i++) { + struct pg_entry_help_data *pg = &help_data->data[i]; + if (pg->pg < DCBX_MAX_NUM_PG_BW_ENTRIES) { + struct cos_entry_help_data *data = &cos_data-> + data[entry]; + /* Fill BW entry */ + data->cos_bw = DCBX_PG_BW_GET(ets->pg_bw_tbl, pg->pg); + data->strict = BNX2X_DCBX_STRICT_INVALID; + data->pri_join_mask = pg->pg_priority; + data->pausable = DCBX_IS_PFC_PRI_SOME_PAUSE(bp, + data->pri_join_mask); + + entry++; + } else { + need_num_of_entries = min_t(u8, + (u8)pg->num_of_dif_pri, + (u8)DCBX_COS_MAX_NUM_E3B0 - + help_data->num_of_pg + 1); + /* + * If there are still VOQ-s which have no associated PG, + * then associate these VOQ-s to PG15. These PG-s will + * be used for SP between priorities on PG15. + */ + entry += bnx2x_dcbx_cee_fill_strict_pri(bp, cos_data, + entry, need_num_of_entries, pg->pg_priority); + } + } + + /* the entry will represent the number of COSes used */ + cos_data->num_of_cos = entry; +} +static void bnx2x_dcbx_fill_cos_params(struct bnx2x *bp, + struct pg_help_data *help_data, + struct dcbx_ets_feature *ets, + u32 *pg_pri_orginal_spread) +{ + struct cos_help_data cos_data; + u8 i = 0; + u32 pri_join_mask = 0; + u8 num_of_dif_pri = 0; + + memset(&cos_data, 0, sizeof(cos_data)); + + /* Validate the pg value */ + for (i = 0; i < help_data->num_of_pg ; i++) { + if (DCBX_STRICT_PRIORITY != help_data->data[i].pg && + DCBX_MAX_NUM_PG_BW_ENTRIES <= help_data->data[i].pg) + BNX2X_ERR("Invalid pg[%d] data %x\n", i, + help_data->data[i].pg); + pri_join_mask |= help_data->data[i].pg_priority; + num_of_dif_pri += help_data->data[i].num_of_dif_pri; + } + + /* defaults */ + cos_data.num_of_cos = 1; + for (i = 0; i < ARRAY_SIZE(cos_data.data); i++) { + cos_data.data[i].pri_join_mask = 0; + cos_data.data[i].pausable = false; + cos_data.data[i].strict = BNX2X_DCBX_STRICT_INVALID; + cos_data.data[i].cos_bw = DCBX_INVALID_COS_BW; + } + + if (CHIP_IS_E3B0(bp)) + bnx2x_dcbx_cee_fill_cos_params(bp, help_data, ets, + &cos_data, pri_join_mask); + else /* E2 + E3A0 */ + bnx2x_dcbx_2cos_limit_cee_fill_cos_params(bp, + help_data, ets, + &cos_data, + pg_pri_orginal_spread, + pri_join_mask, + num_of_dif_pri); + + for (i = 0; i < cos_data.num_of_cos ; i++) { + struct bnx2x_dcbx_cos_params *p = + &bp->dcbx_port_params.ets.cos_params[i]; + + p->strict = cos_data.data[i].strict; + p->bw_tbl = cos_data.data[i].cos_bw; + p->pri_bitmask = cos_data.data[i].pri_join_mask; + p->pauseable = cos_data.data[i].pausable; + + /* sanity */ + if (p->bw_tbl != DCBX_INVALID_COS_BW || + p->strict != BNX2X_DCBX_STRICT_INVALID) { + if (p->pri_bitmask == 0) + BNX2X_ERR("Invalid pri_bitmask for %d\n", i); + + if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp)) { + + if (p->pauseable && + DCBX_PFC_PRI_GET_NON_PAUSE(bp, + p->pri_bitmask) != 0) + BNX2X_ERR("Inconsistent config for " + "pausable COS %d\n", i); + + if (!p->pauseable && + DCBX_PFC_PRI_GET_PAUSE(bp, + p->pri_bitmask) != 0) + BNX2X_ERR("Inconsistent config for " + "nonpausable COS %d\n", i); + } + } + + if (p->pauseable) + DP(NETIF_MSG_LINK, "COS %d PAUSABLE prijoinmask 0x%x\n", + i, cos_data.data[i].pri_join_mask); + else + DP(NETIF_MSG_LINK, "COS %d NONPAUSABLE prijoinmask " + "0x%x\n", + i, cos_data.data[i].pri_join_mask); + } + + bp->dcbx_port_params.ets.num_of_cos = cos_data.num_of_cos ; +} + +static void bnx2x_dcbx_get_ets_pri_pg_tbl(struct bnx2x *bp, + u32 *set_configuration_ets_pg, + u32 *pri_pg_tbl) +{ + int i; + + for (i = 0; i < DCBX_MAX_NUM_PRI_PG_ENTRIES; i++) { + set_configuration_ets_pg[i] = DCBX_PRI_PG_GET(pri_pg_tbl, i); + + DP(NETIF_MSG_LINK, "set_configuration_ets_pg[%d] = 0x%x\n", + i, set_configuration_ets_pg[i]); + } +} + +static void bnx2x_dcbx_fw_struct(struct bnx2x *bp, + struct bnx2x_func_tx_start_params *pfc_fw_cfg) +{ + u16 pri_bit = 0; + u8 cos = 0, pri = 0; + struct priority_cos *tt2cos; + u32 *ttp = bp->dcbx_port_params.app.traffic_type_priority; + + memset(pfc_fw_cfg, 0, sizeof(*pfc_fw_cfg)); + + /* to disable DCB - the structure must be zeroed */ + if (bp->dcbx_error & DCBX_REMOTE_MIB_ERROR) + return; + + /*shortcut*/ + tt2cos = pfc_fw_cfg->traffic_type_to_priority_cos; + + /* Fw version should be incremented each update */ + pfc_fw_cfg->dcb_version = ++bp->dcb_version; + pfc_fw_cfg->dcb_enabled = 1; + + /* Fill priority parameters */ + for (pri = 0; pri < LLFC_DRIVER_TRAFFIC_TYPE_MAX; pri++) { + tt2cos[pri].priority = ttp[pri]; + pri_bit = 1 << tt2cos[pri].priority; + + /* Fill COS parameters based on COS calculated to + * make it more general for future use */ + for (cos = 0; cos < bp->dcbx_port_params.ets.num_of_cos; cos++) + if (bp->dcbx_port_params.ets.cos_params[cos]. + pri_bitmask & pri_bit) + tt2cos[pri].cos = cos; + } + + /* we never want the FW to add a 0 vlan tag */ + pfc_fw_cfg->dont_add_pri_0_en = 1; + + bnx2x_dcbx_print_cos_params(bp, pfc_fw_cfg); +} + +void bnx2x_dcbx_pmf_update(struct bnx2x *bp) +{ + /* if we need to syncronize DCBX result from prev PMF + * read it from shmem and update bp accordingly + */ + if (SHMEM2_HAS(bp, drv_flags) && + GET_FLAGS(SHMEM2_RD(bp, drv_flags), DRV_FLAGS_DCB_CONFIGURED)) { + /* Read neg results if dcbx is in the FW */ + if (bnx2x_dcbx_read_shmem_neg_results(bp)) + return; + + bnx2x_dump_dcbx_drv_param(bp, &bp->dcbx_local_feat, + bp->dcbx_error); + bnx2x_get_dcbx_drv_param(bp, &bp->dcbx_local_feat, + bp->dcbx_error); + } +} + +/* DCB netlink */ +#ifdef BCM_DCBNL + +#define BNX2X_DCBX_CAPS (DCB_CAP_DCBX_LLD_MANAGED | \ + DCB_CAP_DCBX_VER_CEE | DCB_CAP_DCBX_STATIC) + +static inline bool bnx2x_dcbnl_set_valid(struct bnx2x *bp) +{ + /* validate dcbnl call that may change HW state: + * DCB is on and DCBX mode was SUCCESSFULLY set by the user. + */ + return bp->dcb_state && bp->dcbx_mode_uset; +} + +static u8 bnx2x_dcbnl_get_state(struct net_device *netdev) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "state = %d\n", bp->dcb_state); + return bp->dcb_state; +} + +static u8 bnx2x_dcbnl_set_state(struct net_device *netdev, u8 state) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "state = %s\n", state ? "on" : "off"); + + bnx2x_dcbx_set_state(bp, (state ? true : false), bp->dcbx_enabled); + return 0; +} + +static void bnx2x_dcbnl_get_perm_hw_addr(struct net_device *netdev, + u8 *perm_addr) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "GET-PERM-ADDR\n"); + + /* first the HW mac address */ + memcpy(perm_addr, netdev->dev_addr, netdev->addr_len); + +#ifdef BCM_CNIC + /* second SAN address */ + memcpy(perm_addr+netdev->addr_len, bp->fip_mac, netdev->addr_len); +#endif +} + +static void bnx2x_dcbnl_set_pg_tccfg_tx(struct net_device *netdev, int prio, + u8 prio_type, u8 pgid, u8 bw_pct, + u8 up_map) +{ + struct bnx2x *bp = netdev_priv(netdev); + + DP(NETIF_MSG_LINK, "prio[%d] = %d\n", prio, pgid); + if (!bnx2x_dcbnl_set_valid(bp) || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES) + return; + + /** + * bw_pct ingnored - band-width percentage devision between user + * priorities within the same group is not + * standard and hence not supported + * + * prio_type igonred - priority levels within the same group are not + * standard and hence are not supported. According + * to the standard pgid 15 is dedicated to strict + * prioirty traffic (on the port level). + * + * up_map ignored + */ + + bp->dcbx_config_params.admin_configuration_ets_pg[prio] = pgid; + bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1; +} + +static void bnx2x_dcbnl_set_pg_bwgcfg_tx(struct net_device *netdev, + int pgid, u8 bw_pct) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "pgid[%d] = %d\n", pgid, bw_pct); + + if (!bnx2x_dcbnl_set_valid(bp) || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES) + return; + + bp->dcbx_config_params.admin_configuration_bw_precentage[pgid] = bw_pct; + bp->dcbx_config_params.admin_ets_configuration_tx_enable = 1; +} + +static void bnx2x_dcbnl_set_pg_tccfg_rx(struct net_device *netdev, int prio, + u8 prio_type, u8 pgid, u8 bw_pct, + u8 up_map) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "Nothing to set; No RX support\n"); +} + +static void bnx2x_dcbnl_set_pg_bwgcfg_rx(struct net_device *netdev, + int pgid, u8 bw_pct) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "Nothing to set; No RX support\n"); +} + +static void bnx2x_dcbnl_get_pg_tccfg_tx(struct net_device *netdev, int prio, + u8 *prio_type, u8 *pgid, u8 *bw_pct, + u8 *up_map) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "prio = %d\n", prio); + + /** + * bw_pct ingnored - band-width percentage devision between user + * priorities within the same group is not + * standard and hence not supported + * + * prio_type igonred - priority levels within the same group are not + * standard and hence are not supported. According + * to the standard pgid 15 is dedicated to strict + * prioirty traffic (on the port level). + * + * up_map ignored + */ + *up_map = *bw_pct = *prio_type = *pgid = 0; + + if (!bp->dcb_state || prio >= DCBX_MAX_NUM_PRI_PG_ENTRIES) + return; + + *pgid = DCBX_PRI_PG_GET(bp->dcbx_local_feat.ets.pri_pg_tbl, prio); +} + +static void bnx2x_dcbnl_get_pg_bwgcfg_tx(struct net_device *netdev, + int pgid, u8 *bw_pct) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "pgid = %d\n", pgid); + + *bw_pct = 0; + + if (!bp->dcb_state || pgid >= DCBX_MAX_NUM_PG_BW_ENTRIES) + return; + + *bw_pct = DCBX_PG_BW_GET(bp->dcbx_local_feat.ets.pg_bw_tbl, pgid); +} + +static void bnx2x_dcbnl_get_pg_tccfg_rx(struct net_device *netdev, int prio, + u8 *prio_type, u8 *pgid, u8 *bw_pct, + u8 *up_map) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "Nothing to get; No RX support\n"); + + *prio_type = *pgid = *bw_pct = *up_map = 0; +} + +static void bnx2x_dcbnl_get_pg_bwgcfg_rx(struct net_device *netdev, + int pgid, u8 *bw_pct) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "Nothing to get; No RX support\n"); + + *bw_pct = 0; +} + +static void bnx2x_dcbnl_set_pfc_cfg(struct net_device *netdev, int prio, + u8 setting) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "prio[%d] = %d\n", prio, setting); + + if (!bnx2x_dcbnl_set_valid(bp) || prio >= MAX_PFC_PRIORITIES) + return; + + bp->dcbx_config_params.admin_pfc_bitmap |= ((setting ? 1 : 0) << prio); + + if (setting) + bp->dcbx_config_params.admin_pfc_tx_enable = 1; +} + +static void bnx2x_dcbnl_get_pfc_cfg(struct net_device *netdev, int prio, + u8 *setting) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "prio = %d\n", prio); + + *setting = 0; + + if (!bp->dcb_state || prio >= MAX_PFC_PRIORITIES) + return; + + *setting = (bp->dcbx_local_feat.pfc.pri_en_bitmap >> prio) & 0x1; +} + +static u8 bnx2x_dcbnl_set_all(struct net_device *netdev) +{ + struct bnx2x *bp = netdev_priv(netdev); + int rc = 0; + + DP(NETIF_MSG_LINK, "SET-ALL\n"); + + if (!bnx2x_dcbnl_set_valid(bp)) + return 1; + + if (bp->recovery_state != BNX2X_RECOVERY_DONE) { + netdev_err(bp->dev, "Handling parity error recovery. " + "Try again later\n"); + return 1; + } + if (netif_running(bp->dev)) { + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + rc = bnx2x_nic_load(bp, LOAD_NORMAL); + } + DP(NETIF_MSG_LINK, "set_dcbx_params done (%d)\n", rc); + if (rc) + return 1; + + return 0; +} + +static u8 bnx2x_dcbnl_get_cap(struct net_device *netdev, int capid, u8 *cap) +{ + struct bnx2x *bp = netdev_priv(netdev); + u8 rval = 0; + + if (bp->dcb_state) { + switch (capid) { + case DCB_CAP_ATTR_PG: + *cap = true; + break; + case DCB_CAP_ATTR_PFC: + *cap = true; + break; + case DCB_CAP_ATTR_UP2TC: + *cap = false; + break; + case DCB_CAP_ATTR_PG_TCS: + *cap = 0x80; /* 8 priorities for PGs */ + break; + case DCB_CAP_ATTR_PFC_TCS: + *cap = 0x80; /* 8 priorities for PFC */ + break; + case DCB_CAP_ATTR_GSP: + *cap = true; + break; + case DCB_CAP_ATTR_BCN: + *cap = false; + break; + case DCB_CAP_ATTR_DCBX: + *cap = BNX2X_DCBX_CAPS; + default: + rval = -EINVAL; + break; + } + } else + rval = -EINVAL; + + DP(NETIF_MSG_LINK, "capid %d:%x\n", capid, *cap); + return rval; +} + +static u8 bnx2x_dcbnl_get_numtcs(struct net_device *netdev, int tcid, u8 *num) +{ + struct bnx2x *bp = netdev_priv(netdev); + u8 rval = 0; + + DP(NETIF_MSG_LINK, "tcid %d\n", tcid); + + if (bp->dcb_state) { + switch (tcid) { + case DCB_NUMTCS_ATTR_PG: + *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 : + DCBX_COS_MAX_NUM_E2; + break; + case DCB_NUMTCS_ATTR_PFC: + *num = CHIP_IS_E3B0(bp) ? DCBX_COS_MAX_NUM_E3B0 : + DCBX_COS_MAX_NUM_E2; + break; + default: + rval = -EINVAL; + break; + } + } else + rval = -EINVAL; + + return rval; +} + +static u8 bnx2x_dcbnl_set_numtcs(struct net_device *netdev, int tcid, u8 num) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "num tcs = %d; Not supported\n", num); + return -EINVAL; +} + +static u8 bnx2x_dcbnl_get_pfc_state(struct net_device *netdev) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "state = %d\n", bp->dcbx_local_feat.pfc.enabled); + + if (!bp->dcb_state) + return 0; + + return bp->dcbx_local_feat.pfc.enabled; +} + +static void bnx2x_dcbnl_set_pfc_state(struct net_device *netdev, u8 state) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "state = %s\n", state ? "on" : "off"); + + if (!bnx2x_dcbnl_set_valid(bp)) + return; + + bp->dcbx_config_params.admin_pfc_tx_enable = + bp->dcbx_config_params.admin_pfc_enable = (state ? 1 : 0); +} + +static void bnx2x_admin_app_set_ent( + struct bnx2x_admin_priority_app_table *app_ent, + u8 idtype, u16 idval, u8 up) +{ + app_ent->valid = 1; + + switch (idtype) { + case DCB_APP_IDTYPE_ETHTYPE: + app_ent->traffic_type = TRAFFIC_TYPE_ETH; + break; + case DCB_APP_IDTYPE_PORTNUM: + app_ent->traffic_type = TRAFFIC_TYPE_PORT; + break; + default: + break; /* never gets here */ + } + app_ent->app_id = idval; + app_ent->priority = up; +} + +static bool bnx2x_admin_app_is_equal( + struct bnx2x_admin_priority_app_table *app_ent, + u8 idtype, u16 idval) +{ + if (!app_ent->valid) + return false; + + switch (idtype) { + case DCB_APP_IDTYPE_ETHTYPE: + if (app_ent->traffic_type != TRAFFIC_TYPE_ETH) + return false; + break; + case DCB_APP_IDTYPE_PORTNUM: + if (app_ent->traffic_type != TRAFFIC_TYPE_PORT) + return false; + break; + default: + return false; + } + if (app_ent->app_id != idval) + return false; + + return true; +} + +static int bnx2x_set_admin_app_up(struct bnx2x *bp, u8 idtype, u16 idval, u8 up) +{ + int i, ff; + + /* iterate over the app entries looking for idtype and idval */ + for (i = 0, ff = -1; i < 4; i++) { + struct bnx2x_admin_priority_app_table *app_ent = + &bp->dcbx_config_params.admin_priority_app_table[i]; + if (bnx2x_admin_app_is_equal(app_ent, idtype, idval)) + break; + + if (ff < 0 && !app_ent->valid) + ff = i; + } + if (i < 4) + /* if found overwrite up */ + bp->dcbx_config_params. + admin_priority_app_table[i].priority = up; + else if (ff >= 0) + /* not found use first-free */ + bnx2x_admin_app_set_ent( + &bp->dcbx_config_params.admin_priority_app_table[ff], + idtype, idval, up); + else + /* app table is full */ + return -EBUSY; + + /* up configured, if not 0 make sure feature is enabled */ + if (up) + bp->dcbx_config_params.admin_application_priority_tx_enable = 1; + + return 0; +} + +static u8 bnx2x_dcbnl_set_app_up(struct net_device *netdev, u8 idtype, + u16 idval, u8 up) +{ + struct bnx2x *bp = netdev_priv(netdev); + + DP(NETIF_MSG_LINK, "app_type %d, app_id %x, prio bitmap %d\n", + idtype, idval, up); + + if (!bnx2x_dcbnl_set_valid(bp)) + return -EINVAL; + + /* verify idtype */ + switch (idtype) { + case DCB_APP_IDTYPE_ETHTYPE: + case DCB_APP_IDTYPE_PORTNUM: + break; + default: + return -EINVAL; + } + return bnx2x_set_admin_app_up(bp, idtype, idval, up); +} + +static u8 bnx2x_dcbnl_get_dcbx(struct net_device *netdev) +{ + struct bnx2x *bp = netdev_priv(netdev); + u8 state; + + state = DCB_CAP_DCBX_LLD_MANAGED | DCB_CAP_DCBX_VER_CEE; + + if (bp->dcbx_enabled == BNX2X_DCBX_ENABLED_ON_NEG_OFF) + state |= DCB_CAP_DCBX_STATIC; + + return state; +} + +static u8 bnx2x_dcbnl_set_dcbx(struct net_device *netdev, u8 state) +{ + struct bnx2x *bp = netdev_priv(netdev); + DP(NETIF_MSG_LINK, "state = %02x\n", state); + + /* set dcbx mode */ + + if ((state & BNX2X_DCBX_CAPS) != state) { + BNX2X_ERR("Requested DCBX mode %x is beyond advertised " + "capabilities\n", state); + return 1; + } + + if (bp->dcb_state != BNX2X_DCB_STATE_ON) { + BNX2X_ERR("DCB turned off, DCBX configuration is invalid\n"); + return 1; + } + + if (state & DCB_CAP_DCBX_STATIC) + bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_OFF; + else + bp->dcbx_enabled = BNX2X_DCBX_ENABLED_ON_NEG_ON; + + bp->dcbx_mode_uset = true; + return 0; +} + +static u8 bnx2x_dcbnl_get_featcfg(struct net_device *netdev, int featid, + u8 *flags) +{ + struct bnx2x *bp = netdev_priv(netdev); + u8 rval = 0; + + DP(NETIF_MSG_LINK, "featid %d\n", featid); + + if (bp->dcb_state) { + *flags = 0; + switch (featid) { + case DCB_FEATCFG_ATTR_PG: + if (bp->dcbx_local_feat.ets.enabled) + *flags |= DCB_FEATCFG_ENABLE; + if (bp->dcbx_error & DCBX_LOCAL_ETS_ERROR) + *flags |= DCB_FEATCFG_ERROR; + break; + case DCB_FEATCFG_ATTR_PFC: + if (bp->dcbx_local_feat.pfc.enabled) + *flags |= DCB_FEATCFG_ENABLE; + if (bp->dcbx_error & (DCBX_LOCAL_PFC_ERROR | + DCBX_LOCAL_PFC_MISMATCH)) + *flags |= DCB_FEATCFG_ERROR; + break; + case DCB_FEATCFG_ATTR_APP: + if (bp->dcbx_local_feat.app.enabled) + *flags |= DCB_FEATCFG_ENABLE; + if (bp->dcbx_error & (DCBX_LOCAL_APP_ERROR | + DCBX_LOCAL_APP_MISMATCH)) + *flags |= DCB_FEATCFG_ERROR; + break; + default: + rval = -EINVAL; + break; + } + } else + rval = -EINVAL; + + return rval; +} + +static u8 bnx2x_dcbnl_set_featcfg(struct net_device *netdev, int featid, + u8 flags) +{ + struct bnx2x *bp = netdev_priv(netdev); + u8 rval = 0; + + DP(NETIF_MSG_LINK, "featid = %d flags = %02x\n", featid, flags); + + /* ignore the 'advertise' flag */ + if (bnx2x_dcbnl_set_valid(bp)) { + switch (featid) { + case DCB_FEATCFG_ATTR_PG: + bp->dcbx_config_params.admin_ets_enable = + flags & DCB_FEATCFG_ENABLE ? 1 : 0; + bp->dcbx_config_params.admin_ets_willing = + flags & DCB_FEATCFG_WILLING ? 1 : 0; + break; + case DCB_FEATCFG_ATTR_PFC: + bp->dcbx_config_params.admin_pfc_enable = + flags & DCB_FEATCFG_ENABLE ? 1 : 0; + bp->dcbx_config_params.admin_pfc_willing = + flags & DCB_FEATCFG_WILLING ? 1 : 0; + break; + case DCB_FEATCFG_ATTR_APP: + /* ignore enable, always enabled */ + bp->dcbx_config_params.admin_app_priority_willing = + flags & DCB_FEATCFG_WILLING ? 1 : 0; + break; + default: + rval = -EINVAL; + break; + } + } else + rval = -EINVAL; + + return rval; +} + +static int bnx2x_peer_appinfo(struct net_device *netdev, + struct dcb_peer_app_info *info, u16* app_count) +{ + int i; + struct bnx2x *bp = netdev_priv(netdev); + + DP(NETIF_MSG_LINK, "APP-INFO\n"); + + info->willing = (bp->dcbx_remote_flags & DCBX_APP_REM_WILLING) ?: 0; + info->error = (bp->dcbx_remote_flags & DCBX_APP_RX_ERROR) ?: 0; + *app_count = 0; + + for (i = 0; i < DCBX_MAX_APP_PROTOCOL; i++) + if (bp->dcbx_remote_feat.app.app_pri_tbl[i].appBitfield & + DCBX_APP_ENTRY_VALID) + (*app_count)++; + return 0; +} + +static int bnx2x_peer_apptable(struct net_device *netdev, + struct dcb_app *table) +{ + int i, j; + struct bnx2x *bp = netdev_priv(netdev); + + DP(NETIF_MSG_LINK, "APP-TABLE\n"); + + for (i = 0, j = 0; i < DCBX_MAX_APP_PROTOCOL; i++) { + struct dcbx_app_priority_entry *ent = + &bp->dcbx_remote_feat.app.app_pri_tbl[i]; + + if (ent->appBitfield & DCBX_APP_ENTRY_VALID) { + table[j].selector = bnx2x_dcbx_dcbnl_app_idtype(ent); + table[j].priority = bnx2x_dcbx_dcbnl_app_up(ent); + table[j++].protocol = ent->app_id; + } + } + return 0; +} + +static int bnx2x_cee_peer_getpg(struct net_device *netdev, struct cee_pg *pg) +{ + int i; + struct bnx2x *bp = netdev_priv(netdev); + + pg->willing = (bp->dcbx_remote_flags & DCBX_ETS_REM_WILLING) ?: 0; + + for (i = 0; i < CEE_DCBX_MAX_PGS; i++) { + pg->pg_bw[i] = + DCBX_PG_BW_GET(bp->dcbx_remote_feat.ets.pg_bw_tbl, i); + pg->prio_pg[i] = + DCBX_PRI_PG_GET(bp->dcbx_remote_feat.ets.pri_pg_tbl, i); + } + return 0; +} + +static int bnx2x_cee_peer_getpfc(struct net_device *netdev, + struct cee_pfc *pfc) +{ + struct bnx2x *bp = netdev_priv(netdev); + pfc->tcs_supported = bp->dcbx_remote_feat.pfc.pfc_caps; + pfc->pfc_en = bp->dcbx_remote_feat.pfc.pri_en_bitmap; + return 0; +} + +const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops = { + .getstate = bnx2x_dcbnl_get_state, + .setstate = bnx2x_dcbnl_set_state, + .getpermhwaddr = bnx2x_dcbnl_get_perm_hw_addr, + .setpgtccfgtx = bnx2x_dcbnl_set_pg_tccfg_tx, + .setpgbwgcfgtx = bnx2x_dcbnl_set_pg_bwgcfg_tx, + .setpgtccfgrx = bnx2x_dcbnl_set_pg_tccfg_rx, + .setpgbwgcfgrx = bnx2x_dcbnl_set_pg_bwgcfg_rx, + .getpgtccfgtx = bnx2x_dcbnl_get_pg_tccfg_tx, + .getpgbwgcfgtx = bnx2x_dcbnl_get_pg_bwgcfg_tx, + .getpgtccfgrx = bnx2x_dcbnl_get_pg_tccfg_rx, + .getpgbwgcfgrx = bnx2x_dcbnl_get_pg_bwgcfg_rx, + .setpfccfg = bnx2x_dcbnl_set_pfc_cfg, + .getpfccfg = bnx2x_dcbnl_get_pfc_cfg, + .setall = bnx2x_dcbnl_set_all, + .getcap = bnx2x_dcbnl_get_cap, + .getnumtcs = bnx2x_dcbnl_get_numtcs, + .setnumtcs = bnx2x_dcbnl_set_numtcs, + .getpfcstate = bnx2x_dcbnl_get_pfc_state, + .setpfcstate = bnx2x_dcbnl_set_pfc_state, + .setapp = bnx2x_dcbnl_set_app_up, + .getdcbx = bnx2x_dcbnl_get_dcbx, + .setdcbx = bnx2x_dcbnl_set_dcbx, + .getfeatcfg = bnx2x_dcbnl_get_featcfg, + .setfeatcfg = bnx2x_dcbnl_set_featcfg, + .peer_getappinfo = bnx2x_peer_appinfo, + .peer_getapptable = bnx2x_peer_apptable, + .cee_peer_getpg = bnx2x_cee_peer_getpg, + .cee_peer_getpfc = bnx2x_cee_peer_getpfc, +}; + +#endif /* BCM_DCBNL */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h new file mode 100644 index 000000000000..2c6a3bca6f28 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h @@ -0,0 +1,203 @@ +/* bnx2x_dcb.h: Broadcom Everest network driver. + * + * Copyright 2009-2011 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + * + * Maintained by: Eilon Greenstein + * Written by: Dmitry Kravkov + * + */ +#ifndef BNX2X_DCB_H +#define BNX2X_DCB_H + +#include "bnx2x_hsi.h" + +#define LLFC_DRIVER_TRAFFIC_TYPE_MAX 3 /* NW, iSCSI, FCoE */ +struct bnx2x_dcbx_app_params { + u32 enabled; + u32 traffic_type_priority[LLFC_DRIVER_TRAFFIC_TYPE_MAX]; +}; + +#define DCBX_COS_MAX_NUM_E2 DCBX_E2E3_MAX_NUM_COS +/* bnx2x currently limits numbers of supported COSes to 3 to be extended to 6 */ +#define BNX2X_MAX_COS_SUPPORT 3 +#define DCBX_COS_MAX_NUM_E3B0 BNX2X_MAX_COS_SUPPORT +#define DCBX_COS_MAX_NUM BNX2X_MAX_COS_SUPPORT + +struct bnx2x_dcbx_cos_params { + u32 bw_tbl; + u32 pri_bitmask; + /* + * strict priority: valid values are 0..5; 0 is highest priority. + * There can't be two COSes with the same priority. + */ + u8 strict; +#define BNX2X_DCBX_STRICT_INVALID DCBX_COS_MAX_NUM +#define BNX2X_DCBX_STRICT_COS_HIGHEST 0 +#define BNX2X_DCBX_STRICT_COS_NEXT_LOWER_PRI(sp) ((sp) + 1) + u8 pauseable; +}; + +struct bnx2x_dcbx_pg_params { + u32 enabled; + u8 num_of_cos; /* valid COS entries */ + struct bnx2x_dcbx_cos_params cos_params[DCBX_COS_MAX_NUM]; +}; + +struct bnx2x_dcbx_pfc_params { + u32 enabled; + u32 priority_non_pauseable_mask; +}; + +struct bnx2x_dcbx_port_params { + struct bnx2x_dcbx_pfc_params pfc; + struct bnx2x_dcbx_pg_params ets; + struct bnx2x_dcbx_app_params app; +}; + +#define BNX2X_DCBX_CONFIG_INV_VALUE (0xFFFFFFFF) +#define BNX2X_DCBX_OVERWRITE_SETTINGS_DISABLE 0 +#define BNX2X_DCBX_OVERWRITE_SETTINGS_ENABLE 1 +#define BNX2X_DCBX_OVERWRITE_SETTINGS_INVALID (BNX2X_DCBX_CONFIG_INV_VALUE) +#define BNX2X_IS_ETS_ENABLED(bp) ((bp)->dcb_state == BNX2X_DCB_STATE_ON &&\ + (bp)->dcbx_port_params.ets.enabled) + +struct bnx2x_config_lldp_params { + u32 overwrite_settings; + u32 msg_tx_hold; + u32 msg_fast_tx; + u32 tx_credit_max; + u32 msg_tx_interval; + u32 tx_fast; +}; + +struct bnx2x_admin_priority_app_table { + u32 valid; + u32 priority; +#define INVALID_TRAFFIC_TYPE_PRIORITY (0xFFFFFFFF) + u32 traffic_type; +#define TRAFFIC_TYPE_ETH 0 +#define TRAFFIC_TYPE_PORT 1 + u32 app_id; +}; + +struct bnx2x_config_dcbx_params { + u32 overwrite_settings; + u32 admin_dcbx_version; + u32 admin_ets_enable; + u32 admin_pfc_enable; + u32 admin_tc_supported_tx_enable; + u32 admin_ets_configuration_tx_enable; + u32 admin_ets_recommendation_tx_enable; + u32 admin_pfc_tx_enable; + u32 admin_application_priority_tx_enable; + u32 admin_ets_willing; + u32 admin_ets_reco_valid; + u32 admin_pfc_willing; + u32 admin_app_priority_willing; + u32 admin_configuration_bw_precentage[8]; + u32 admin_configuration_ets_pg[8]; + u32 admin_recommendation_bw_precentage[8]; + u32 admin_recommendation_ets_pg[8]; + u32 admin_pfc_bitmap; + struct bnx2x_admin_priority_app_table admin_priority_app_table[4]; + u32 admin_default_priority; +}; + +#define GET_FLAGS(flags, bits) ((flags) & (bits)) +#define SET_FLAGS(flags, bits) ((flags) |= (bits)) +#define RESET_FLAGS(flags, bits) ((flags) &= ~(bits)) + +enum { + DCBX_READ_LOCAL_MIB, + DCBX_READ_REMOTE_MIB +}; + +#define ETH_TYPE_FCOE (0x8906) +#define TCP_PORT_ISCSI (0xCBC) + +#define PFC_VALUE_FRAME_SIZE (512) +#define PFC_QUANTA_IN_NANOSEC_FROM_SPEED_MEGA(mega_speed) \ + ((1000 * PFC_VALUE_FRAME_SIZE)/(mega_speed)) + +#define PFC_BRB1_REG_HIGH_LLFC_LOW_THRESHOLD 130 +#define PFC_BRB1_REG_HIGH_LLFC_HIGH_THRESHOLD 170 + + + +struct cos_entry_help_data { + u32 pri_join_mask; + u32 cos_bw; + u8 strict; + bool pausable; +}; + +struct cos_help_data { + struct cos_entry_help_data data[DCBX_COS_MAX_NUM]; + u8 num_of_cos; +}; + +#define DCBX_ILLEGAL_PG (0xFF) +#define DCBX_PFC_PRI_MASK (0xFF) +#define DCBX_STRICT_PRIORITY (15) +#define DCBX_INVALID_COS_BW (0xFFFFFFFF) +#define DCBX_PFC_PRI_NON_PAUSE_MASK(bp) \ + ((bp)->dcbx_port_params.pfc.priority_non_pauseable_mask) +#define DCBX_PFC_PRI_PAUSE_MASK(bp) \ + ((u8)~DCBX_PFC_PRI_NON_PAUSE_MASK(bp)) +#define DCBX_PFC_PRI_GET_PAUSE(bp, pg_pri) \ + ((pg_pri) & (DCBX_PFC_PRI_PAUSE_MASK(bp))) +#define DCBX_PFC_PRI_GET_NON_PAUSE(bp, pg_pri) \ + (DCBX_PFC_PRI_NON_PAUSE_MASK(bp) & (pg_pri)) +#define DCBX_IS_PFC_PRI_SOME_PAUSE(bp, pg_pri) \ + (0 != DCBX_PFC_PRI_GET_PAUSE(bp, pg_pri)) +#define IS_DCBX_PFC_PRI_ONLY_PAUSE(bp, pg_pri) \ + (pg_pri == DCBX_PFC_PRI_GET_PAUSE((bp), (pg_pri))) +#define IS_DCBX_PFC_PRI_ONLY_NON_PAUSE(bp, pg_pri)\ + ((pg_pri) == DCBX_PFC_PRI_GET_NON_PAUSE((bp), (pg_pri))) +#define IS_DCBX_PFC_PRI_MIX_PAUSE(bp, pg_pri) \ + (!(IS_DCBX_PFC_PRI_ONLY_NON_PAUSE((bp), (pg_pri)) || \ + IS_DCBX_PFC_PRI_ONLY_PAUSE((bp), (pg_pri)))) + + +struct pg_entry_help_data { + u8 num_of_dif_pri; + u8 pg; + u32 pg_priority; +}; + +struct pg_help_data { + struct pg_entry_help_data data[LLFC_DRIVER_TRAFFIC_TYPE_MAX]; + u8 num_of_pg; +}; + +/* forward DCB/PFC related declarations */ +struct bnx2x; +void bnx2x_dcbx_update(struct work_struct *work); +void bnx2x_dcbx_init_params(struct bnx2x *bp); +void bnx2x_dcbx_set_state(struct bnx2x *bp, bool dcb_on, u32 dcbx_enabled); + +enum { + BNX2X_DCBX_STATE_NEG_RECEIVED = 0x1, + BNX2X_DCBX_STATE_TX_PAUSED, + BNX2X_DCBX_STATE_TX_RELEASED +}; + +void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state); +void bnx2x_dcbx_pmf_update(struct bnx2x *bp); +/* DCB netlink */ +#ifdef BCM_DCBNL +extern const struct dcbnl_rtnl_ops bnx2x_dcbnl_ops; +int bnx2x_dcbnl_update_applist(struct bnx2x *bp, bool delall); +#endif /* BCM_DCBNL */ + +#endif /* BNX2X_DCB_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h new file mode 100644 index 000000000000..b983825d0ee9 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h @@ -0,0 +1,1156 @@ +/* bnx2x_dump.h: Broadcom Everest network driver. + * + * Copyright (c) 2011 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + */ + + +/* This struct holds a signature to ensure the dump returned from the driver + * match the meta data file inserted to grc_dump.tcl + * The signature is time stamp, diag version and grc_dump version + */ + +#ifndef BNX2X_DUMP_H +#define BNX2X_DUMP_H + + + +/*definitions */ +#define XSTORM_WAITP_ADDR 0x2b8a80 +#define TSTORM_WAITP_ADDR 0x1b8a80 +#define USTORM_WAITP_ADDR 0x338a80 +#define CSTORM_WAITP_ADDR 0x238a80 +#define TSTORM_CAM_MODE 0x1B1440 + +#define MAX_TIMER_PENDING 200 +#define TIMER_SCAN_DONT_CARE 0xFF +#define RI_E1 0x1 +#define RI_E1H 0x2 +#define RI_E2 0x4 +#define RI_E3 0x8 +#define RI_E3B0 0x10 +#define RI_ONLINE 0x100 +#define RI_OFFLINE 0x0 +#define RI_PATH0_DUMP 0x200 +#define RI_PATH1_DUMP 0x400 + +#define RI_E1_ONLINE (RI_E1 | RI_ONLINE) +#define RI_E1H_ONLINE (RI_E1H | RI_ONLINE) +#define RI_E1E1H_ONLINE (RI_E1 | RI_E1H | RI_ONLINE) +#define RI_E2_ONLINE (RI_E2 | RI_ONLINE) +#define RI_E1E2_ONLINE (RI_E1 | RI_E2 | RI_ONLINE) +#define RI_E1HE2_ONLINE (RI_E1H | RI_E2 | RI_ONLINE) +#define RI_E1E1HE2_ONLINE (RI_E1 | RI_E1H | RI_E2 | RI_ONLINE) +#define RI_E3_ONLINE (RI_E3 | RI_ONLINE) +#define RI_E1E3_ONLINE (RI_E1 | RI_E3 | RI_ONLINE) +#define RI_E1HE3_ONLINE (RI_E1H | RI_E3 | RI_ONLINE) +#define RI_E1E1HE3_ONLINE (RI_E1 | RI_E1H | RI_E3 | RI_ONLINE) +#define RI_E2E3_ONLINE (RI_E2 | RI_E3 | RI_ONLINE) +#define RI_E1E2E3_ONLINE (RI_E1 | RI_E2 | RI_E3 | RI_ONLINE) +#define RI_E1HE2E3_ONLINE (RI_E1H | RI_E2 | RI_E3 | RI_ONLINE) +#define RI_E1E1HE2E3_ONLINE (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_ONLINE) +#define RI_E3B0_ONLINE (RI_E3B0 | RI_ONLINE) +#define RI_E1E3B0_ONLINE (RI_E1 | RI_E3B0 | RI_ONLINE) +#define RI_E1HE3B0_ONLINE (RI_E1H | RI_E3B0 | RI_ONLINE) +#define RI_E1E1HE3B0_ONLINE (RI_E1 | RI_E1H | RI_E3B0 | RI_ONLINE) +#define RI_E2E3B0_ONLINE (RI_E2 | RI_E3B0 | RI_ONLINE) +#define RI_E1E2E3B0_ONLINE (RI_E1 | RI_E2 | RI_E3B0 | RI_ONLINE) +#define RI_E1HE2E3B0_ONLINE (RI_E1H | RI_E2 | RI_E3B0 | RI_ONLINE) +#define RI_E1E1HE2E3B0_ONLINE (RI_E1 | RI_E1H | RI_E2 | RI_E3B0 | RI_ONLINE) +#define RI_E3E3B0_ONLINE (RI_E3 | RI_E3B0 | RI_ONLINE) +#define RI_E1E3E3B0_ONLINE (RI_E1 | RI_E3 | RI_E3B0 | RI_ONLINE) +#define RI_E1HE3E3B0_ONLINE (RI_E1H | RI_E3 | RI_E3B0 | RI_ONLINE) +#define RI_E1E1HE3E3B0_ONLINE (RI_E1 | RI_E1H | RI_E3 | RI_E3B0 | RI_ONLINE) +#define RI_E2E3E3B0_ONLINE (RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE) +#define RI_E1E2E3E3B0_ONLINE (RI_E1 | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE) +#define RI_E1HE2E3E3B0_ONLINE (RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE) +#define RI_E1E1HE2E3E3B0_ONLINE \ + (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_ONLINE) +#define RI_E1_OFFLINE (RI_E1 | RI_OFFLINE) +#define RI_E1H_OFFLINE (RI_E1H | RI_OFFLINE) +#define RI_E1E1H_OFFLINE (RI_E1 | RI_E1H | RI_OFFLINE) +#define RI_E2_OFFLINE (RI_E2 | RI_OFFLINE) +#define RI_E1E2_OFFLINE (RI_E1 | RI_E2 | RI_OFFLINE) +#define RI_E1HE2_OFFLINE (RI_E1H | RI_E2 | RI_OFFLINE) +#define RI_E1E1HE2_OFFLINE (RI_E1 | RI_E1H | RI_E2 | RI_OFFLINE) +#define RI_E3_OFFLINE (RI_E3 | RI_OFFLINE) +#define RI_E1E3_OFFLINE (RI_E1 | RI_E3 | RI_OFFLINE) +#define RI_E1HE3_OFFLINE (RI_E1H | RI_E3 | RI_OFFLINE) +#define RI_E1E1HE3_OFFLINE (RI_E1 | RI_E1H | RI_E3 | RI_OFFLINE) +#define RI_E2E3_OFFLINE (RI_E2 | RI_E3 | RI_OFFLINE) +#define RI_E1E2E3_OFFLINE (RI_E1 | RI_E2 | RI_E3 | RI_OFFLINE) +#define RI_E1HE2E3_OFFLINE (RI_E1H | RI_E2 | RI_E3 | RI_OFFLINE) +#define RI_E1E1HE2E3_OFFLINE (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_OFFLINE) +#define RI_E3B0_OFFLINE (RI_E3B0 | RI_OFFLINE) +#define RI_E1E3B0_OFFLINE (RI_E1 | RI_E3B0 | RI_OFFLINE) +#define RI_E1HE3B0_OFFLINE (RI_E1H | RI_E3B0 | RI_OFFLINE) +#define RI_E1E1HE3B0_OFFLINE (RI_E1 | RI_E1H | RI_E3B0 | RI_OFFLINE) +#define RI_E2E3B0_OFFLINE (RI_E2 | RI_E3B0 | RI_OFFLINE) +#define RI_E1E2E3B0_OFFLINE (RI_E1 | RI_E2 | RI_E3B0 | RI_OFFLINE) +#define RI_E1HE2E3B0_OFFLINE (RI_E1H | RI_E2 | RI_E3B0 | RI_OFFLINE) +#define RI_E1E1HE2E3B0_OFFLINE (RI_E1 | RI_E1H | RI_E2 | RI_E3B0 | RI_OFFLINE) +#define RI_E3E3B0_OFFLINE (RI_E3 | RI_E3B0 | RI_OFFLINE) +#define RI_E1E3E3B0_OFFLINE (RI_E1 | RI_E3 | RI_E3B0 | RI_OFFLINE) +#define RI_E1HE3E3B0_OFFLINE (RI_E1H | RI_E3 | RI_E3B0 | RI_OFFLINE) +#define RI_E1E1HE3E3B0_OFFLINE (RI_E1 | RI_E1H | RI_E3 | RI_E3B0 | RI_OFFLINE) +#define RI_E2E3E3B0_OFFLINE (RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE) +#define RI_E1E2E3E3B0_OFFLINE (RI_E1 | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE) +#define RI_E1HE2E3E3B0_OFFLINE (RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE) +#define RI_E1E1HE2E3E3B0_OFFLINE \ + (RI_E1 | RI_E1H | RI_E2 | RI_E3 | RI_E3B0 | RI_OFFLINE) +#define RI_ALL_ONLINE RI_E1E1HE2E3E3B0_ONLINE +#define RI_ALL_OFFLINE RI_E1E1HE2E3E3B0_OFFLINE + +#define DBG_DMP_TRACE_BUFFER_SIZE 0x800 +#define DBG_DMP_TRACE_BUFFER_OFFSET(shmem0_offset) \ + ((shmem0_offset) - DBG_DMP_TRACE_BUFFER_SIZE) + +struct dump_sign { + u32 time_stamp; + u32 diag_ver; + u32 grc_dump_ver; +}; + +struct dump_hdr { + u32 hdr_size; /* in dwords, excluding this field */ + struct dump_sign dump_sign; + u32 xstorm_waitp; + u32 tstorm_waitp; + u32 ustorm_waitp; + u32 cstorm_waitp; + u16 info; + u8 idle_chk; + u8 reserved; +}; + +struct reg_addr { + u32 addr; + u32 size; + u16 info; +}; + +struct wreg_addr { + u32 addr; + u32 size; + u32 read_regs_count; + const u32 *read_regs; + u16 info; +}; + +static const struct reg_addr reg_addrs[] = { + { 0x2000, 341, RI_ALL_ONLINE }, + { 0x2800, 103, RI_ALL_ONLINE }, + { 0x3000, 287, RI_ALL_ONLINE }, + { 0x3800, 331, RI_ALL_ONLINE }, + { 0x8800, 6, RI_ALL_ONLINE }, + { 0x8818, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x9000, 147, RI_E2E3E3B0_ONLINE }, + { 0x924c, 1, RI_E2_ONLINE }, + { 0x9250, 16, RI_E2E3E3B0_ONLINE }, + { 0x9400, 33, RI_E2E3E3B0_ONLINE }, + { 0x9484, 5, RI_E3E3B0_ONLINE }, + { 0xa000, 27, RI_ALL_ONLINE }, + { 0xa06c, 1, RI_E1E1H_ONLINE }, + { 0xa070, 71, RI_ALL_ONLINE }, + { 0xa18c, 4, RI_E1E1H_ONLINE }, + { 0xa19c, 62, RI_ALL_ONLINE }, + { 0xa294, 2, RI_E1E1H_ONLINE }, + { 0xa29c, 2, RI_ALL_ONLINE }, + { 0xa2a4, 2, RI_E1E1HE2_ONLINE }, + { 0xa2ac, 52, RI_ALL_ONLINE }, + { 0xa39c, 7, RI_E1HE2E3E3B0_ONLINE }, + { 0xa3b8, 2, RI_E3E3B0_ONLINE }, + { 0xa3c0, 3, RI_E1HE2E3E3B0_ONLINE }, + { 0xa3d0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0xa3d8, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0xa3e0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0xa3e8, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0xa3f0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0xa3f8, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0xa400, 40, RI_ALL_ONLINE }, + { 0xa4a0, 1, RI_E1E1HE2_ONLINE }, + { 0xa4a4, 2, RI_ALL_ONLINE }, + { 0xa4ac, 2, RI_E1E1H_ONLINE }, + { 0xa4b4, 1, RI_E1E1HE2_ONLINE }, + { 0xa4b8, 2, RI_E1E1H_ONLINE }, + { 0xa4c0, 3, RI_ALL_ONLINE }, + { 0xa4cc, 5, RI_E1E1H_ONLINE }, + { 0xa4e0, 3, RI_ALL_ONLINE }, + { 0xa4fc, 2, RI_ALL_ONLINE }, + { 0xa504, 1, RI_E1E1H_ONLINE }, + { 0xa508, 3, RI_ALL_ONLINE }, + { 0xa518, 1, RI_ALL_ONLINE }, + { 0xa520, 1, RI_ALL_ONLINE }, + { 0xa528, 1, RI_ALL_ONLINE }, + { 0xa530, 1, RI_ALL_ONLINE }, + { 0xa538, 1, RI_ALL_ONLINE }, + { 0xa540, 1, RI_ALL_ONLINE }, + { 0xa548, 1, RI_E1E1H_ONLINE }, + { 0xa550, 1, RI_E1E1H_ONLINE }, + { 0xa558, 1, RI_E1E1H_ONLINE }, + { 0xa560, 1, RI_E1E1H_ONLINE }, + { 0xa568, 1, RI_E1E1H_ONLINE }, + { 0xa570, 1, RI_ALL_ONLINE }, + { 0xa580, 1, RI_ALL_ONLINE }, + { 0xa590, 1, RI_ALL_ONLINE }, + { 0xa5a0, 1, RI_E1E1HE2_ONLINE }, + { 0xa5c0, 1, RI_ALL_ONLINE }, + { 0xa5e0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0xa5e8, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0xa5f0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0xa5f8, 1, RI_E1HE2_ONLINE }, + { 0xa5fc, 9, RI_E1HE2E3E3B0_ONLINE }, + { 0xa620, 6, RI_E2E3E3B0_ONLINE }, + { 0xa638, 20, RI_E2_ONLINE }, + { 0xa688, 42, RI_E2E3E3B0_ONLINE }, + { 0xa730, 1, RI_E2_ONLINE }, + { 0xa734, 2, RI_E2E3E3B0_ONLINE }, + { 0xa73c, 4, RI_E2_ONLINE }, + { 0xa74c, 5, RI_E2E3E3B0_ONLINE }, + { 0xa760, 5, RI_E2_ONLINE }, + { 0xa774, 7, RI_E2E3E3B0_ONLINE }, + { 0xa790, 15, RI_E2_ONLINE }, + { 0xa7cc, 4, RI_E2E3E3B0_ONLINE }, + { 0xa7e0, 6, RI_E3E3B0_ONLINE }, + { 0xa800, 18, RI_E2_ONLINE }, + { 0xa848, 33, RI_E2E3E3B0_ONLINE }, + { 0xa8cc, 2, RI_E3E3B0_ONLINE }, + { 0xa8d4, 4, RI_E2E3E3B0_ONLINE }, + { 0xa8e4, 1, RI_E3E3B0_ONLINE }, + { 0xa8e8, 1, RI_E2E3E3B0_ONLINE }, + { 0xa8f0, 1, RI_E2E3E3B0_ONLINE }, + { 0xa8f8, 30, RI_E3E3B0_ONLINE }, + { 0xa974, 73, RI_E3E3B0_ONLINE }, + { 0xac30, 1, RI_E3E3B0_ONLINE }, + { 0xac40, 1, RI_E3E3B0_ONLINE }, + { 0xac50, 1, RI_E3E3B0_ONLINE }, + { 0xac60, 1, RI_E3B0_ONLINE }, + { 0x10000, 9, RI_ALL_ONLINE }, + { 0x10024, 1, RI_E1E1HE2_ONLINE }, + { 0x10028, 5, RI_ALL_ONLINE }, + { 0x1003c, 6, RI_E1E1HE2_ONLINE }, + { 0x10054, 20, RI_ALL_ONLINE }, + { 0x100a4, 4, RI_E1E1HE2_ONLINE }, + { 0x100b4, 11, RI_ALL_ONLINE }, + { 0x100e0, 4, RI_E1E1HE2_ONLINE }, + { 0x100f0, 8, RI_ALL_ONLINE }, + { 0x10110, 6, RI_E1E1HE2_ONLINE }, + { 0x10128, 110, RI_ALL_ONLINE }, + { 0x102e0, 4, RI_E1E1HE2_ONLINE }, + { 0x102f0, 18, RI_ALL_ONLINE }, + { 0x10338, 20, RI_E1E1HE2_ONLINE }, + { 0x10388, 10, RI_ALL_ONLINE }, + { 0x10400, 6, RI_E1E1HE2_ONLINE }, + { 0x10418, 6, RI_ALL_ONLINE }, + { 0x10430, 10, RI_E1E1HE2_ONLINE }, + { 0x10458, 22, RI_ALL_ONLINE }, + { 0x104b0, 12, RI_E1E1HE2_ONLINE }, + { 0x104e0, 1, RI_ALL_ONLINE }, + { 0x104e8, 2, RI_ALL_ONLINE }, + { 0x104f4, 2, RI_ALL_ONLINE }, + { 0x10500, 146, RI_ALL_ONLINE }, + { 0x10750, 2, RI_E1E1HE2_ONLINE }, + { 0x10760, 2, RI_E1E1HE2_ONLINE }, + { 0x10770, 2, RI_E1E1HE2_ONLINE }, + { 0x10780, 2, RI_E1E1HE2_ONLINE }, + { 0x10790, 2, RI_ALL_ONLINE }, + { 0x107a0, 2, RI_E1E1HE2_ONLINE }, + { 0x107b0, 2, RI_E1E1HE2_ONLINE }, + { 0x107c0, 2, RI_E1E1HE2_ONLINE }, + { 0x107d0, 2, RI_E1E1HE2_ONLINE }, + { 0x107e0, 2, RI_ALL_ONLINE }, + { 0x10880, 2, RI_ALL_ONLINE }, + { 0x10900, 2, RI_ALL_ONLINE }, + { 0x16000, 1, RI_E1HE2_ONLINE }, + { 0x16004, 25, RI_E1HE2E3E3B0_ONLINE }, + { 0x16070, 8, RI_E1HE2E3E3B0_ONLINE }, + { 0x16090, 4, RI_E1HE2E3_ONLINE }, + { 0x160a0, 6, RI_E1HE2E3E3B0_ONLINE }, + { 0x160c0, 7, RI_E1HE2E3E3B0_ONLINE }, + { 0x160dc, 2, RI_E1HE2_ONLINE }, + { 0x160e4, 10, RI_E1HE2E3E3B0_ONLINE }, + { 0x1610c, 2, RI_E1HE2_ONLINE }, + { 0x16114, 6, RI_E1HE2E3E3B0_ONLINE }, + { 0x16140, 48, RI_E1HE2E3E3B0_ONLINE }, + { 0x16204, 5, RI_E1HE2E3E3B0_ONLINE }, + { 0x18000, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x18008, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x18010, 35, RI_E2E3E3B0_ONLINE }, + { 0x180a4, 2, RI_E2E3E3B0_ONLINE }, + { 0x180c0, 9, RI_E2E3E3B0_ONLINE }, + { 0x180e4, 1, RI_E2E3_ONLINE }, + { 0x180e8, 2, RI_E2E3E3B0_ONLINE }, + { 0x180f0, 1, RI_E2E3_ONLINE }, + { 0x180f4, 79, RI_E2E3E3B0_ONLINE }, + { 0x18230, 1, RI_E2E3_ONLINE }, + { 0x18234, 2, RI_E2E3E3B0_ONLINE }, + { 0x1823c, 1, RI_E2E3_ONLINE }, + { 0x18240, 13, RI_E2E3E3B0_ONLINE }, + { 0x18274, 1, RI_E2_ONLINE }, + { 0x18278, 81, RI_E2E3E3B0_ONLINE }, + { 0x18440, 63, RI_E2E3E3B0_ONLINE }, + { 0x18570, 42, RI_E3E3B0_ONLINE }, + { 0x18618, 25, RI_E3B0_ONLINE }, + { 0x18680, 44, RI_E3B0_ONLINE }, + { 0x18748, 12, RI_E3B0_ONLINE }, + { 0x18788, 1, RI_E3B0_ONLINE }, + { 0x1879c, 6, RI_E3B0_ONLINE }, + { 0x187c4, 51, RI_E3B0_ONLINE }, + { 0x18a00, 48, RI_E3B0_ONLINE }, + { 0x20000, 24, RI_ALL_ONLINE }, + { 0x20060, 8, RI_ALL_ONLINE }, + { 0x20080, 94, RI_ALL_ONLINE }, + { 0x201f8, 1, RI_E1E1H_ONLINE }, + { 0x201fc, 1, RI_ALL_ONLINE }, + { 0x20200, 1, RI_E1E1H_ONLINE }, + { 0x20204, 1, RI_ALL_ONLINE }, + { 0x20208, 1, RI_E1E1H_ONLINE }, + { 0x2020c, 39, RI_ALL_ONLINE }, + { 0x202c8, 1, RI_E2E3E3B0_ONLINE }, + { 0x202d8, 4, RI_E2E3E3B0_ONLINE }, + { 0x202f0, 1, RI_E3B0_ONLINE }, + { 0x20400, 2, RI_ALL_ONLINE }, + { 0x2040c, 8, RI_ALL_ONLINE }, + { 0x2042c, 18, RI_E1HE2E3E3B0_ONLINE }, + { 0x20480, 1, RI_ALL_ONLINE }, + { 0x20500, 1, RI_ALL_ONLINE }, + { 0x20600, 1, RI_ALL_ONLINE }, + { 0x28000, 1, RI_ALL_ONLINE }, + { 0x28004, 8191, RI_ALL_OFFLINE }, + { 0x30000, 1, RI_ALL_ONLINE }, + { 0x30004, 16383, RI_ALL_OFFLINE }, + { 0x40000, 98, RI_ALL_ONLINE }, + { 0x401a8, 8, RI_E1HE2E3E3B0_ONLINE }, + { 0x401c8, 1, RI_E1H_ONLINE }, + { 0x401cc, 2, RI_E1HE2E3E3B0_ONLINE }, + { 0x401d4, 2, RI_E2E3E3B0_ONLINE }, + { 0x40200, 4, RI_ALL_ONLINE }, + { 0x40220, 6, RI_E2E3E3B0_ONLINE }, + { 0x40238, 8, RI_E2E3_ONLINE }, + { 0x40258, 4, RI_E2E3E3B0_ONLINE }, + { 0x40268, 2, RI_E3E3B0_ONLINE }, + { 0x40270, 17, RI_E3B0_ONLINE }, + { 0x40400, 43, RI_ALL_ONLINE }, + { 0x404cc, 3, RI_E1HE2E3E3B0_ONLINE }, + { 0x404e0, 1, RI_E2E3E3B0_ONLINE }, + { 0x40500, 2, RI_ALL_ONLINE }, + { 0x40510, 2, RI_ALL_ONLINE }, + { 0x40520, 2, RI_ALL_ONLINE }, + { 0x40530, 2, RI_ALL_ONLINE }, + { 0x40540, 2, RI_ALL_ONLINE }, + { 0x40550, 10, RI_E2E3E3B0_ONLINE }, + { 0x40610, 2, RI_E2E3E3B0_ONLINE }, + { 0x42000, 164, RI_ALL_ONLINE }, + { 0x422c0, 4, RI_E2E3E3B0_ONLINE }, + { 0x422d4, 5, RI_E1HE2E3E3B0_ONLINE }, + { 0x422e8, 1, RI_E2E3E3B0_ONLINE }, + { 0x42400, 49, RI_ALL_ONLINE }, + { 0x424c8, 38, RI_ALL_ONLINE }, + { 0x42568, 2, RI_ALL_ONLINE }, + { 0x42640, 5, RI_E2E3E3B0_ONLINE }, + { 0x42800, 1, RI_ALL_ONLINE }, + { 0x50000, 1, RI_ALL_ONLINE }, + { 0x50004, 19, RI_ALL_ONLINE }, + { 0x50050, 8, RI_ALL_ONLINE }, + { 0x50070, 88, RI_ALL_ONLINE }, + { 0x501f0, 4, RI_E1HE2E3E3B0_ONLINE }, + { 0x50200, 2, RI_ALL_ONLINE }, + { 0x5020c, 7, RI_ALL_ONLINE }, + { 0x50228, 6, RI_E1HE2E3E3B0_ONLINE }, + { 0x50240, 1, RI_ALL_ONLINE }, + { 0x50280, 1, RI_ALL_ONLINE }, + { 0x50300, 1, RI_E2E3E3B0_ONLINE }, + { 0x5030c, 1, RI_E2E3E3B0_ONLINE }, + { 0x50318, 1, RI_E2E3E3B0_ONLINE }, + { 0x5031c, 1, RI_E2E3E3B0_ONLINE }, + { 0x50320, 2, RI_E2E3E3B0_ONLINE }, + { 0x50330, 1, RI_E3B0_ONLINE }, + { 0x52000, 1, RI_ALL_ONLINE }, + { 0x54000, 1, RI_ALL_ONLINE }, + { 0x54004, 3327, RI_ALL_OFFLINE }, + { 0x58000, 1, RI_ALL_ONLINE }, + { 0x58004, 8191, RI_E1E1H_OFFLINE }, + { 0x60000, 26, RI_ALL_ONLINE }, + { 0x60068, 8, RI_E1E1H_ONLINE }, + { 0x60088, 12, RI_ALL_ONLINE }, + { 0x600b8, 9, RI_E1E1H_ONLINE }, + { 0x600dc, 1, RI_ALL_ONLINE }, + { 0x600e0, 5, RI_E1E1H_ONLINE }, + { 0x600f4, 1, RI_E1E1HE2_ONLINE }, + { 0x600f8, 1, RI_E1E1H_ONLINE }, + { 0x600fc, 8, RI_ALL_ONLINE }, + { 0x6013c, 24, RI_E1H_ONLINE }, + { 0x6019c, 2, RI_E2E3E3B0_ONLINE }, + { 0x601ac, 18, RI_E2E3E3B0_ONLINE }, + { 0x60200, 1, RI_ALL_ONLINE }, + { 0x60204, 2, RI_ALL_OFFLINE }, + { 0x60210, 13, RI_E2E3E3B0_ONLINE }, + { 0x60244, 16, RI_E3B0_ONLINE }, + { 0x61000, 1, RI_ALL_ONLINE }, + { 0x61004, 511, RI_ALL_OFFLINE }, + { 0x61800, 512, RI_E3E3B0_OFFLINE }, + { 0x70000, 8, RI_ALL_ONLINE }, + { 0x70020, 8184, RI_ALL_OFFLINE }, + { 0x78000, 8192, RI_E3E3B0_OFFLINE }, + { 0x85000, 3, RI_ALL_ONLINE }, + { 0x8501c, 7, RI_ALL_ONLINE }, + { 0x85048, 1, RI_ALL_ONLINE }, + { 0x85200, 32, RI_ALL_ONLINE }, + { 0xb0000, 16384, RI_E1H_ONLINE }, + { 0xc1000, 7, RI_ALL_ONLINE }, + { 0xc103c, 2, RI_E2E3E3B0_ONLINE }, + { 0xc1800, 2, RI_ALL_ONLINE }, + { 0xc2000, 164, RI_ALL_ONLINE }, + { 0xc22c0, 5, RI_E2E3E3B0_ONLINE }, + { 0xc22d8, 4, RI_E2E3E3B0_ONLINE }, + { 0xc2400, 49, RI_ALL_ONLINE }, + { 0xc24c8, 38, RI_ALL_ONLINE }, + { 0xc2568, 2, RI_ALL_ONLINE }, + { 0xc2600, 1, RI_ALL_ONLINE }, + { 0xc4000, 165, RI_ALL_ONLINE }, + { 0xc42d8, 2, RI_E2E3E3B0_ONLINE }, + { 0xc42e0, 7, RI_E1HE2E3E3B0_ONLINE }, + { 0xc42fc, 1, RI_E2E3E3B0_ONLINE }, + { 0xc4400, 51, RI_ALL_ONLINE }, + { 0xc44d0, 38, RI_ALL_ONLINE }, + { 0xc4570, 2, RI_ALL_ONLINE }, + { 0xc4578, 5, RI_E2E3E3B0_ONLINE }, + { 0xc4600, 1, RI_ALL_ONLINE }, + { 0xd0000, 19, RI_ALL_ONLINE }, + { 0xd004c, 8, RI_ALL_ONLINE }, + { 0xd006c, 91, RI_ALL_ONLINE }, + { 0xd01fc, 1, RI_E2E3E3B0_ONLINE }, + { 0xd0200, 2, RI_ALL_ONLINE }, + { 0xd020c, 7, RI_ALL_ONLINE }, + { 0xd0228, 18, RI_E1HE2E3E3B0_ONLINE }, + { 0xd0280, 1, RI_ALL_ONLINE }, + { 0xd0300, 1, RI_ALL_ONLINE }, + { 0xd0400, 1, RI_ALL_ONLINE }, + { 0xd0818, 1, RI_E3B0_ONLINE }, + { 0xd4000, 1, RI_ALL_ONLINE }, + { 0xd4004, 2559, RI_ALL_OFFLINE }, + { 0xd8000, 1, RI_ALL_ONLINE }, + { 0xd8004, 8191, RI_ALL_OFFLINE }, + { 0xe0000, 21, RI_ALL_ONLINE }, + { 0xe0054, 8, RI_ALL_ONLINE }, + { 0xe0074, 49, RI_ALL_ONLINE }, + { 0xe0138, 1, RI_E1E1H_ONLINE }, + { 0xe013c, 35, RI_ALL_ONLINE }, + { 0xe01f4, 1, RI_E2_ONLINE }, + { 0xe01f8, 1, RI_E2E3E3B0_ONLINE }, + { 0xe0200, 2, RI_ALL_ONLINE }, + { 0xe020c, 8, RI_ALL_ONLINE }, + { 0xe022c, 18, RI_E1HE2E3E3B0_ONLINE }, + { 0xe0280, 1, RI_ALL_ONLINE }, + { 0xe0300, 1, RI_ALL_ONLINE }, + { 0xe0400, 1, RI_E3B0_ONLINE }, + { 0xe1000, 1, RI_ALL_ONLINE }, + { 0xe2000, 1, RI_ALL_ONLINE }, + { 0xe2004, 2047, RI_ALL_OFFLINE }, + { 0xf0000, 1, RI_ALL_ONLINE }, + { 0xf0004, 16383, RI_ALL_OFFLINE }, + { 0x101000, 12, RI_ALL_ONLINE }, + { 0x101050, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x101054, 3, RI_E2E3E3B0_ONLINE }, + { 0x101100, 1, RI_ALL_ONLINE }, + { 0x101800, 8, RI_ALL_ONLINE }, + { 0x102000, 18, RI_ALL_ONLINE }, + { 0x102068, 6, RI_E2E3E3B0_ONLINE }, + { 0x102080, 17, RI_ALL_ONLINE }, + { 0x1020c8, 8, RI_E1H_ONLINE }, + { 0x1020e8, 9, RI_E2E3E3B0_ONLINE }, + { 0x102400, 1, RI_ALL_ONLINE }, + { 0x103000, 26, RI_ALL_ONLINE }, + { 0x103098, 5, RI_E1HE2E3E3B0_ONLINE }, + { 0x1030ac, 2, RI_E2E3E3B0_ONLINE }, + { 0x1030b4, 1, RI_E2_ONLINE }, + { 0x1030b8, 7, RI_E2E3E3B0_ONLINE }, + { 0x1030d8, 8, RI_E2E3E3B0_ONLINE }, + { 0x103400, 1, RI_E2E3E3B0_ONLINE }, + { 0x103404, 135, RI_E2E3E3B0_OFFLINE }, + { 0x103800, 8, RI_ALL_ONLINE }, + { 0x104000, 63, RI_ALL_ONLINE }, + { 0x10411c, 16, RI_E2E3E3B0_ONLINE }, + { 0x104200, 17, RI_ALL_ONLINE }, + { 0x104400, 64, RI_ALL_ONLINE }, + { 0x104500, 192, RI_ALL_OFFLINE }, + { 0x104800, 64, RI_ALL_ONLINE }, + { 0x104900, 192, RI_ALL_OFFLINE }, + { 0x105000, 256, RI_ALL_ONLINE }, + { 0x105400, 768, RI_ALL_OFFLINE }, + { 0x107000, 7, RI_E2E3E3B0_ONLINE }, + { 0x10701c, 1, RI_E3E3B0_ONLINE }, + { 0x108000, 33, RI_E1E1H_ONLINE }, + { 0x1080ac, 5, RI_E1H_ONLINE }, + { 0x108100, 5, RI_E1E1H_ONLINE }, + { 0x108120, 5, RI_E1E1H_ONLINE }, + { 0x108200, 74, RI_E1E1H_ONLINE }, + { 0x108400, 74, RI_E1E1H_ONLINE }, + { 0x108800, 152, RI_E1E1H_ONLINE }, + { 0x110000, 111, RI_E2E3E3B0_ONLINE }, + { 0x1101dc, 1, RI_E3E3B0_ONLINE }, + { 0x110200, 4, RI_E2E3E3B0_ONLINE }, + { 0x120000, 2, RI_ALL_ONLINE }, + { 0x120008, 4, RI_ALL_ONLINE }, + { 0x120018, 3, RI_ALL_ONLINE }, + { 0x120024, 4, RI_ALL_ONLINE }, + { 0x120034, 3, RI_ALL_ONLINE }, + { 0x120040, 4, RI_ALL_ONLINE }, + { 0x120050, 3, RI_ALL_ONLINE }, + { 0x12005c, 4, RI_ALL_ONLINE }, + { 0x12006c, 3, RI_ALL_ONLINE }, + { 0x120078, 4, RI_ALL_ONLINE }, + { 0x120088, 3, RI_ALL_ONLINE }, + { 0x120094, 4, RI_ALL_ONLINE }, + { 0x1200a4, 3, RI_ALL_ONLINE }, + { 0x1200b0, 4, RI_ALL_ONLINE }, + { 0x1200c0, 3, RI_ALL_ONLINE }, + { 0x1200cc, 4, RI_ALL_ONLINE }, + { 0x1200dc, 3, RI_ALL_ONLINE }, + { 0x1200e8, 4, RI_ALL_ONLINE }, + { 0x1200f8, 3, RI_ALL_ONLINE }, + { 0x120104, 4, RI_ALL_ONLINE }, + { 0x120114, 1, RI_ALL_ONLINE }, + { 0x120118, 22, RI_ALL_ONLINE }, + { 0x120170, 2, RI_E1E1H_ONLINE }, + { 0x120178, 243, RI_ALL_ONLINE }, + { 0x120544, 4, RI_E1E1H_ONLINE }, + { 0x120554, 6, RI_ALL_ONLINE }, + { 0x12059c, 6, RI_E1HE2E3E3B0_ONLINE }, + { 0x1205b4, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1205b8, 15, RI_E1HE2E3E3B0_ONLINE }, + { 0x1205f4, 1, RI_E1HE2_ONLINE }, + { 0x1205f8, 4, RI_E2E3E3B0_ONLINE }, + { 0x120618, 1, RI_E2E3E3B0_ONLINE }, + { 0x12061c, 20, RI_E1HE2E3E3B0_ONLINE }, + { 0x12066c, 11, RI_E1HE2E3E3B0_ONLINE }, + { 0x120698, 3, RI_E2E3E3B0_ONLINE }, + { 0x1206a4, 1, RI_E2_ONLINE }, + { 0x1206a8, 1, RI_E2E3E3B0_ONLINE }, + { 0x1206b0, 75, RI_E2E3E3B0_ONLINE }, + { 0x1207dc, 1, RI_E2_ONLINE }, + { 0x1207fc, 1, RI_E2E3E3B0_ONLINE }, + { 0x12080c, 65, RI_ALL_ONLINE }, + { 0x120910, 7, RI_E2E3E3B0_ONLINE }, + { 0x120930, 9, RI_E2E3E3B0_ONLINE }, + { 0x12095c, 37, RI_E3E3B0_ONLINE }, + { 0x120a00, 2, RI_E1E1HE2_ONLINE }, + { 0x120b00, 1, RI_E3E3B0_ONLINE }, + { 0x122000, 2, RI_ALL_ONLINE }, + { 0x122008, 2046, RI_E1_OFFLINE }, + { 0x128000, 2, RI_E1HE2E3E3B0_ONLINE }, + { 0x128008, 6142, RI_E1HE2E3E3B0_OFFLINE }, + { 0x130000, 35, RI_E2E3E3B0_ONLINE }, + { 0x130100, 29, RI_E2E3E3B0_ONLINE }, + { 0x130180, 1, RI_E2E3E3B0_ONLINE }, + { 0x130200, 1, RI_E2E3E3B0_ONLINE }, + { 0x130280, 1, RI_E2E3E3B0_ONLINE }, + { 0x130300, 5, RI_E2E3E3B0_ONLINE }, + { 0x130380, 1, RI_E2E3E3B0_ONLINE }, + { 0x130400, 1, RI_E2E3E3B0_ONLINE }, + { 0x130480, 5, RI_E2E3E3B0_ONLINE }, + { 0x130800, 72, RI_E2E3E3B0_ONLINE }, + { 0x131000, 136, RI_E2E3E3B0_ONLINE }, + { 0x132000, 148, RI_E2E3E3B0_ONLINE }, + { 0x134000, 544, RI_E2E3E3B0_ONLINE }, + { 0x140000, 1, RI_ALL_ONLINE }, + { 0x140004, 9, RI_E1E1HE2E3_ONLINE }, + { 0x140028, 8, RI_ALL_ONLINE }, + { 0x140048, 10, RI_E1E1HE2E3_ONLINE }, + { 0x140070, 1, RI_ALL_ONLINE }, + { 0x140074, 10, RI_E1E1HE2E3_ONLINE }, + { 0x14009c, 1, RI_ALL_ONLINE }, + { 0x1400a0, 5, RI_E1E1HE2E3_ONLINE }, + { 0x1400b4, 7, RI_ALL_ONLINE }, + { 0x1400d0, 10, RI_E1E1HE2E3_ONLINE }, + { 0x1400f8, 2, RI_ALL_ONLINE }, + { 0x140100, 5, RI_E1E1H_ONLINE }, + { 0x140114, 5, RI_E1E1HE2E3_ONLINE }, + { 0x140128, 7, RI_ALL_ONLINE }, + { 0x140144, 9, RI_E1E1HE2E3_ONLINE }, + { 0x140168, 8, RI_ALL_ONLINE }, + { 0x140188, 3, RI_E1E1HE2E3_ONLINE }, + { 0x140194, 13, RI_ALL_ONLINE }, + { 0x140200, 6, RI_E1E1HE2E3_ONLINE }, + { 0x140220, 4, RI_E2E3_ONLINE }, + { 0x140240, 4, RI_E2E3_ONLINE }, + { 0x140260, 4, RI_E2E3_ONLINE }, + { 0x140280, 4, RI_E2E3_ONLINE }, + { 0x1402a0, 4, RI_E2E3_ONLINE }, + { 0x1402c0, 4, RI_E2E3_ONLINE }, + { 0x1402e0, 2, RI_E2E3_ONLINE }, + { 0x1402e8, 2, RI_E2E3E3B0_ONLINE }, + { 0x1402f0, 9, RI_E2E3_ONLINE }, + { 0x140314, 44, RI_E3B0_ONLINE }, + { 0x1403d0, 70, RI_E3B0_ONLINE }, + { 0x144000, 4, RI_E1E1H_ONLINE }, + { 0x148000, 4, RI_E1E1H_ONLINE }, + { 0x14c000, 4, RI_E1E1H_ONLINE }, + { 0x150000, 4, RI_E1E1H_ONLINE }, + { 0x154000, 4, RI_E1E1H_ONLINE }, + { 0x158000, 4, RI_E1E1H_ONLINE }, + { 0x15c000, 2, RI_E1HE2E3E3B0_ONLINE }, + { 0x15c008, 5, RI_E1H_ONLINE }, + { 0x15c020, 8, RI_E2E3E3B0_ONLINE }, + { 0x15c040, 1, RI_E2E3_ONLINE }, + { 0x15c044, 2, RI_E2E3E3B0_ONLINE }, + { 0x15c04c, 8, RI_E2E3_ONLINE }, + { 0x15c06c, 8, RI_E2E3E3B0_ONLINE }, + { 0x15c090, 13, RI_E2E3E3B0_ONLINE }, + { 0x15c0c8, 24, RI_E2E3E3B0_ONLINE }, + { 0x15c128, 2, RI_E2E3_ONLINE }, + { 0x15c130, 8, RI_E2E3E3B0_ONLINE }, + { 0x15c150, 2, RI_E3E3B0_ONLINE }, + { 0x15c158, 2, RI_E3_ONLINE }, + { 0x15c160, 149, RI_E3B0_ONLINE }, + { 0x161000, 7, RI_ALL_ONLINE }, + { 0x16103c, 2, RI_E2E3E3B0_ONLINE }, + { 0x161800, 2, RI_ALL_ONLINE }, + { 0x162000, 54, RI_E3E3B0_ONLINE }, + { 0x162200, 60, RI_E3E3B0_ONLINE }, + { 0x162400, 54, RI_E3E3B0_ONLINE }, + { 0x162600, 60, RI_E3E3B0_ONLINE }, + { 0x162800, 54, RI_E3E3B0_ONLINE }, + { 0x162a00, 60, RI_E3E3B0_ONLINE }, + { 0x162c00, 54, RI_E3E3B0_ONLINE }, + { 0x162e00, 60, RI_E3E3B0_ONLINE }, + { 0x164000, 60, RI_ALL_ONLINE }, + { 0x164110, 2, RI_E1HE2E3E3B0_ONLINE }, + { 0x164118, 15, RI_E2E3E3B0_ONLINE }, + { 0x164200, 1, RI_ALL_ONLINE }, + { 0x164208, 1, RI_ALL_ONLINE }, + { 0x164210, 1, RI_ALL_ONLINE }, + { 0x164218, 1, RI_ALL_ONLINE }, + { 0x164220, 1, RI_ALL_ONLINE }, + { 0x164228, 1, RI_ALL_ONLINE }, + { 0x164230, 1, RI_ALL_ONLINE }, + { 0x164238, 1, RI_ALL_ONLINE }, + { 0x164240, 1, RI_ALL_ONLINE }, + { 0x164248, 1, RI_ALL_ONLINE }, + { 0x164250, 1, RI_ALL_ONLINE }, + { 0x164258, 1, RI_ALL_ONLINE }, + { 0x164260, 1, RI_ALL_ONLINE }, + { 0x164270, 2, RI_ALL_ONLINE }, + { 0x164280, 2, RI_ALL_ONLINE }, + { 0x164800, 2, RI_ALL_ONLINE }, + { 0x165000, 2, RI_ALL_ONLINE }, + { 0x166000, 164, RI_ALL_ONLINE }, + { 0x1662cc, 7, RI_E2E3E3B0_ONLINE }, + { 0x166400, 49, RI_ALL_ONLINE }, + { 0x1664c8, 38, RI_ALL_ONLINE }, + { 0x166568, 2, RI_ALL_ONLINE }, + { 0x166570, 5, RI_E2E3E3B0_ONLINE }, + { 0x166800, 1, RI_ALL_ONLINE }, + { 0x168000, 137, RI_ALL_ONLINE }, + { 0x168224, 2, RI_E1E1H_ONLINE }, + { 0x16822c, 29, RI_ALL_ONLINE }, + { 0x1682a0, 12, RI_E1E1H_ONLINE }, + { 0x1682d0, 12, RI_ALL_ONLINE }, + { 0x168300, 2, RI_E1E1H_ONLINE }, + { 0x168308, 68, RI_ALL_ONLINE }, + { 0x168418, 2, RI_E1E1H_ONLINE }, + { 0x168420, 6, RI_ALL_ONLINE }, + { 0x168800, 19, RI_ALL_ONLINE }, + { 0x168900, 1, RI_ALL_ONLINE }, + { 0x168a00, 128, RI_ALL_ONLINE }, + { 0x16a000, 1, RI_ALL_ONLINE }, + { 0x16a004, 1535, RI_ALL_OFFLINE }, + { 0x16c000, 1, RI_ALL_ONLINE }, + { 0x16c004, 1535, RI_ALL_OFFLINE }, + { 0x16e000, 16, RI_E1H_ONLINE }, + { 0x16e040, 8, RI_E2E3E3B0_ONLINE }, + { 0x16e100, 1, RI_E1H_ONLINE }, + { 0x16e200, 2, RI_E1H_ONLINE }, + { 0x16e400, 161, RI_E1H_ONLINE }, + { 0x16e684, 2, RI_E1HE2E3E3B0_ONLINE }, + { 0x16e68c, 12, RI_E1H_ONLINE }, + { 0x16e6bc, 4, RI_E1HE2E3E3B0_ONLINE }, + { 0x16e6cc, 4, RI_E1H_ONLINE }, + { 0x16e6e0, 2, RI_E2E3E3B0_ONLINE }, + { 0x16e6e8, 5, RI_E2E3_ONLINE }, + { 0x16e6fc, 5, RI_E2E3E3B0_ONLINE }, + { 0x16e768, 17, RI_E2E3E3B0_ONLINE }, + { 0x16e7ac, 12, RI_E3B0_ONLINE }, + { 0x170000, 24, RI_ALL_ONLINE }, + { 0x170060, 4, RI_E1E1H_ONLINE }, + { 0x170070, 65, RI_ALL_ONLINE }, + { 0x170194, 11, RI_E2E3E3B0_ONLINE }, + { 0x1701c4, 1, RI_E2E3E3B0_ONLINE }, + { 0x1701cc, 7, RI_E2E3E3B0_ONLINE }, + { 0x1701e8, 1, RI_E3E3B0_ONLINE }, + { 0x1701ec, 1, RI_E2E3E3B0_ONLINE }, + { 0x1701f4, 1, RI_E2E3E3B0_ONLINE }, + { 0x170200, 4, RI_ALL_ONLINE }, + { 0x170214, 1, RI_ALL_ONLINE }, + { 0x170218, 77, RI_E2E3E3B0_ONLINE }, + { 0x170400, 64, RI_E2E3E3B0_ONLINE }, + { 0x178000, 1, RI_ALL_ONLINE }, + { 0x180000, 61, RI_ALL_ONLINE }, + { 0x18013c, 2, RI_E1HE2E3E3B0_ONLINE }, + { 0x180200, 58, RI_ALL_ONLINE }, + { 0x180340, 4, RI_ALL_ONLINE }, + { 0x180380, 1, RI_E2E3E3B0_ONLINE }, + { 0x180388, 1, RI_E2E3E3B0_ONLINE }, + { 0x180390, 1, RI_E2E3E3B0_ONLINE }, + { 0x180398, 1, RI_E2E3E3B0_ONLINE }, + { 0x1803a0, 5, RI_E2E3E3B0_ONLINE }, + { 0x1803b4, 2, RI_E3E3B0_ONLINE }, + { 0x180400, 1, RI_ALL_ONLINE }, + { 0x180404, 255, RI_E1E1H_OFFLINE }, + { 0x181000, 4, RI_ALL_ONLINE }, + { 0x181010, 1020, RI_ALL_OFFLINE }, + { 0x182000, 4, RI_E3E3B0_ONLINE }, + { 0x1a0000, 1, RI_ALL_ONLINE }, + { 0x1a0004, 5631, RI_ALL_OFFLINE }, + { 0x1a5800, 2560, RI_E1HE2E3E3B0_OFFLINE }, + { 0x1a8000, 1, RI_ALL_ONLINE }, + { 0x1a8004, 8191, RI_E1HE2E3E3B0_OFFLINE }, + { 0x1b0000, 1, RI_ALL_ONLINE }, + { 0x1b0004, 15, RI_E1H_OFFLINE }, + { 0x1b0040, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b0044, 239, RI_E1H_OFFLINE }, + { 0x1b0400, 1, RI_ALL_ONLINE }, + { 0x1b0404, 255, RI_E1H_OFFLINE }, + { 0x1b0800, 1, RI_ALL_ONLINE }, + { 0x1b0840, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b0c00, 1, RI_ALL_ONLINE }, + { 0x1b1000, 1, RI_ALL_ONLINE }, + { 0x1b1040, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b1400, 1, RI_ALL_ONLINE }, + { 0x1b1440, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b1480, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b14c0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b1800, 128, RI_ALL_OFFLINE }, + { 0x1b1c00, 128, RI_ALL_OFFLINE }, + { 0x1b2000, 1, RI_ALL_ONLINE }, + { 0x1b2400, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b2404, 5631, RI_E2E3E3B0_OFFLINE }, + { 0x1b8000, 1, RI_ALL_ONLINE }, + { 0x1b8040, 1, RI_ALL_ONLINE }, + { 0x1b8080, 1, RI_ALL_ONLINE }, + { 0x1b80c0, 1, RI_ALL_ONLINE }, + { 0x1b8100, 1, RI_ALL_ONLINE }, + { 0x1b8140, 1, RI_ALL_ONLINE }, + { 0x1b8180, 1, RI_ALL_ONLINE }, + { 0x1b81c0, 1, RI_ALL_ONLINE }, + { 0x1b8200, 1, RI_ALL_ONLINE }, + { 0x1b8240, 1, RI_ALL_ONLINE }, + { 0x1b8280, 1, RI_ALL_ONLINE }, + { 0x1b82c0, 1, RI_ALL_ONLINE }, + { 0x1b8300, 1, RI_ALL_ONLINE }, + { 0x1b8340, 1, RI_ALL_ONLINE }, + { 0x1b8380, 1, RI_ALL_ONLINE }, + { 0x1b83c0, 1, RI_ALL_ONLINE }, + { 0x1b8400, 1, RI_ALL_ONLINE }, + { 0x1b8440, 1, RI_ALL_ONLINE }, + { 0x1b8480, 1, RI_ALL_ONLINE }, + { 0x1b84c0, 1, RI_ALL_ONLINE }, + { 0x1b8500, 1, RI_ALL_ONLINE }, + { 0x1b8540, 1, RI_ALL_ONLINE }, + { 0x1b8580, 1, RI_ALL_ONLINE }, + { 0x1b85c0, 19, RI_E2E3E3B0_ONLINE }, + { 0x1b8800, 1, RI_ALL_ONLINE }, + { 0x1b8840, 1, RI_ALL_ONLINE }, + { 0x1b8880, 1, RI_ALL_ONLINE }, + { 0x1b88c0, 1, RI_ALL_ONLINE }, + { 0x1b8900, 1, RI_ALL_ONLINE }, + { 0x1b8940, 1, RI_ALL_ONLINE }, + { 0x1b8980, 1, RI_ALL_ONLINE }, + { 0x1b89c0, 1, RI_ALL_ONLINE }, + { 0x1b8a00, 1, RI_ALL_ONLINE }, + { 0x1b8a40, 1, RI_ALL_ONLINE }, + { 0x1b8a80, 1, RI_ALL_ONLINE }, + { 0x1b8ac0, 1, RI_ALL_ONLINE }, + { 0x1b8b00, 1, RI_ALL_ONLINE }, + { 0x1b8b40, 1, RI_ALL_ONLINE }, + { 0x1b8b80, 1, RI_ALL_ONLINE }, + { 0x1b8bc0, 1, RI_ALL_ONLINE }, + { 0x1b8c00, 1, RI_ALL_ONLINE }, + { 0x1b8c40, 1, RI_ALL_ONLINE }, + { 0x1b8c80, 1, RI_ALL_ONLINE }, + { 0x1b8cc0, 1, RI_ALL_ONLINE }, + { 0x1b8cc4, 1, RI_E2E3E3B0_ONLINE }, + { 0x1b8d00, 1, RI_ALL_ONLINE }, + { 0x1b8d40, 1, RI_ALL_ONLINE }, + { 0x1b8d80, 1, RI_ALL_ONLINE }, + { 0x1b8dc0, 1, RI_ALL_ONLINE }, + { 0x1b8e00, 1, RI_ALL_ONLINE }, + { 0x1b8e40, 1, RI_ALL_ONLINE }, + { 0x1b8e80, 1, RI_ALL_ONLINE }, + { 0x1b8e84, 1, RI_E2E3E3B0_ONLINE }, + { 0x1b8ec0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b8f00, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b8f40, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b8f80, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b8fc0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x1b8fc4, 2, RI_E2E3E3B0_ONLINE }, + { 0x1b8fd0, 6, RI_E2E3E3B0_ONLINE }, + { 0x1b8fe8, 2, RI_E3E3B0_ONLINE }, + { 0x1b9000, 1, RI_E2E3E3B0_ONLINE }, + { 0x1b9040, 3, RI_E2E3E3B0_ONLINE }, + { 0x1b905c, 1, RI_E3E3B0_ONLINE }, + { 0x1b9064, 1, RI_E3B0_ONLINE }, + { 0x1b9080, 10, RI_E3B0_ONLINE }, + { 0x1b9400, 14, RI_E2E3E3B0_ONLINE }, + { 0x1b943c, 19, RI_E2E3E3B0_ONLINE }, + { 0x1b9490, 10, RI_E2E3E3B0_ONLINE }, + { 0x1c0000, 2, RI_ALL_ONLINE }, + { 0x200000, 65, RI_ALL_ONLINE }, + { 0x20014c, 2, RI_E1HE2E3E3B0_ONLINE }, + { 0x200200, 58, RI_ALL_ONLINE }, + { 0x200340, 4, RI_ALL_ONLINE }, + { 0x200380, 1, RI_E2E3E3B0_ONLINE }, + { 0x200388, 1, RI_E2E3E3B0_ONLINE }, + { 0x200390, 1, RI_E2E3E3B0_ONLINE }, + { 0x200398, 1, RI_E2E3E3B0_ONLINE }, + { 0x2003a0, 1, RI_E2E3E3B0_ONLINE }, + { 0x2003a8, 2, RI_E2E3E3B0_ONLINE }, + { 0x200400, 1, RI_ALL_ONLINE }, + { 0x200404, 255, RI_E1E1H_OFFLINE }, + { 0x202000, 4, RI_ALL_ONLINE }, + { 0x202010, 2044, RI_ALL_OFFLINE }, + { 0x204000, 4, RI_E3E3B0_ONLINE }, + { 0x220000, 1, RI_ALL_ONLINE }, + { 0x220004, 5631, RI_ALL_OFFLINE }, + { 0x225800, 2560, RI_E1HE2E3E3B0_OFFLINE }, + { 0x228000, 1, RI_ALL_ONLINE }, + { 0x228004, 8191, RI_E1HE2E3E3B0_OFFLINE }, + { 0x230000, 1, RI_ALL_ONLINE }, + { 0x230004, 15, RI_E1H_OFFLINE }, + { 0x230040, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x230044, 239, RI_E1H_OFFLINE }, + { 0x230400, 1, RI_ALL_ONLINE }, + { 0x230404, 255, RI_E1H_OFFLINE }, + { 0x230800, 1, RI_ALL_ONLINE }, + { 0x230840, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x230c00, 1, RI_ALL_ONLINE }, + { 0x231000, 1, RI_ALL_ONLINE }, + { 0x231040, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x231400, 1, RI_ALL_ONLINE }, + { 0x231440, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x231480, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2314c0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x231800, 128, RI_ALL_OFFLINE }, + { 0x231c00, 128, RI_ALL_OFFLINE }, + { 0x232000, 1, RI_ALL_ONLINE }, + { 0x232400, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x232404, 5631, RI_E2E3E3B0_OFFLINE }, + { 0x238000, 1, RI_ALL_ONLINE }, + { 0x238040, 1, RI_ALL_ONLINE }, + { 0x238080, 1, RI_ALL_ONLINE }, + { 0x2380c0, 1, RI_ALL_ONLINE }, + { 0x238100, 1, RI_ALL_ONLINE }, + { 0x238140, 1, RI_ALL_ONLINE }, + { 0x238180, 1, RI_ALL_ONLINE }, + { 0x2381c0, 1, RI_ALL_ONLINE }, + { 0x238200, 1, RI_ALL_ONLINE }, + { 0x238240, 1, RI_ALL_ONLINE }, + { 0x238280, 1, RI_ALL_ONLINE }, + { 0x2382c0, 1, RI_ALL_ONLINE }, + { 0x238300, 1, RI_ALL_ONLINE }, + { 0x238340, 1, RI_ALL_ONLINE }, + { 0x238380, 1, RI_ALL_ONLINE }, + { 0x2383c0, 1, RI_ALL_ONLINE }, + { 0x238400, 1, RI_ALL_ONLINE }, + { 0x238440, 1, RI_ALL_ONLINE }, + { 0x238480, 1, RI_ALL_ONLINE }, + { 0x2384c0, 1, RI_ALL_ONLINE }, + { 0x238500, 1, RI_ALL_ONLINE }, + { 0x238540, 1, RI_ALL_ONLINE }, + { 0x238580, 1, RI_ALL_ONLINE }, + { 0x2385c0, 19, RI_E2E3E3B0_ONLINE }, + { 0x238800, 1, RI_ALL_ONLINE }, + { 0x238840, 1, RI_ALL_ONLINE }, + { 0x238880, 1, RI_ALL_ONLINE }, + { 0x2388c0, 1, RI_ALL_ONLINE }, + { 0x238900, 1, RI_ALL_ONLINE }, + { 0x238940, 1, RI_ALL_ONLINE }, + { 0x238980, 1, RI_ALL_ONLINE }, + { 0x2389c0, 1, RI_ALL_ONLINE }, + { 0x238a00, 1, RI_ALL_ONLINE }, + { 0x238a40, 1, RI_ALL_ONLINE }, + { 0x238a80, 1, RI_ALL_ONLINE }, + { 0x238ac0, 1, RI_ALL_ONLINE }, + { 0x238b00, 1, RI_ALL_ONLINE }, + { 0x238b40, 1, RI_ALL_ONLINE }, + { 0x238b80, 1, RI_ALL_ONLINE }, + { 0x238bc0, 1, RI_ALL_ONLINE }, + { 0x238c00, 1, RI_ALL_ONLINE }, + { 0x238c40, 1, RI_ALL_ONLINE }, + { 0x238c80, 1, RI_ALL_ONLINE }, + { 0x238cc0, 1, RI_ALL_ONLINE }, + { 0x238cc4, 1, RI_E2E3E3B0_ONLINE }, + { 0x238d00, 1, RI_ALL_ONLINE }, + { 0x238d40, 1, RI_ALL_ONLINE }, + { 0x238d80, 1, RI_ALL_ONLINE }, + { 0x238dc0, 1, RI_ALL_ONLINE }, + { 0x238e00, 1, RI_ALL_ONLINE }, + { 0x238e40, 1, RI_ALL_ONLINE }, + { 0x238e80, 1, RI_ALL_ONLINE }, + { 0x238e84, 1, RI_E2E3E3B0_ONLINE }, + { 0x238ec0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x238f00, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x238f40, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x238f80, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x238fc0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x238fc4, 2, RI_E2E3E3B0_ONLINE }, + { 0x238fd0, 6, RI_E2E3E3B0_ONLINE }, + { 0x238fe8, 2, RI_E3E3B0_ONLINE }, + { 0x239000, 1, RI_E2E3E3B0_ONLINE }, + { 0x239040, 3, RI_E2E3E3B0_ONLINE }, + { 0x23905c, 1, RI_E3E3B0_ONLINE }, + { 0x239064, 1, RI_E3B0_ONLINE }, + { 0x239080, 10, RI_E3B0_ONLINE }, + { 0x240000, 2, RI_ALL_ONLINE }, + { 0x280000, 65, RI_ALL_ONLINE }, + { 0x28014c, 2, RI_E1HE2E3E3B0_ONLINE }, + { 0x280200, 58, RI_ALL_ONLINE }, + { 0x280340, 4, RI_ALL_ONLINE }, + { 0x280380, 1, RI_E2E3E3B0_ONLINE }, + { 0x280388, 1, RI_E2E3E3B0_ONLINE }, + { 0x280390, 1, RI_E2E3E3B0_ONLINE }, + { 0x280398, 1, RI_E2E3E3B0_ONLINE }, + { 0x2803a0, 1, RI_E2E3E3B0_ONLINE }, + { 0x2803a8, 2, RI_E2E3E3B0_ONLINE }, + { 0x280400, 1, RI_ALL_ONLINE }, + { 0x280404, 255, RI_E1E1H_OFFLINE }, + { 0x282000, 4, RI_ALL_ONLINE }, + { 0x282010, 2044, RI_ALL_OFFLINE }, + { 0x284000, 4, RI_E3E3B0_ONLINE }, + { 0x2a0000, 1, RI_ALL_ONLINE }, + { 0x2a0004, 5631, RI_ALL_OFFLINE }, + { 0x2a5800, 2560, RI_E1HE2E3E3B0_OFFLINE }, + { 0x2a8000, 1, RI_ALL_ONLINE }, + { 0x2a8004, 8191, RI_E1HE2E3E3B0_OFFLINE }, + { 0x2b0000, 1, RI_ALL_ONLINE }, + { 0x2b0004, 15, RI_E1H_OFFLINE }, + { 0x2b0040, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b0044, 239, RI_E1H_OFFLINE }, + { 0x2b0400, 1, RI_ALL_ONLINE }, + { 0x2b0404, 255, RI_E1H_OFFLINE }, + { 0x2b0800, 1, RI_ALL_ONLINE }, + { 0x2b0840, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b0c00, 1, RI_ALL_ONLINE }, + { 0x2b1000, 1, RI_ALL_ONLINE }, + { 0x2b1040, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b1400, 1, RI_ALL_ONLINE }, + { 0x2b1440, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b1480, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b14c0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b1800, 128, RI_ALL_OFFLINE }, + { 0x2b1c00, 128, RI_ALL_OFFLINE }, + { 0x2b2000, 1, RI_ALL_ONLINE }, + { 0x2b2400, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b2404, 5631, RI_E2E3E3B0_OFFLINE }, + { 0x2b8000, 1, RI_ALL_ONLINE }, + { 0x2b8040, 1, RI_ALL_ONLINE }, + { 0x2b8080, 1, RI_ALL_ONLINE }, + { 0x2b80c0, 1, RI_ALL_ONLINE }, + { 0x2b8100, 1, RI_ALL_ONLINE }, + { 0x2b8140, 1, RI_ALL_ONLINE }, + { 0x2b8180, 1, RI_ALL_ONLINE }, + { 0x2b81c0, 1, RI_ALL_ONLINE }, + { 0x2b8200, 1, RI_ALL_ONLINE }, + { 0x2b8240, 1, RI_ALL_ONLINE }, + { 0x2b8280, 1, RI_ALL_ONLINE }, + { 0x2b82c0, 1, RI_ALL_ONLINE }, + { 0x2b8300, 1, RI_ALL_ONLINE }, + { 0x2b8340, 1, RI_ALL_ONLINE }, + { 0x2b8380, 1, RI_ALL_ONLINE }, + { 0x2b83c0, 1, RI_ALL_ONLINE }, + { 0x2b8400, 1, RI_ALL_ONLINE }, + { 0x2b8440, 1, RI_ALL_ONLINE }, + { 0x2b8480, 1, RI_ALL_ONLINE }, + { 0x2b84c0, 1, RI_ALL_ONLINE }, + { 0x2b8500, 1, RI_ALL_ONLINE }, + { 0x2b8540, 1, RI_ALL_ONLINE }, + { 0x2b8580, 1, RI_ALL_ONLINE }, + { 0x2b85c0, 19, RI_E2E3E3B0_ONLINE }, + { 0x2b8800, 1, RI_ALL_ONLINE }, + { 0x2b8840, 1, RI_ALL_ONLINE }, + { 0x2b8880, 1, RI_ALL_ONLINE }, + { 0x2b88c0, 1, RI_ALL_ONLINE }, + { 0x2b8900, 1, RI_ALL_ONLINE }, + { 0x2b8940, 1, RI_ALL_ONLINE }, + { 0x2b8980, 1, RI_ALL_ONLINE }, + { 0x2b89c0, 1, RI_ALL_ONLINE }, + { 0x2b8a00, 1, RI_ALL_ONLINE }, + { 0x2b8a40, 1, RI_ALL_ONLINE }, + { 0x2b8a80, 1, RI_ALL_ONLINE }, + { 0x2b8ac0, 1, RI_ALL_ONLINE }, + { 0x2b8b00, 1, RI_ALL_ONLINE }, + { 0x2b8b40, 1, RI_ALL_ONLINE }, + { 0x2b8b80, 1, RI_ALL_ONLINE }, + { 0x2b8bc0, 1, RI_ALL_ONLINE }, + { 0x2b8c00, 1, RI_ALL_ONLINE }, + { 0x2b8c40, 1, RI_ALL_ONLINE }, + { 0x2b8c80, 1, RI_ALL_ONLINE }, + { 0x2b8cc0, 1, RI_ALL_ONLINE }, + { 0x2b8cc4, 1, RI_E2E3E3B0_ONLINE }, + { 0x2b8d00, 1, RI_ALL_ONLINE }, + { 0x2b8d40, 1, RI_ALL_ONLINE }, + { 0x2b8d80, 1, RI_ALL_ONLINE }, + { 0x2b8dc0, 1, RI_ALL_ONLINE }, + { 0x2b8e00, 1, RI_ALL_ONLINE }, + { 0x2b8e40, 1, RI_ALL_ONLINE }, + { 0x2b8e80, 1, RI_ALL_ONLINE }, + { 0x2b8e84, 1, RI_E2E3E3B0_ONLINE }, + { 0x2b8ec0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b8f00, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b8f40, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b8f80, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b8fc0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x2b8fc4, 2, RI_E2E3E3B0_ONLINE }, + { 0x2b8fd0, 6, RI_E2E3E3B0_ONLINE }, + { 0x2b8fe8, 2, RI_E3E3B0_ONLINE }, + { 0x2b9000, 1, RI_E2E3E3B0_ONLINE }, + { 0x2b9040, 3, RI_E2E3E3B0_ONLINE }, + { 0x2b905c, 1, RI_E3E3B0_ONLINE }, + { 0x2b9064, 1, RI_E3B0_ONLINE }, + { 0x2b9080, 10, RI_E3B0_ONLINE }, + { 0x2b9400, 14, RI_E2E3E3B0_ONLINE }, + { 0x2b943c, 19, RI_E2E3E3B0_ONLINE }, + { 0x2b9490, 10, RI_E2E3E3B0_ONLINE }, + { 0x2c0000, 2, RI_ALL_ONLINE }, + { 0x300000, 65, RI_ALL_ONLINE }, + { 0x30014c, 2, RI_E1HE2E3E3B0_ONLINE }, + { 0x300200, 58, RI_ALL_ONLINE }, + { 0x300340, 4, RI_ALL_ONLINE }, + { 0x300380, 1, RI_E2E3E3B0_ONLINE }, + { 0x300388, 1, RI_E2E3E3B0_ONLINE }, + { 0x300390, 1, RI_E2E3E3B0_ONLINE }, + { 0x300398, 1, RI_E2E3E3B0_ONLINE }, + { 0x3003a0, 1, RI_E2E3E3B0_ONLINE }, + { 0x3003a8, 2, RI_E2E3E3B0_ONLINE }, + { 0x300400, 1, RI_ALL_ONLINE }, + { 0x300404, 255, RI_E1E1H_OFFLINE }, + { 0x302000, 4, RI_ALL_ONLINE }, + { 0x302010, 2044, RI_ALL_OFFLINE }, + { 0x304000, 4, RI_E3E3B0_ONLINE }, + { 0x320000, 1, RI_ALL_ONLINE }, + { 0x320004, 5631, RI_ALL_OFFLINE }, + { 0x325800, 2560, RI_E1HE2E3E3B0_OFFLINE }, + { 0x328000, 1, RI_ALL_ONLINE }, + { 0x328004, 8191, RI_E1HE2E3E3B0_OFFLINE }, + { 0x330000, 1, RI_ALL_ONLINE }, + { 0x330004, 15, RI_E1H_OFFLINE }, + { 0x330040, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x330044, 239, RI_E1H_OFFLINE }, + { 0x330400, 1, RI_ALL_ONLINE }, + { 0x330404, 255, RI_E1H_OFFLINE }, + { 0x330800, 1, RI_ALL_ONLINE }, + { 0x330840, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x330c00, 1, RI_ALL_ONLINE }, + { 0x331000, 1, RI_ALL_ONLINE }, + { 0x331040, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x331400, 1, RI_ALL_ONLINE }, + { 0x331440, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x331480, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x3314c0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x331800, 128, RI_ALL_OFFLINE }, + { 0x331c00, 128, RI_ALL_OFFLINE }, + { 0x332000, 1, RI_ALL_ONLINE }, + { 0x332400, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x332404, 5631, RI_E2E3E3B0_OFFLINE }, + { 0x338000, 1, RI_ALL_ONLINE }, + { 0x338040, 1, RI_ALL_ONLINE }, + { 0x338080, 1, RI_ALL_ONLINE }, + { 0x3380c0, 1, RI_ALL_ONLINE }, + { 0x338100, 1, RI_ALL_ONLINE }, + { 0x338140, 1, RI_ALL_ONLINE }, + { 0x338180, 1, RI_ALL_ONLINE }, + { 0x3381c0, 1, RI_ALL_ONLINE }, + { 0x338200, 1, RI_ALL_ONLINE }, + { 0x338240, 1, RI_ALL_ONLINE }, + { 0x338280, 1, RI_ALL_ONLINE }, + { 0x3382c0, 1, RI_ALL_ONLINE }, + { 0x338300, 1, RI_ALL_ONLINE }, + { 0x338340, 1, RI_ALL_ONLINE }, + { 0x338380, 1, RI_ALL_ONLINE }, + { 0x3383c0, 1, RI_ALL_ONLINE }, + { 0x338400, 1, RI_ALL_ONLINE }, + { 0x338440, 1, RI_ALL_ONLINE }, + { 0x338480, 1, RI_ALL_ONLINE }, + { 0x3384c0, 1, RI_ALL_ONLINE }, + { 0x338500, 1, RI_ALL_ONLINE }, + { 0x338540, 1, RI_ALL_ONLINE }, + { 0x338580, 1, RI_ALL_ONLINE }, + { 0x3385c0, 19, RI_E2E3E3B0_ONLINE }, + { 0x338800, 1, RI_ALL_ONLINE }, + { 0x338840, 1, RI_ALL_ONLINE }, + { 0x338880, 1, RI_ALL_ONLINE }, + { 0x3388c0, 1, RI_ALL_ONLINE }, + { 0x338900, 1, RI_ALL_ONLINE }, + { 0x338940, 1, RI_ALL_ONLINE }, + { 0x338980, 1, RI_ALL_ONLINE }, + { 0x3389c0, 1, RI_ALL_ONLINE }, + { 0x338a00, 1, RI_ALL_ONLINE }, + { 0x338a40, 1, RI_ALL_ONLINE }, + { 0x338a80, 1, RI_ALL_ONLINE }, + { 0x338ac0, 1, RI_ALL_ONLINE }, + { 0x338b00, 1, RI_ALL_ONLINE }, + { 0x338b40, 1, RI_ALL_ONLINE }, + { 0x338b80, 1, RI_ALL_ONLINE }, + { 0x338bc0, 1, RI_ALL_ONLINE }, + { 0x338c00, 1, RI_ALL_ONLINE }, + { 0x338c40, 1, RI_ALL_ONLINE }, + { 0x338c80, 1, RI_ALL_ONLINE }, + { 0x338cc0, 1, RI_ALL_ONLINE }, + { 0x338cc4, 1, RI_E2E3E3B0_ONLINE }, + { 0x338d00, 1, RI_ALL_ONLINE }, + { 0x338d40, 1, RI_ALL_ONLINE }, + { 0x338d80, 1, RI_ALL_ONLINE }, + { 0x338dc0, 1, RI_ALL_ONLINE }, + { 0x338e00, 1, RI_ALL_ONLINE }, + { 0x338e40, 1, RI_ALL_ONLINE }, + { 0x338e80, 1, RI_ALL_ONLINE }, + { 0x338e84, 1, RI_E2E3E3B0_ONLINE }, + { 0x338ec0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x338f00, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x338f40, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x338f80, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x338fc0, 1, RI_E1HE2E3E3B0_ONLINE }, + { 0x338fc4, 2, RI_E2E3E3B0_ONLINE }, + { 0x338fd0, 6, RI_E2E3E3B0_ONLINE }, + { 0x338fe8, 2, RI_E3E3B0_ONLINE }, + { 0x339000, 1, RI_E2E3E3B0_ONLINE }, + { 0x339040, 3, RI_E2E3E3B0_ONLINE }, + { 0x33905c, 1, RI_E3E3B0_ONLINE }, + { 0x339064, 1, RI_E3B0_ONLINE }, + { 0x339080, 10, RI_E3B0_ONLINE }, + { 0x340000, 2, RI_ALL_ONLINE }, +}; +#define REGS_COUNT ARRAY_SIZE(reg_addrs) + +static const struct dump_sign dump_sign_all = { 0x4e23fde1, 0x70017, 0x3a }; + +static const u32 page_vals_e2[] = { 0, 128 }; +#define PAGE_MODE_VALUES_E2 ARRAY_SIZE(page_vals_e2) + +static const u32 page_write_regs_e2[] = { 328476 }; +#define PAGE_WRITE_REGS_E2 ARRAY_SIZE(page_write_regs_e2) + +static const struct reg_addr page_read_regs_e2[] = { + { 0x58000, 4608, RI_E2_ONLINE } }; +#define PAGE_READ_REGS_E2 ARRAY_SIZE(page_read_regs_e2) + +static const u32 page_vals_e3[] = { 0, 128 }; +#define PAGE_MODE_VALUES_E3 ARRAY_SIZE(page_vals_e3) + +static const u32 page_write_regs_e3[] = { 328476 }; +#define PAGE_WRITE_REGS_E3 ARRAY_SIZE(page_write_regs_e3) + +static const struct reg_addr page_read_regs_e3[] = { + { 0x58000, 4608, RI_E3E3B0_ONLINE } }; +#define PAGE_READ_REGS_E3 ARRAY_SIZE(page_read_regs_e3) + +#endif /* BNX2X_DUMP_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c new file mode 100644 index 000000000000..221863059dae --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -0,0 +1,2355 @@ +/* bnx2x_ethtool.c: Broadcom Everest network driver. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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: Eilon Greenstein + * 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 + * + */ +#include +#include +#include +#include +#include + + +#include "bnx2x.h" +#include "bnx2x_cmn.h" +#include "bnx2x_dump.h" +#include "bnx2x_init.h" +#include "bnx2x_sp.h" + +/* Note: in the format strings below %s is replaced by the queue-name which is + * either its index or 'fcoe' for the fcoe queue. Make sure the format string + * length does not exceed ETH_GSTRING_LEN - MAX_QUEUE_NAME_LEN + 2 + */ +#define MAX_QUEUE_NAME_LEN 4 +static const struct { + long offset; + int size; + char string[ETH_GSTRING_LEN]; +} bnx2x_q_stats_arr[] = { +/* 1 */ { Q_STATS_OFFSET32(total_bytes_received_hi), 8, "[%s]: rx_bytes" }, + { Q_STATS_OFFSET32(total_unicast_packets_received_hi), + 8, "[%s]: rx_ucast_packets" }, + { Q_STATS_OFFSET32(total_multicast_packets_received_hi), + 8, "[%s]: rx_mcast_packets" }, + { Q_STATS_OFFSET32(total_broadcast_packets_received_hi), + 8, "[%s]: rx_bcast_packets" }, + { Q_STATS_OFFSET32(no_buff_discard_hi), 8, "[%s]: rx_discards" }, + { Q_STATS_OFFSET32(rx_err_discard_pkt), + 4, "[%s]: rx_phy_ip_err_discards"}, + { Q_STATS_OFFSET32(rx_skb_alloc_failed), + 4, "[%s]: rx_skb_alloc_discard" }, + { Q_STATS_OFFSET32(hw_csum_err), 4, "[%s]: rx_csum_offload_errors" }, + + { Q_STATS_OFFSET32(total_bytes_transmitted_hi), 8, "[%s]: tx_bytes" }, +/* 10 */{ Q_STATS_OFFSET32(total_unicast_packets_transmitted_hi), + 8, "[%s]: tx_ucast_packets" }, + { Q_STATS_OFFSET32(total_multicast_packets_transmitted_hi), + 8, "[%s]: tx_mcast_packets" }, + { Q_STATS_OFFSET32(total_broadcast_packets_transmitted_hi), + 8, "[%s]: tx_bcast_packets" }, + { Q_STATS_OFFSET32(total_tpa_aggregations_hi), + 8, "[%s]: tpa_aggregations" }, + { Q_STATS_OFFSET32(total_tpa_aggregated_frames_hi), + 8, "[%s]: tpa_aggregated_frames"}, + { Q_STATS_OFFSET32(total_tpa_bytes_hi), 8, "[%s]: tpa_bytes"} +}; + +#define BNX2X_NUM_Q_STATS ARRAY_SIZE(bnx2x_q_stats_arr) + +static const struct { + long offset; + int size; + u32 flags; +#define STATS_FLAGS_PORT 1 +#define STATS_FLAGS_FUNC 2 +#define STATS_FLAGS_BOTH (STATS_FLAGS_FUNC | STATS_FLAGS_PORT) + char string[ETH_GSTRING_LEN]; +} bnx2x_stats_arr[] = { +/* 1 */ { STATS_OFFSET32(total_bytes_received_hi), + 8, STATS_FLAGS_BOTH, "rx_bytes" }, + { STATS_OFFSET32(error_bytes_received_hi), + 8, STATS_FLAGS_BOTH, "rx_error_bytes" }, + { STATS_OFFSET32(total_unicast_packets_received_hi), + 8, STATS_FLAGS_BOTH, "rx_ucast_packets" }, + { STATS_OFFSET32(total_multicast_packets_received_hi), + 8, STATS_FLAGS_BOTH, "rx_mcast_packets" }, + { STATS_OFFSET32(total_broadcast_packets_received_hi), + 8, STATS_FLAGS_BOTH, "rx_bcast_packets" }, + { STATS_OFFSET32(rx_stat_dot3statsfcserrors_hi), + 8, STATS_FLAGS_PORT, "rx_crc_errors" }, + { STATS_OFFSET32(rx_stat_dot3statsalignmenterrors_hi), + 8, STATS_FLAGS_PORT, "rx_align_errors" }, + { STATS_OFFSET32(rx_stat_etherstatsundersizepkts_hi), + 8, STATS_FLAGS_PORT, "rx_undersize_packets" }, + { STATS_OFFSET32(etherstatsoverrsizepkts_hi), + 8, STATS_FLAGS_PORT, "rx_oversize_packets" }, +/* 10 */{ STATS_OFFSET32(rx_stat_etherstatsfragments_hi), + 8, STATS_FLAGS_PORT, "rx_fragments" }, + { STATS_OFFSET32(rx_stat_etherstatsjabbers_hi), + 8, STATS_FLAGS_PORT, "rx_jabbers" }, + { STATS_OFFSET32(no_buff_discard_hi), + 8, STATS_FLAGS_BOTH, "rx_discards" }, + { STATS_OFFSET32(mac_filter_discard), + 4, STATS_FLAGS_PORT, "rx_filtered_packets" }, + { STATS_OFFSET32(mf_tag_discard), + 4, STATS_FLAGS_PORT, "rx_mf_tag_discard" }, + { STATS_OFFSET32(brb_drop_hi), + 8, STATS_FLAGS_PORT, "rx_brb_discard" }, + { STATS_OFFSET32(brb_truncate_hi), + 8, STATS_FLAGS_PORT, "rx_brb_truncate" }, + { STATS_OFFSET32(pause_frames_received_hi), + 8, STATS_FLAGS_PORT, "rx_pause_frames" }, + { STATS_OFFSET32(rx_stat_maccontrolframesreceived_hi), + 8, STATS_FLAGS_PORT, "rx_mac_ctrl_frames" }, + { STATS_OFFSET32(nig_timer_max), + 4, STATS_FLAGS_PORT, "rx_constant_pause_events" }, +/* 20 */{ STATS_OFFSET32(rx_err_discard_pkt), + 4, STATS_FLAGS_BOTH, "rx_phy_ip_err_discards"}, + { STATS_OFFSET32(rx_skb_alloc_failed), + 4, STATS_FLAGS_BOTH, "rx_skb_alloc_discard" }, + { STATS_OFFSET32(hw_csum_err), + 4, STATS_FLAGS_BOTH, "rx_csum_offload_errors" }, + + { STATS_OFFSET32(total_bytes_transmitted_hi), + 8, STATS_FLAGS_BOTH, "tx_bytes" }, + { STATS_OFFSET32(tx_stat_ifhcoutbadoctets_hi), + 8, STATS_FLAGS_PORT, "tx_error_bytes" }, + { STATS_OFFSET32(total_unicast_packets_transmitted_hi), + 8, STATS_FLAGS_BOTH, "tx_ucast_packets" }, + { STATS_OFFSET32(total_multicast_packets_transmitted_hi), + 8, STATS_FLAGS_BOTH, "tx_mcast_packets" }, + { STATS_OFFSET32(total_broadcast_packets_transmitted_hi), + 8, STATS_FLAGS_BOTH, "tx_bcast_packets" }, + { STATS_OFFSET32(tx_stat_dot3statsinternalmactransmiterrors_hi), + 8, STATS_FLAGS_PORT, "tx_mac_errors" }, + { STATS_OFFSET32(rx_stat_dot3statscarriersenseerrors_hi), + 8, STATS_FLAGS_PORT, "tx_carrier_errors" }, +/* 30 */{ STATS_OFFSET32(tx_stat_dot3statssinglecollisionframes_hi), + 8, STATS_FLAGS_PORT, "tx_single_collisions" }, + { STATS_OFFSET32(tx_stat_dot3statsmultiplecollisionframes_hi), + 8, STATS_FLAGS_PORT, "tx_multi_collisions" }, + { STATS_OFFSET32(tx_stat_dot3statsdeferredtransmissions_hi), + 8, STATS_FLAGS_PORT, "tx_deferred" }, + { STATS_OFFSET32(tx_stat_dot3statsexcessivecollisions_hi), + 8, STATS_FLAGS_PORT, "tx_excess_collisions" }, + { STATS_OFFSET32(tx_stat_dot3statslatecollisions_hi), + 8, STATS_FLAGS_PORT, "tx_late_collisions" }, + { STATS_OFFSET32(tx_stat_etherstatscollisions_hi), + 8, STATS_FLAGS_PORT, "tx_total_collisions" }, + { STATS_OFFSET32(tx_stat_etherstatspkts64octets_hi), + 8, STATS_FLAGS_PORT, "tx_64_byte_packets" }, + { STATS_OFFSET32(tx_stat_etherstatspkts65octetsto127octets_hi), + 8, STATS_FLAGS_PORT, "tx_65_to_127_byte_packets" }, + { STATS_OFFSET32(tx_stat_etherstatspkts128octetsto255octets_hi), + 8, STATS_FLAGS_PORT, "tx_128_to_255_byte_packets" }, + { STATS_OFFSET32(tx_stat_etherstatspkts256octetsto511octets_hi), + 8, STATS_FLAGS_PORT, "tx_256_to_511_byte_packets" }, +/* 40 */{ STATS_OFFSET32(tx_stat_etherstatspkts512octetsto1023octets_hi), + 8, STATS_FLAGS_PORT, "tx_512_to_1023_byte_packets" }, + { STATS_OFFSET32(etherstatspkts1024octetsto1522octets_hi), + 8, STATS_FLAGS_PORT, "tx_1024_to_1522_byte_packets" }, + { STATS_OFFSET32(etherstatspktsover1522octets_hi), + 8, STATS_FLAGS_PORT, "tx_1523_to_9022_byte_packets" }, + { STATS_OFFSET32(pause_frames_sent_hi), + 8, STATS_FLAGS_PORT, "tx_pause_frames" }, + { STATS_OFFSET32(total_tpa_aggregations_hi), + 8, STATS_FLAGS_FUNC, "tpa_aggregations" }, + { STATS_OFFSET32(total_tpa_aggregated_frames_hi), + 8, STATS_FLAGS_FUNC, "tpa_aggregated_frames"}, + { STATS_OFFSET32(total_tpa_bytes_hi), + 8, STATS_FLAGS_FUNC, "tpa_bytes"} +}; + +#define BNX2X_NUM_STATS ARRAY_SIZE(bnx2x_stats_arr) +static int bnx2x_get_port_type(struct bnx2x *bp) +{ + int port_type; + u32 phy_idx = bnx2x_get_cur_phy_idx(bp); + switch (bp->link_params.phy[phy_idx].media_type) { + case ETH_PHY_SFP_FIBER: + case ETH_PHY_XFP_FIBER: + case ETH_PHY_KR: + case ETH_PHY_CX4: + port_type = PORT_FIBRE; + break; + case ETH_PHY_DA_TWINAX: + port_type = PORT_DA; + break; + case ETH_PHY_BASE_T: + port_type = PORT_TP; + break; + case ETH_PHY_NOT_PRESENT: + port_type = PORT_NONE; + break; + case ETH_PHY_UNSPECIFIED: + default: + port_type = PORT_OTHER; + break; + } + return port_type; +} + +static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct bnx2x *bp = netdev_priv(dev); + int cfg_idx = bnx2x_get_link_cfg_idx(bp); + + /* Dual Media boards present all available port types */ + cmd->supported = bp->port.supported[cfg_idx] | + (bp->port.supported[cfg_idx ^ 1] & + (SUPPORTED_TP | SUPPORTED_FIBRE)); + cmd->advertising = bp->port.advertising[cfg_idx]; + + if ((bp->state == BNX2X_STATE_OPEN) && + !(bp->flags & MF_FUNC_DIS) && + (bp->link_vars.link_up)) { + ethtool_cmd_speed_set(cmd, bp->link_vars.line_speed); + cmd->duplex = bp->link_vars.duplex; + } else { + ethtool_cmd_speed_set( + cmd, bp->link_params.req_line_speed[cfg_idx]); + cmd->duplex = bp->link_params.req_duplex[cfg_idx]; + } + + if (IS_MF(bp)) + ethtool_cmd_speed_set(cmd, bnx2x_get_mf_speed(bp)); + + cmd->port = bnx2x_get_port_type(bp); + + cmd->phy_address = bp->mdio.prtad; + cmd->transceiver = XCVR_INTERNAL; + + if (bp->link_params.req_line_speed[cfg_idx] == SPEED_AUTO_NEG) + cmd->autoneg = AUTONEG_ENABLE; + else + cmd->autoneg = AUTONEG_DISABLE; + + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + + DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" + DP_LEVEL " supported 0x%x advertising 0x%x speed %u\n" + DP_LEVEL " duplex %d port %d phy_address %d transceiver %d\n" + DP_LEVEL " autoneg %d maxtxpkt %d maxrxpkt %d\n", + cmd->cmd, cmd->supported, cmd->advertising, + ethtool_cmd_speed(cmd), + cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, + cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); + + return 0; +} + +static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 advertising, cfg_idx, old_multi_phy_config, new_multi_phy_config; + u32 speed; + + if (IS_MF_SD(bp)) + return 0; + + DP(NETIF_MSG_LINK, "ethtool_cmd: cmd %d\n" + " supported 0x%x advertising 0x%x speed %u\n" + " duplex %d port %d phy_address %d transceiver %d\n" + " autoneg %d maxtxpkt %d maxrxpkt %d\n", + cmd->cmd, cmd->supported, cmd->advertising, + ethtool_cmd_speed(cmd), + cmd->duplex, cmd->port, cmd->phy_address, cmd->transceiver, + cmd->autoneg, cmd->maxtxpkt, cmd->maxrxpkt); + + speed = ethtool_cmd_speed(cmd); + + if (IS_MF_SI(bp)) { + u32 part; + u32 line_speed = bp->link_vars.line_speed; + + /* use 10G if no link detected */ + if (!line_speed) + line_speed = 10000; + + if (bp->common.bc_ver < REQ_BC_VER_4_SET_MF_BW) { + BNX2X_DEV_INFO("To set speed BC %X or higher " + "is required, please upgrade BC\n", + REQ_BC_VER_4_SET_MF_BW); + return -EINVAL; + } + + part = (speed * 100) / line_speed; + + if (line_speed < speed || !part) { + BNX2X_DEV_INFO("Speed setting should be in a range " + "from 1%% to 100%% " + "of actual line speed\n"); + return -EINVAL; + } + + if (bp->state != BNX2X_STATE_OPEN) + /* store value for following "load" */ + bp->pending_max = part; + else + bnx2x_update_max_mf_config(bp, part); + + return 0; + } + + cfg_idx = bnx2x_get_link_cfg_idx(bp); + old_multi_phy_config = bp->link_params.multi_phy_config; + switch (cmd->port) { + case PORT_TP: + if (bp->port.supported[cfg_idx] & SUPPORTED_TP) + break; /* no port change */ + + if (!(bp->port.supported[0] & SUPPORTED_TP || + bp->port.supported[1] & SUPPORTED_TP)) { + DP(NETIF_MSG_LINK, "Unsupported port type\n"); + return -EINVAL; + } + bp->link_params.multi_phy_config &= + ~PORT_HW_CFG_PHY_SELECTION_MASK; + if (bp->link_params.multi_phy_config & + PORT_HW_CFG_PHY_SWAPPED_ENABLED) + bp->link_params.multi_phy_config |= + PORT_HW_CFG_PHY_SELECTION_SECOND_PHY; + else + bp->link_params.multi_phy_config |= + PORT_HW_CFG_PHY_SELECTION_FIRST_PHY; + break; + case PORT_FIBRE: + if (bp->port.supported[cfg_idx] & SUPPORTED_FIBRE) + break; /* no port change */ + + if (!(bp->port.supported[0] & SUPPORTED_FIBRE || + bp->port.supported[1] & SUPPORTED_FIBRE)) { + DP(NETIF_MSG_LINK, "Unsupported port type\n"); + return -EINVAL; + } + bp->link_params.multi_phy_config &= + ~PORT_HW_CFG_PHY_SELECTION_MASK; + if (bp->link_params.multi_phy_config & + PORT_HW_CFG_PHY_SWAPPED_ENABLED) + bp->link_params.multi_phy_config |= + PORT_HW_CFG_PHY_SELECTION_FIRST_PHY; + else + bp->link_params.multi_phy_config |= + PORT_HW_CFG_PHY_SELECTION_SECOND_PHY; + break; + default: + DP(NETIF_MSG_LINK, "Unsupported port type\n"); + return -EINVAL; + } + /* Save new config in case command complete successuly */ + new_multi_phy_config = bp->link_params.multi_phy_config; + /* Get the new cfg_idx */ + cfg_idx = bnx2x_get_link_cfg_idx(bp); + /* Restore old config in case command failed */ + bp->link_params.multi_phy_config = old_multi_phy_config; + DP(NETIF_MSG_LINK, "cfg_idx = %x\n", cfg_idx); + + if (cmd->autoneg == AUTONEG_ENABLE) { + if (!(bp->port.supported[cfg_idx] & SUPPORTED_Autoneg)) { + DP(NETIF_MSG_LINK, "Autoneg not supported\n"); + return -EINVAL; + } + + /* advertise the requested speed and duplex if supported */ + cmd->advertising &= bp->port.supported[cfg_idx]; + + bp->link_params.req_line_speed[cfg_idx] = SPEED_AUTO_NEG; + bp->link_params.req_duplex[cfg_idx] = DUPLEX_FULL; + bp->port.advertising[cfg_idx] |= (ADVERTISED_Autoneg | + cmd->advertising); + + } else { /* forced speed */ + /* advertise the requested speed and duplex if supported */ + switch (speed) { + case SPEED_10: + if (cmd->duplex == DUPLEX_FULL) { + if (!(bp->port.supported[cfg_idx] & + SUPPORTED_10baseT_Full)) { + DP(NETIF_MSG_LINK, + "10M full not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_10baseT_Full | + ADVERTISED_TP); + } else { + if (!(bp->port.supported[cfg_idx] & + SUPPORTED_10baseT_Half)) { + DP(NETIF_MSG_LINK, + "10M half not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_10baseT_Half | + ADVERTISED_TP); + } + break; + + case SPEED_100: + if (cmd->duplex == DUPLEX_FULL) { + if (!(bp->port.supported[cfg_idx] & + SUPPORTED_100baseT_Full)) { + DP(NETIF_MSG_LINK, + "100M full not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_100baseT_Full | + ADVERTISED_TP); + } else { + if (!(bp->port.supported[cfg_idx] & + SUPPORTED_100baseT_Half)) { + DP(NETIF_MSG_LINK, + "100M half not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_100baseT_Half | + ADVERTISED_TP); + } + break; + + case SPEED_1000: + if (cmd->duplex != DUPLEX_FULL) { + DP(NETIF_MSG_LINK, "1G half not supported\n"); + return -EINVAL; + } + + if (!(bp->port.supported[cfg_idx] & + SUPPORTED_1000baseT_Full)) { + DP(NETIF_MSG_LINK, "1G full not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_1000baseT_Full | + ADVERTISED_TP); + break; + + case SPEED_2500: + if (cmd->duplex != DUPLEX_FULL) { + DP(NETIF_MSG_LINK, + "2.5G half not supported\n"); + return -EINVAL; + } + + if (!(bp->port.supported[cfg_idx] + & SUPPORTED_2500baseX_Full)) { + DP(NETIF_MSG_LINK, + "2.5G full not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_2500baseX_Full | + ADVERTISED_TP); + break; + + case SPEED_10000: + if (cmd->duplex != DUPLEX_FULL) { + DP(NETIF_MSG_LINK, "10G half not supported\n"); + return -EINVAL; + } + + if (!(bp->port.supported[cfg_idx] + & SUPPORTED_10000baseT_Full)) { + DP(NETIF_MSG_LINK, "10G full not supported\n"); + return -EINVAL; + } + + advertising = (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); + break; + + default: + DP(NETIF_MSG_LINK, "Unsupported speed %u\n", speed); + return -EINVAL; + } + + bp->link_params.req_line_speed[cfg_idx] = speed; + bp->link_params.req_duplex[cfg_idx] = cmd->duplex; + bp->port.advertising[cfg_idx] = advertising; + } + + DP(NETIF_MSG_LINK, "req_line_speed %d\n" + DP_LEVEL " req_duplex %d advertising 0x%x\n", + bp->link_params.req_line_speed[cfg_idx], + bp->link_params.req_duplex[cfg_idx], + bp->port.advertising[cfg_idx]); + + /* Set new config */ + bp->link_params.multi_phy_config = new_multi_phy_config; + if (netif_running(dev)) { + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + bnx2x_link_set(bp); + } + + return 0; +} + +#define IS_E1_ONLINE(info) (((info) & RI_E1_ONLINE) == RI_E1_ONLINE) +#define IS_E1H_ONLINE(info) (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE) +#define IS_E2_ONLINE(info) (((info) & RI_E2_ONLINE) == RI_E2_ONLINE) +#define IS_E3_ONLINE(info) (((info) & RI_E3_ONLINE) == RI_E3_ONLINE) +#define IS_E3B0_ONLINE(info) (((info) & RI_E3B0_ONLINE) == RI_E3B0_ONLINE) + +static inline bool bnx2x_is_reg_online(struct bnx2x *bp, + const struct reg_addr *reg_info) +{ + if (CHIP_IS_E1(bp)) + return IS_E1_ONLINE(reg_info->info); + else if (CHIP_IS_E1H(bp)) + return IS_E1H_ONLINE(reg_info->info); + else if (CHIP_IS_E2(bp)) + return IS_E2_ONLINE(reg_info->info); + else if (CHIP_IS_E3A0(bp)) + return IS_E3_ONLINE(reg_info->info); + else if (CHIP_IS_E3B0(bp)) + return IS_E3B0_ONLINE(reg_info->info); + else + return false; +} + +/******* Paged registers info selectors ********/ +static inline const u32 *__bnx2x_get_page_addr_ar(struct bnx2x *bp) +{ + if (CHIP_IS_E2(bp)) + return page_vals_e2; + else if (CHIP_IS_E3(bp)) + return page_vals_e3; + else + return NULL; +} + +static inline u32 __bnx2x_get_page_reg_num(struct bnx2x *bp) +{ + if (CHIP_IS_E2(bp)) + return PAGE_MODE_VALUES_E2; + else if (CHIP_IS_E3(bp)) + return PAGE_MODE_VALUES_E3; + else + return 0; +} + +static inline const u32 *__bnx2x_get_page_write_ar(struct bnx2x *bp) +{ + if (CHIP_IS_E2(bp)) + return page_write_regs_e2; + else if (CHIP_IS_E3(bp)) + return page_write_regs_e3; + else + return NULL; +} + +static inline u32 __bnx2x_get_page_write_num(struct bnx2x *bp) +{ + if (CHIP_IS_E2(bp)) + return PAGE_WRITE_REGS_E2; + else if (CHIP_IS_E3(bp)) + return PAGE_WRITE_REGS_E3; + else + return 0; +} + +static inline const struct reg_addr *__bnx2x_get_page_read_ar(struct bnx2x *bp) +{ + if (CHIP_IS_E2(bp)) + return page_read_regs_e2; + else if (CHIP_IS_E3(bp)) + return page_read_regs_e3; + else + return NULL; +} + +static inline u32 __bnx2x_get_page_read_num(struct bnx2x *bp) +{ + if (CHIP_IS_E2(bp)) + return PAGE_READ_REGS_E2; + else if (CHIP_IS_E3(bp)) + return PAGE_READ_REGS_E3; + else + return 0; +} + +static inline int __bnx2x_get_regs_len(struct bnx2x *bp) +{ + int num_pages = __bnx2x_get_page_reg_num(bp); + int page_write_num = __bnx2x_get_page_write_num(bp); + const struct reg_addr *page_read_addr = __bnx2x_get_page_read_ar(bp); + int page_read_num = __bnx2x_get_page_read_num(bp); + int regdump_len = 0; + int i, j, k; + + for (i = 0; i < REGS_COUNT; i++) + if (bnx2x_is_reg_online(bp, ®_addrs[i])) + regdump_len += reg_addrs[i].size; + + for (i = 0; i < num_pages; i++) + for (j = 0; j < page_write_num; j++) + for (k = 0; k < page_read_num; k++) + if (bnx2x_is_reg_online(bp, &page_read_addr[k])) + regdump_len += page_read_addr[k].size; + + return regdump_len; +} + +static int bnx2x_get_regs_len(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + int regdump_len = 0; + + regdump_len = __bnx2x_get_regs_len(bp); + regdump_len *= 4; + regdump_len += sizeof(struct dump_hdr); + + return regdump_len; +} + +/** + * bnx2x_read_pages_regs - read "paged" registers + * + * @bp device handle + * @p output buffer + * + * Reads "paged" memories: memories that may only be read by first writing to a + * specific address ("write address") and then reading from a specific address + * ("read address"). There may be more than one write address per "page" and + * more than one read address per write address. + */ +static inline void bnx2x_read_pages_regs(struct bnx2x *bp, u32 *p) +{ + u32 i, j, k, n; + /* addresses of the paged registers */ + const u32 *page_addr = __bnx2x_get_page_addr_ar(bp); + /* number of paged registers */ + int num_pages = __bnx2x_get_page_reg_num(bp); + /* write addresses */ + const u32 *write_addr = __bnx2x_get_page_write_ar(bp); + /* number of write addresses */ + int write_num = __bnx2x_get_page_write_num(bp); + /* read addresses info */ + const struct reg_addr *read_addr = __bnx2x_get_page_read_ar(bp); + /* number of read addresses */ + int read_num = __bnx2x_get_page_read_num(bp); + + for (i = 0; i < num_pages; i++) { + for (j = 0; j < write_num; j++) { + REG_WR(bp, write_addr[j], page_addr[i]); + for (k = 0; k < read_num; k++) + if (bnx2x_is_reg_online(bp, &read_addr[k])) + for (n = 0; n < + read_addr[k].size; n++) + *p++ = REG_RD(bp, + read_addr[k].addr + n*4); + } + } +} + +static inline void __bnx2x_get_regs(struct bnx2x *bp, u32 *p) +{ + u32 i, j; + + /* Read the regular registers */ + for (i = 0; i < REGS_COUNT; i++) + if (bnx2x_is_reg_online(bp, ®_addrs[i])) + for (j = 0; j < reg_addrs[i].size; j++) + *p++ = REG_RD(bp, reg_addrs[i].addr + j*4); + + /* Read "paged" registes */ + bnx2x_read_pages_regs(bp, p); +} + +static void bnx2x_get_regs(struct net_device *dev, + struct ethtool_regs *regs, void *_p) +{ + u32 *p = _p; + struct bnx2x *bp = netdev_priv(dev); + struct dump_hdr dump_hdr = {0}; + + regs->version = 0; + memset(p, 0, regs->len); + + if (!netif_running(bp->dev)) + return; + + /* Disable parity attentions as long as following dump may + * cause false alarms by reading never written registers. We + * will re-enable parity attentions right after the dump. + */ + bnx2x_disable_blocks_parity(bp); + + dump_hdr.hdr_size = (sizeof(struct dump_hdr) / 4) - 1; + dump_hdr.dump_sign = dump_sign_all; + dump_hdr.xstorm_waitp = REG_RD(bp, XSTORM_WAITP_ADDR); + dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR); + dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR); + dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR); + + if (CHIP_IS_E1(bp)) + dump_hdr.info = RI_E1_ONLINE; + else if (CHIP_IS_E1H(bp)) + dump_hdr.info = RI_E1H_ONLINE; + else if (!CHIP_IS_E1x(bp)) + dump_hdr.info = RI_E2_ONLINE | + (BP_PATH(bp) ? RI_PATH1_DUMP : RI_PATH0_DUMP); + + memcpy(p, &dump_hdr, sizeof(struct dump_hdr)); + p += dump_hdr.hdr_size + 1; + + /* Actually read the registers */ + __bnx2x_get_regs(bp, p); + + /* Re-enable parity attentions */ + bnx2x_clear_blocks_parity(bp); + bnx2x_enable_blocks_parity(bp); +} + +static void bnx2x_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct bnx2x *bp = netdev_priv(dev); + u8 phy_fw_ver[PHY_FW_VER_LEN]; + + strcpy(info->driver, DRV_MODULE_NAME); + strcpy(info->version, DRV_MODULE_VERSION); + + phy_fw_ver[0] = '\0'; + if (bp->port.pmf) { + bnx2x_acquire_phy_lock(bp); + bnx2x_get_ext_phy_fw_version(&bp->link_params, + (bp->state != BNX2X_STATE_CLOSED), + phy_fw_ver, PHY_FW_VER_LEN); + bnx2x_release_phy_lock(bp); + } + + strncpy(info->fw_version, bp->fw_ver, 32); + snprintf(info->fw_version + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver), + "bc %d.%d.%d%s%s", + (bp->common.bc_ver & 0xff0000) >> 16, + (bp->common.bc_ver & 0xff00) >> 8, + (bp->common.bc_ver & 0xff), + ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver); + strcpy(info->bus_info, pci_name(bp->pdev)); + info->n_stats = BNX2X_NUM_STATS; + info->testinfo_len = BNX2X_NUM_TESTS; + info->eedump_len = bp->common.flash_size; + info->regdump_len = bnx2x_get_regs_len(dev); +} + +static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (bp->flags & NO_WOL_FLAG) { + wol->supported = 0; + wol->wolopts = 0; + } else { + wol->supported = WAKE_MAGIC; + if (bp->wol) + wol->wolopts = WAKE_MAGIC; + else + wol->wolopts = 0; + } + memset(&wol->sopass, 0, sizeof(wol->sopass)); +} + +static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (wol->wolopts & ~WAKE_MAGIC) + return -EINVAL; + + if (wol->wolopts & WAKE_MAGIC) { + if (bp->flags & NO_WOL_FLAG) + return -EINVAL; + + bp->wol = 1; + } else + bp->wol = 0; + + return 0; +} + +static u32 bnx2x_get_msglevel(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + return bp->msg_enable; +} + +static void bnx2x_set_msglevel(struct net_device *dev, u32 level) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (capable(CAP_NET_ADMIN)) { + /* dump MCP trace */ + if (level & BNX2X_MSG_MCP) + bnx2x_fw_dump_lvl(bp, KERN_INFO); + bp->msg_enable = level; + } +} + +static int bnx2x_nway_reset(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (!bp->port.pmf) + return 0; + + if (netif_running(dev)) { + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + bnx2x_link_set(bp); + } + + return 0; +} + +static u32 bnx2x_get_link(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (bp->flags & MF_FUNC_DIS || (bp->state != BNX2X_STATE_OPEN)) + return 0; + + return bp->link_vars.link_up; +} + +static int bnx2x_get_eeprom_len(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + return bp->common.flash_size; +} + +static int bnx2x_acquire_nvram_lock(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int count, i; + u32 val = 0; + + /* adjust timeout for emulation/FPGA */ + count = BNX2X_NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* request access to nvram interface */ + REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, + (MCPR_NVM_SW_ARB_ARB_REQ_SET1 << port)); + + for (i = 0; i < count*10; i++) { + val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB); + if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) + break; + + udelay(5); + } + + if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) { + DP(BNX2X_MSG_NVM, "cannot get access to nvram interface\n"); + return -EBUSY; + } + + return 0; +} + +static int bnx2x_release_nvram_lock(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int count, i; + u32 val = 0; + + /* adjust timeout for emulation/FPGA */ + count = BNX2X_NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* relinquish nvram interface */ + REG_WR(bp, MCP_REG_MCPR_NVM_SW_ARB, + (MCPR_NVM_SW_ARB_ARB_REQ_CLR1 << port)); + + for (i = 0; i < count*10; i++) { + val = REG_RD(bp, MCP_REG_MCPR_NVM_SW_ARB); + if (!(val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port))) + break; + + udelay(5); + } + + if (val & (MCPR_NVM_SW_ARB_ARB_ARB1 << port)) { + DP(BNX2X_MSG_NVM, "cannot free access to nvram interface\n"); + return -EBUSY; + } + + return 0; +} + +static void bnx2x_enable_nvram_access(struct bnx2x *bp) +{ + u32 val; + + val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE); + + /* enable both bits, even on read */ + REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE, + (val | MCPR_NVM_ACCESS_ENABLE_EN | + MCPR_NVM_ACCESS_ENABLE_WR_EN)); +} + +static void bnx2x_disable_nvram_access(struct bnx2x *bp) +{ + u32 val; + + val = REG_RD(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE); + + /* disable both bits, even after read */ + REG_WR(bp, MCP_REG_MCPR_NVM_ACCESS_ENABLE, + (val & ~(MCPR_NVM_ACCESS_ENABLE_EN | + MCPR_NVM_ACCESS_ENABLE_WR_EN))); +} + +static int bnx2x_nvram_read_dword(struct bnx2x *bp, u32 offset, __be32 *ret_val, + u32 cmd_flags) +{ + int count, i, rc; + u32 val; + + /* build the command word */ + cmd_flags |= MCPR_NVM_COMMAND_DOIT; + + /* need to clear DONE bit separately */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE); + + /* address of the NVRAM to read from */ + REG_WR(bp, MCP_REG_MCPR_NVM_ADDR, + (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE)); + + /* issue a read command */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags); + + /* adjust timeout for emulation/FPGA */ + count = BNX2X_NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* wait for completion */ + *ret_val = 0; + rc = -EBUSY; + for (i = 0; i < count; i++) { + udelay(5); + val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND); + + if (val & MCPR_NVM_COMMAND_DONE) { + val = REG_RD(bp, MCP_REG_MCPR_NVM_READ); + /* we read nvram data in cpu order + * but ethtool sees it as an array of bytes + * converting to big-endian will do the work */ + *ret_val = cpu_to_be32(val); + rc = 0; + break; + } + } + + return rc; +} + +static int bnx2x_nvram_read(struct bnx2x *bp, u32 offset, u8 *ret_buf, + int buf_size) +{ + int rc; + u32 cmd_flags; + __be32 val; + + if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { + DP(BNX2X_MSG_NVM, + "Invalid parameter: offset 0x%x buf_size 0x%x\n", + offset, buf_size); + return -EINVAL; + } + + if (offset + buf_size > bp->common.flash_size) { + DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +" + " buf_size (0x%x) > flash_size (0x%x)\n", + offset, buf_size, bp->common.flash_size); + return -EINVAL; + } + + /* request access to nvram interface */ + rc = bnx2x_acquire_nvram_lock(bp); + if (rc) + return rc; + + /* enable access to nvram interface */ + bnx2x_enable_nvram_access(bp); + + /* read the first word(s) */ + cmd_flags = MCPR_NVM_COMMAND_FIRST; + while ((buf_size > sizeof(u32)) && (rc == 0)) { + rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags); + memcpy(ret_buf, &val, 4); + + /* advance to the next dword */ + offset += sizeof(u32); + ret_buf += sizeof(u32); + buf_size -= sizeof(u32); + cmd_flags = 0; + } + + if (rc == 0) { + cmd_flags |= MCPR_NVM_COMMAND_LAST; + rc = bnx2x_nvram_read_dword(bp, offset, &val, cmd_flags); + memcpy(ret_buf, &val, 4); + } + + /* disable access to nvram interface */ + bnx2x_disable_nvram_access(bp); + bnx2x_release_nvram_lock(bp); + + return rc; +} + +static int bnx2x_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *eebuf) +{ + struct bnx2x *bp = netdev_priv(dev); + int rc; + + if (!netif_running(dev)) + return -EAGAIN; + + DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n" + DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", + eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, + eeprom->len, eeprom->len); + + /* parameters already validated in ethtool_get_eeprom */ + + rc = bnx2x_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); + + return rc; +} + +static int bnx2x_nvram_write_dword(struct bnx2x *bp, u32 offset, u32 val, + u32 cmd_flags) +{ + int count, i, rc; + + /* build the command word */ + cmd_flags |= MCPR_NVM_COMMAND_DOIT | MCPR_NVM_COMMAND_WR; + + /* need to clear DONE bit separately */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, MCPR_NVM_COMMAND_DONE); + + /* write the data */ + REG_WR(bp, MCP_REG_MCPR_NVM_WRITE, val); + + /* address of the NVRAM to write to */ + REG_WR(bp, MCP_REG_MCPR_NVM_ADDR, + (offset & MCPR_NVM_ADDR_NVM_ADDR_VALUE)); + + /* issue the write command */ + REG_WR(bp, MCP_REG_MCPR_NVM_COMMAND, cmd_flags); + + /* adjust timeout for emulation/FPGA */ + count = BNX2X_NVRAM_TIMEOUT_COUNT; + if (CHIP_REV_IS_SLOW(bp)) + count *= 100; + + /* wait for completion */ + rc = -EBUSY; + for (i = 0; i < count; i++) { + udelay(5); + val = REG_RD(bp, MCP_REG_MCPR_NVM_COMMAND); + if (val & MCPR_NVM_COMMAND_DONE) { + rc = 0; + break; + } + } + + return rc; +} + +#define BYTE_OFFSET(offset) (8 * (offset & 0x03)) + +static int bnx2x_nvram_write1(struct bnx2x *bp, u32 offset, u8 *data_buf, + int buf_size) +{ + int rc; + u32 cmd_flags; + u32 align_offset; + __be32 val; + + if (offset + buf_size > bp->common.flash_size) { + DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +" + " buf_size (0x%x) > flash_size (0x%x)\n", + offset, buf_size, bp->common.flash_size); + return -EINVAL; + } + + /* request access to nvram interface */ + rc = bnx2x_acquire_nvram_lock(bp); + if (rc) + return rc; + + /* enable access to nvram interface */ + bnx2x_enable_nvram_access(bp); + + cmd_flags = (MCPR_NVM_COMMAND_FIRST | MCPR_NVM_COMMAND_LAST); + align_offset = (offset & ~0x03); + rc = bnx2x_nvram_read_dword(bp, align_offset, &val, cmd_flags); + + if (rc == 0) { + val &= ~(0xff << BYTE_OFFSET(offset)); + val |= (*data_buf << BYTE_OFFSET(offset)); + + /* nvram data is returned as an array of bytes + * convert it back to cpu order */ + val = be32_to_cpu(val); + + rc = bnx2x_nvram_write_dword(bp, align_offset, val, + cmd_flags); + } + + /* disable access to nvram interface */ + bnx2x_disable_nvram_access(bp); + bnx2x_release_nvram_lock(bp); + + return rc; +} + +static int bnx2x_nvram_write(struct bnx2x *bp, u32 offset, u8 *data_buf, + int buf_size) +{ + int rc; + u32 cmd_flags; + u32 val; + u32 written_so_far; + + if (buf_size == 1) /* ethtool */ + return bnx2x_nvram_write1(bp, offset, data_buf, buf_size); + + if ((offset & 0x03) || (buf_size & 0x03) || (buf_size == 0)) { + DP(BNX2X_MSG_NVM, + "Invalid parameter: offset 0x%x buf_size 0x%x\n", + offset, buf_size); + return -EINVAL; + } + + if (offset + buf_size > bp->common.flash_size) { + DP(BNX2X_MSG_NVM, "Invalid parameter: offset (0x%x) +" + " buf_size (0x%x) > flash_size (0x%x)\n", + offset, buf_size, bp->common.flash_size); + return -EINVAL; + } + + /* request access to nvram interface */ + rc = bnx2x_acquire_nvram_lock(bp); + if (rc) + return rc; + + /* enable access to nvram interface */ + bnx2x_enable_nvram_access(bp); + + written_so_far = 0; + cmd_flags = MCPR_NVM_COMMAND_FIRST; + while ((written_so_far < buf_size) && (rc == 0)) { + if (written_so_far == (buf_size - sizeof(u32))) + cmd_flags |= MCPR_NVM_COMMAND_LAST; + else if (((offset + 4) % BNX2X_NVRAM_PAGE_SIZE) == 0) + cmd_flags |= MCPR_NVM_COMMAND_LAST; + else if ((offset % BNX2X_NVRAM_PAGE_SIZE) == 0) + cmd_flags |= MCPR_NVM_COMMAND_FIRST; + + memcpy(&val, data_buf, 4); + + rc = bnx2x_nvram_write_dword(bp, offset, val, cmd_flags); + + /* advance to the next dword */ + offset += sizeof(u32); + data_buf += sizeof(u32); + written_so_far += sizeof(u32); + cmd_flags = 0; + } + + /* disable access to nvram interface */ + bnx2x_disable_nvram_access(bp); + bnx2x_release_nvram_lock(bp); + + return rc; +} + +static int bnx2x_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *eebuf) +{ + struct bnx2x *bp = netdev_priv(dev); + int port = BP_PORT(bp); + int rc = 0; + u32 ext_phy_config; + if (!netif_running(dev)) + return -EAGAIN; + + DP(BNX2X_MSG_NVM, "ethtool_eeprom: cmd %d\n" + DP_LEVEL " magic 0x%x offset 0x%x (%d) len 0x%x (%d)\n", + eeprom->cmd, eeprom->magic, eeprom->offset, eeprom->offset, + eeprom->len, eeprom->len); + + /* parameters already validated in ethtool_set_eeprom */ + + /* PHY eeprom can be accessed only by the PMF */ + if ((eeprom->magic >= 0x50485900) && (eeprom->magic <= 0x504859FF) && + !bp->port.pmf) + return -EINVAL; + + ext_phy_config = + SHMEM_RD(bp, + dev_info.port_hw_config[port].external_phy_config); + + if (eeprom->magic == 0x50485950) { + /* 'PHYP' (0x50485950): prepare phy for FW upgrade */ + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + + bnx2x_acquire_phy_lock(bp); + rc |= bnx2x_link_reset(&bp->link_params, + &bp->link_vars, 0); + if (XGXS_EXT_PHY_TYPE(ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, + MISC_REGISTERS_GPIO_HIGH, port); + bnx2x_release_phy_lock(bp); + bnx2x_link_report(bp); + + } else if (eeprom->magic == 0x50485952) { + /* 'PHYR' (0x50485952): re-init link after FW upgrade */ + if (bp->state == BNX2X_STATE_OPEN) { + bnx2x_acquire_phy_lock(bp); + rc |= bnx2x_link_reset(&bp->link_params, + &bp->link_vars, 1); + + rc |= bnx2x_phy_init(&bp->link_params, + &bp->link_vars); + bnx2x_release_phy_lock(bp); + bnx2x_calc_fc_adv(bp); + } + } else if (eeprom->magic == 0x53985943) { + /* 'PHYC' (0x53985943): PHY FW upgrade completed */ + if (XGXS_EXT_PHY_TYPE(ext_phy_config) == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101) { + + /* DSP Remove Download Mode */ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_0, + MISC_REGISTERS_GPIO_LOW, port); + + bnx2x_acquire_phy_lock(bp); + + bnx2x_sfx7101_sp_sw_reset(bp, + &bp->link_params.phy[EXT_PHY1]); + + /* wait 0.5 sec to allow it to run */ + msleep(500); + bnx2x_ext_phy_hw_reset(bp, port); + msleep(500); + bnx2x_release_phy_lock(bp); + } + } else + rc = bnx2x_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); + + return rc; +} + +static int bnx2x_get_coalesce(struct net_device *dev, + struct ethtool_coalesce *coal) +{ + struct bnx2x *bp = netdev_priv(dev); + + memset(coal, 0, sizeof(struct ethtool_coalesce)); + + coal->rx_coalesce_usecs = bp->rx_ticks; + coal->tx_coalesce_usecs = bp->tx_ticks; + + return 0; +} + +static int bnx2x_set_coalesce(struct net_device *dev, + struct ethtool_coalesce *coal) +{ + struct bnx2x *bp = netdev_priv(dev); + + bp->rx_ticks = (u16)coal->rx_coalesce_usecs; + if (bp->rx_ticks > BNX2X_MAX_COALESCE_TOUT) + bp->rx_ticks = BNX2X_MAX_COALESCE_TOUT; + + bp->tx_ticks = (u16)coal->tx_coalesce_usecs; + if (bp->tx_ticks > BNX2X_MAX_COALESCE_TOUT) + bp->tx_ticks = BNX2X_MAX_COALESCE_TOUT; + + if (netif_running(dev)) + bnx2x_update_coalesce(bp); + + return 0; +} + +static void bnx2x_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ering) +{ + struct bnx2x *bp = netdev_priv(dev); + + ering->rx_max_pending = MAX_RX_AVAIL; + ering->rx_mini_max_pending = 0; + ering->rx_jumbo_max_pending = 0; + + if (bp->rx_ring_size) + ering->rx_pending = bp->rx_ring_size; + else + if (bp->state == BNX2X_STATE_OPEN && bp->num_queues) + ering->rx_pending = MAX_RX_AVAIL/bp->num_queues; + else + ering->rx_pending = MAX_RX_AVAIL; + + ering->rx_mini_pending = 0; + ering->rx_jumbo_pending = 0; + + ering->tx_max_pending = MAX_TX_AVAIL; + ering->tx_pending = bp->tx_ring_size; +} + +static int bnx2x_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ering) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (bp->recovery_state != BNX2X_RECOVERY_DONE) { + printk(KERN_ERR "Handling parity error recovery. Try again later\n"); + return -EAGAIN; + } + + if ((ering->rx_pending > MAX_RX_AVAIL) || + (ering->rx_pending < (bp->disable_tpa ? MIN_RX_SIZE_NONTPA : + MIN_RX_SIZE_TPA)) || + (ering->tx_pending > MAX_TX_AVAIL) || + (ering->tx_pending <= MAX_SKB_FRAGS + 4)) + return -EINVAL; + + bp->rx_ring_size = ering->rx_pending; + bp->tx_ring_size = ering->tx_pending; + + return bnx2x_reload_if_running(dev); +} + +static void bnx2x_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct bnx2x *bp = netdev_priv(dev); + int cfg_idx = bnx2x_get_link_cfg_idx(bp); + epause->autoneg = (bp->link_params.req_flow_ctrl[cfg_idx] == + BNX2X_FLOW_CTRL_AUTO); + + epause->rx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) == + BNX2X_FLOW_CTRL_RX); + epause->tx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) == + BNX2X_FLOW_CTRL_TX); + + DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n" + DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", + epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); +} + +static int bnx2x_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *epause) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 cfg_idx = bnx2x_get_link_cfg_idx(bp); + if (IS_MF(bp)) + return 0; + + DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n" + DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", + epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); + + bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_AUTO; + + if (epause->rx_pause) + bp->link_params.req_flow_ctrl[cfg_idx] |= BNX2X_FLOW_CTRL_RX; + + if (epause->tx_pause) + bp->link_params.req_flow_ctrl[cfg_idx] |= BNX2X_FLOW_CTRL_TX; + + if (bp->link_params.req_flow_ctrl[cfg_idx] == BNX2X_FLOW_CTRL_AUTO) + bp->link_params.req_flow_ctrl[cfg_idx] = BNX2X_FLOW_CTRL_NONE; + + if (epause->autoneg) { + if (!(bp->port.supported[cfg_idx] & SUPPORTED_Autoneg)) { + DP(NETIF_MSG_LINK, "autoneg not supported\n"); + return -EINVAL; + } + + if (bp->link_params.req_line_speed[cfg_idx] == SPEED_AUTO_NEG) { + bp->link_params.req_flow_ctrl[cfg_idx] = + BNX2X_FLOW_CTRL_AUTO; + } + } + + DP(NETIF_MSG_LINK, + "req_flow_ctrl 0x%x\n", bp->link_params.req_flow_ctrl[cfg_idx]); + + if (netif_running(dev)) { + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + bnx2x_link_set(bp); + } + + return 0; +} + +static const struct { + char string[ETH_GSTRING_LEN]; +} bnx2x_tests_str_arr[BNX2X_NUM_TESTS] = { + { "register_test (offline)" }, + { "memory_test (offline)" }, + { "loopback_test (offline)" }, + { "nvram_test (online)" }, + { "interrupt_test (online)" }, + { "link_test (online)" }, + { "idle check (online)" } +}; + +enum { + BNX2X_CHIP_E1_OFST = 0, + BNX2X_CHIP_E1H_OFST, + BNX2X_CHIP_E2_OFST, + BNX2X_CHIP_E3_OFST, + BNX2X_CHIP_E3B0_OFST, + BNX2X_CHIP_MAX_OFST +}; + +#define BNX2X_CHIP_MASK_E1 (1 << BNX2X_CHIP_E1_OFST) +#define BNX2X_CHIP_MASK_E1H (1 << BNX2X_CHIP_E1H_OFST) +#define BNX2X_CHIP_MASK_E2 (1 << BNX2X_CHIP_E2_OFST) +#define BNX2X_CHIP_MASK_E3 (1 << BNX2X_CHIP_E3_OFST) +#define BNX2X_CHIP_MASK_E3B0 (1 << BNX2X_CHIP_E3B0_OFST) + +#define BNX2X_CHIP_MASK_ALL ((1 << BNX2X_CHIP_MAX_OFST) - 1) +#define BNX2X_CHIP_MASK_E1X (BNX2X_CHIP_MASK_E1 | BNX2X_CHIP_MASK_E1H) + +static int bnx2x_test_registers(struct bnx2x *bp) +{ + int idx, i, rc = -ENODEV; + u32 wr_val = 0, hw; + int port = BP_PORT(bp); + static const struct { + u32 hw; + u32 offset0; + u32 offset1; + u32 mask; + } reg_tbl[] = { +/* 0 */ { BNX2X_CHIP_MASK_ALL, + BRB1_REG_PAUSE_LOW_THRESHOLD_0, 4, 0x000003ff }, + { BNX2X_CHIP_MASK_ALL, + DORQ_REG_DB_ADDR0, 4, 0xffffffff }, + { BNX2X_CHIP_MASK_E1X, + HC_REG_AGG_INT_0, 4, 0x000003ff }, + { BNX2X_CHIP_MASK_ALL, + PBF_REG_MAC_IF0_ENABLE, 4, 0x00000001 }, + { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2 | BNX2X_CHIP_MASK_E3, + PBF_REG_P0_INIT_CRD, 4, 0x000007ff }, + { BNX2X_CHIP_MASK_E3B0, + PBF_REG_INIT_CRD_Q0, 4, 0x000007ff }, + { BNX2X_CHIP_MASK_ALL, + PRS_REG_CID_PORT_0, 4, 0x00ffffff }, + { BNX2X_CHIP_MASK_ALL, + PXP2_REG_PSWRQ_CDU0_L2P, 4, 0x000fffff }, + { BNX2X_CHIP_MASK_ALL, + PXP2_REG_RQ_CDU0_EFIRST_MEM_ADDR, 8, 0x0003ffff }, + { BNX2X_CHIP_MASK_ALL, + PXP2_REG_PSWRQ_TM0_L2P, 4, 0x000fffff }, +/* 10 */ { BNX2X_CHIP_MASK_ALL, + PXP2_REG_RQ_USDM0_EFIRST_MEM_ADDR, 8, 0x0003ffff }, + { BNX2X_CHIP_MASK_ALL, + PXP2_REG_PSWRQ_TSDM0_L2P, 4, 0x000fffff }, + { BNX2X_CHIP_MASK_ALL, + QM_REG_CONNNUM_0, 4, 0x000fffff }, + { BNX2X_CHIP_MASK_ALL, + TM_REG_LIN0_MAX_ACTIVE_CID, 4, 0x0003ffff }, + { BNX2X_CHIP_MASK_ALL, + SRC_REG_KEYRSS0_0, 40, 0xffffffff }, + { BNX2X_CHIP_MASK_ALL, + SRC_REG_KEYRSS0_7, 40, 0xffffffff }, + { BNX2X_CHIP_MASK_ALL, + XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00, 4, 0x00000001 }, + { BNX2X_CHIP_MASK_ALL, + XCM_REG_WU_DA_CNT_CMD00, 4, 0x00000003 }, + { BNX2X_CHIP_MASK_ALL, + XCM_REG_GLB_DEL_ACK_MAX_CNT_0, 4, 0x000000ff }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_LLH0_T_BIT, 4, 0x00000001 }, +/* 20 */ { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2, + NIG_REG_EMAC0_IN_EN, 4, 0x00000001 }, + { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2, + NIG_REG_BMAC0_IN_EN, 4, 0x00000001 }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_XCM0_OUT_EN, 4, 0x00000001 }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_BRB0_OUT_EN, 4, 0x00000001 }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_LLH0_XCM_MASK, 4, 0x00000007 }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_LLH0_ACPI_PAT_6_LEN, 68, 0x000000ff }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_LLH0_ACPI_PAT_0_CRC, 68, 0xffffffff }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_LLH0_DEST_MAC_0_0, 160, 0xffffffff }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_LLH0_DEST_IP_0_1, 160, 0xffffffff }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_LLH0_IPV4_IPV6_0, 160, 0x00000001 }, +/* 30 */ { BNX2X_CHIP_MASK_ALL, + NIG_REG_LLH0_DEST_UDP_0, 160, 0x0000ffff }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_LLH0_DEST_TCP_0, 160, 0x0000ffff }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_LLH0_VLAN_ID_0, 160, 0x00000fff }, + { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2, + NIG_REG_XGXS_SERDES0_MODE_SEL, 4, 0x00000001 }, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0, 4, 0x00000001}, + { BNX2X_CHIP_MASK_ALL, + NIG_REG_STATUS_INTERRUPT_PORT0, 4, 0x07ffffff }, + { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2, + NIG_REG_XGXS0_CTRL_EXTREMOTEMDIOST, 24, 0x00000001 }, + { BNX2X_CHIP_MASK_E1X | BNX2X_CHIP_MASK_E2, + NIG_REG_SERDES0_CTRL_PHY_ADDR, 16, 0x0000001f }, + + { BNX2X_CHIP_MASK_ALL, 0xffffffff, 0, 0x00000000 } + }; + + if (!netif_running(bp->dev)) + return rc; + + if (CHIP_IS_E1(bp)) + hw = BNX2X_CHIP_MASK_E1; + else if (CHIP_IS_E1H(bp)) + hw = BNX2X_CHIP_MASK_E1H; + else if (CHIP_IS_E2(bp)) + hw = BNX2X_CHIP_MASK_E2; + else if (CHIP_IS_E3B0(bp)) + hw = BNX2X_CHIP_MASK_E3B0; + else /* e3 A0 */ + hw = BNX2X_CHIP_MASK_E3; + + /* Repeat the test twice: + First by writing 0x00000000, second by writing 0xffffffff */ + for (idx = 0; idx < 2; idx++) { + + switch (idx) { + case 0: + wr_val = 0; + break; + case 1: + wr_val = 0xffffffff; + break; + } + + for (i = 0; reg_tbl[i].offset0 != 0xffffffff; i++) { + u32 offset, mask, save_val, val; + if (!(hw & reg_tbl[i].hw)) + continue; + + offset = reg_tbl[i].offset0 + port*reg_tbl[i].offset1; + mask = reg_tbl[i].mask; + + save_val = REG_RD(bp, offset); + + REG_WR(bp, offset, wr_val & mask); + + val = REG_RD(bp, offset); + + /* Restore the original register's value */ + REG_WR(bp, offset, save_val); + + /* verify value is as expected */ + if ((val & mask) != (wr_val & mask)) { + DP(NETIF_MSG_HW, + "offset 0x%x: val 0x%x != 0x%x mask 0x%x\n", + offset, val, wr_val, mask); + goto test_reg_exit; + } + } + } + + rc = 0; + +test_reg_exit: + return rc; +} + +static int bnx2x_test_memory(struct bnx2x *bp) +{ + int i, j, rc = -ENODEV; + u32 val, index; + static const struct { + u32 offset; + int size; + } mem_tbl[] = { + { CCM_REG_XX_DESCR_TABLE, CCM_REG_XX_DESCR_TABLE_SIZE }, + { CFC_REG_ACTIVITY_COUNTER, CFC_REG_ACTIVITY_COUNTER_SIZE }, + { CFC_REG_LINK_LIST, CFC_REG_LINK_LIST_SIZE }, + { DMAE_REG_CMD_MEM, DMAE_REG_CMD_MEM_SIZE }, + { TCM_REG_XX_DESCR_TABLE, TCM_REG_XX_DESCR_TABLE_SIZE }, + { UCM_REG_XX_DESCR_TABLE, UCM_REG_XX_DESCR_TABLE_SIZE }, + { XCM_REG_XX_DESCR_TABLE, XCM_REG_XX_DESCR_TABLE_SIZE }, + + { 0xffffffff, 0 } + }; + + static const struct { + char *name; + u32 offset; + u32 hw_mask[BNX2X_CHIP_MAX_OFST]; + } prty_tbl[] = { + { "CCM_PRTY_STS", CCM_REG_CCM_PRTY_STS, + {0x3ffc0, 0, 0, 0} }, + { "CFC_PRTY_STS", CFC_REG_CFC_PRTY_STS, + {0x2, 0x2, 0, 0} }, + { "DMAE_PRTY_STS", DMAE_REG_DMAE_PRTY_STS, + {0, 0, 0, 0} }, + { "TCM_PRTY_STS", TCM_REG_TCM_PRTY_STS, + {0x3ffc0, 0, 0, 0} }, + { "UCM_PRTY_STS", UCM_REG_UCM_PRTY_STS, + {0x3ffc0, 0, 0, 0} }, + { "XCM_PRTY_STS", XCM_REG_XCM_PRTY_STS, + {0x3ffc1, 0, 0, 0} }, + + { NULL, 0xffffffff, {0, 0, 0, 0} } + }; + + if (!netif_running(bp->dev)) + return rc; + + if (CHIP_IS_E1(bp)) + index = BNX2X_CHIP_E1_OFST; + else if (CHIP_IS_E1H(bp)) + index = BNX2X_CHIP_E1H_OFST; + else if (CHIP_IS_E2(bp)) + index = BNX2X_CHIP_E2_OFST; + else /* e3 */ + index = BNX2X_CHIP_E3_OFST; + + /* pre-Check the parity status */ + for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) { + val = REG_RD(bp, prty_tbl[i].offset); + if (val & ~(prty_tbl[i].hw_mask[index])) { + DP(NETIF_MSG_HW, + "%s is 0x%x\n", prty_tbl[i].name, val); + goto test_mem_exit; + } + } + + /* Go through all the memories */ + for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) + for (j = 0; j < mem_tbl[i].size; j++) + REG_RD(bp, mem_tbl[i].offset + j*4); + + /* Check the parity status */ + for (i = 0; prty_tbl[i].offset != 0xffffffff; i++) { + val = REG_RD(bp, prty_tbl[i].offset); + if (val & ~(prty_tbl[i].hw_mask[index])) { + DP(NETIF_MSG_HW, + "%s is 0x%x\n", prty_tbl[i].name, val); + goto test_mem_exit; + } + } + + rc = 0; + +test_mem_exit: + return rc; +} + +static void bnx2x_wait_for_link(struct bnx2x *bp, u8 link_up, u8 is_serdes) +{ + int cnt = 1400; + + if (link_up) { + while (bnx2x_link_test(bp, is_serdes) && cnt--) + msleep(20); + + if (cnt <= 0 && bnx2x_link_test(bp, is_serdes)) + DP(NETIF_MSG_LINK, "Timeout waiting for link up\n"); + } +} + +static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode) +{ + unsigned int pkt_size, num_pkts, i; + struct sk_buff *skb; + unsigned char *packet; + struct bnx2x_fastpath *fp_rx = &bp->fp[0]; + struct bnx2x_fastpath *fp_tx = &bp->fp[0]; + struct bnx2x_fp_txdata *txdata = &fp_tx->txdata[0]; + u16 tx_start_idx, tx_idx; + u16 rx_start_idx, rx_idx; + u16 pkt_prod, bd_prod, rx_comp_cons; + struct sw_tx_bd *tx_buf; + struct eth_tx_start_bd *tx_start_bd; + struct eth_tx_parse_bd_e1x *pbd_e1x = NULL; + struct eth_tx_parse_bd_e2 *pbd_e2 = NULL; + dma_addr_t mapping; + union eth_rx_cqe *cqe; + u8 cqe_fp_flags, cqe_fp_type; + struct sw_rx_bd *rx_buf; + u16 len; + int rc = -ENODEV; + + /* check the loopback mode */ + switch (loopback_mode) { + case BNX2X_PHY_LOOPBACK: + if (bp->link_params.loopback_mode != LOOPBACK_XGXS) + return -EINVAL; + break; + case BNX2X_MAC_LOOPBACK: + bp->link_params.loopback_mode = CHIP_IS_E3(bp) ? + LOOPBACK_XMAC : LOOPBACK_BMAC; + bnx2x_phy_init(&bp->link_params, &bp->link_vars); + break; + default: + return -EINVAL; + } + + /* prepare the loopback packet */ + pkt_size = (((bp->dev->mtu < ETH_MAX_PACKET_SIZE) ? + bp->dev->mtu : ETH_MAX_PACKET_SIZE) + ETH_HLEN); + skb = netdev_alloc_skb(bp->dev, fp_rx->rx_buf_size); + if (!skb) { + rc = -ENOMEM; + goto test_loopback_exit; + } + packet = skb_put(skb, pkt_size); + memcpy(packet, bp->dev->dev_addr, ETH_ALEN); + memset(packet + ETH_ALEN, 0, ETH_ALEN); + memset(packet + 2*ETH_ALEN, 0x77, (ETH_HLEN - 2*ETH_ALEN)); + for (i = ETH_HLEN; i < pkt_size; i++) + packet[i] = (unsigned char) (i & 0xff); + mapping = dma_map_single(&bp->pdev->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { + rc = -ENOMEM; + dev_kfree_skb(skb); + BNX2X_ERR("Unable to map SKB\n"); + goto test_loopback_exit; + } + + /* send the loopback packet */ + num_pkts = 0; + tx_start_idx = le16_to_cpu(*txdata->tx_cons_sb); + rx_start_idx = le16_to_cpu(*fp_rx->rx_cons_sb); + + pkt_prod = txdata->tx_pkt_prod++; + tx_buf = &txdata->tx_buf_ring[TX_BD(pkt_prod)]; + tx_buf->first_bd = txdata->tx_bd_prod; + tx_buf->skb = skb; + tx_buf->flags = 0; + + bd_prod = TX_BD(txdata->tx_bd_prod); + tx_start_bd = &txdata->tx_desc_ring[bd_prod].start_bd; + tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); + tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); + tx_start_bd->nbd = cpu_to_le16(2); /* start + pbd */ + tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb)); + tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod); + tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; + SET_FLAG(tx_start_bd->general_data, + ETH_TX_START_BD_ETH_ADDR_TYPE, + UNICAST_ADDRESS); + SET_FLAG(tx_start_bd->general_data, + ETH_TX_START_BD_HDR_NBDS, + 1); + + /* turn on parsing and get a BD */ + bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); + + pbd_e1x = &txdata->tx_desc_ring[bd_prod].parse_bd_e1x; + pbd_e2 = &txdata->tx_desc_ring[bd_prod].parse_bd_e2; + + memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2)); + memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x)); + + wmb(); + + txdata->tx_db.data.prod += 2; + barrier(); + DOORBELL(bp, txdata->cid, txdata->tx_db.raw); + + mmiowb(); + barrier(); + + num_pkts++; + txdata->tx_bd_prod += 2; /* start + pbd */ + + udelay(100); + + tx_idx = le16_to_cpu(*txdata->tx_cons_sb); + if (tx_idx != tx_start_idx + num_pkts) + goto test_loopback_exit; + + /* Unlike HC IGU won't generate an interrupt for status block + * updates that have been performed while interrupts were + * disabled. + */ + if (bp->common.int_block == INT_BLOCK_IGU) { + /* Disable local BHes to prevent a dead-lock situation between + * sch_direct_xmit() and bnx2x_run_loopback() (calling + * bnx2x_tx_int()), as both are taking netif_tx_lock(). + */ + local_bh_disable(); + bnx2x_tx_int(bp, txdata); + local_bh_enable(); + } + + rx_idx = le16_to_cpu(*fp_rx->rx_cons_sb); + if (rx_idx != rx_start_idx + num_pkts) + goto test_loopback_exit; + + rx_comp_cons = le16_to_cpu(fp_rx->rx_comp_cons); + cqe = &fp_rx->rx_comp_ring[RCQ_BD(rx_comp_cons)]; + cqe_fp_flags = cqe->fast_path_cqe.type_error_flags; + cqe_fp_type = cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE; + if (!CQE_TYPE_FAST(cqe_fp_type) || (cqe_fp_flags & ETH_RX_ERROR_FALGS)) + goto test_loopback_rx_exit; + + len = le16_to_cpu(cqe->fast_path_cqe.pkt_len); + if (len != pkt_size) + goto test_loopback_rx_exit; + + rx_buf = &fp_rx->rx_buf_ring[RX_BD(fp_rx->rx_bd_cons)]; + dma_sync_single_for_cpu(&bp->pdev->dev, + dma_unmap_addr(rx_buf, mapping), + fp_rx->rx_buf_size, DMA_FROM_DEVICE); + skb = rx_buf->skb; + skb_reserve(skb, cqe->fast_path_cqe.placement_offset); + for (i = ETH_HLEN; i < pkt_size; i++) + if (*(skb->data + i) != (unsigned char) (i & 0xff)) + goto test_loopback_rx_exit; + + rc = 0; + +test_loopback_rx_exit: + + fp_rx->rx_bd_cons = NEXT_RX_IDX(fp_rx->rx_bd_cons); + fp_rx->rx_bd_prod = NEXT_RX_IDX(fp_rx->rx_bd_prod); + fp_rx->rx_comp_cons = NEXT_RCQ_IDX(fp_rx->rx_comp_cons); + fp_rx->rx_comp_prod = NEXT_RCQ_IDX(fp_rx->rx_comp_prod); + + /* Update producers */ + bnx2x_update_rx_prod(bp, fp_rx, fp_rx->rx_bd_prod, fp_rx->rx_comp_prod, + fp_rx->rx_sge_prod); + +test_loopback_exit: + bp->link_params.loopback_mode = LOOPBACK_NONE; + + return rc; +} + +static int bnx2x_test_loopback(struct bnx2x *bp) +{ + int rc = 0, res; + + if (BP_NOMCP(bp)) + return rc; + + if (!netif_running(bp->dev)) + return BNX2X_LOOPBACK_FAILED; + + bnx2x_netif_stop(bp, 1); + bnx2x_acquire_phy_lock(bp); + + res = bnx2x_run_loopback(bp, BNX2X_PHY_LOOPBACK); + if (res) { + DP(NETIF_MSG_PROBE, " PHY loopback failed (res %d)\n", res); + rc |= BNX2X_PHY_LOOPBACK_FAILED; + } + + res = bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK); + if (res) { + DP(NETIF_MSG_PROBE, " MAC loopback failed (res %d)\n", res); + rc |= BNX2X_MAC_LOOPBACK_FAILED; + } + + bnx2x_release_phy_lock(bp); + bnx2x_netif_start(bp); + + return rc; +} + +#define CRC32_RESIDUAL 0xdebb20e3 + +static int bnx2x_test_nvram(struct bnx2x *bp) +{ + static const struct { + int offset; + int size; + } nvram_tbl[] = { + { 0, 0x14 }, /* bootstrap */ + { 0x14, 0xec }, /* dir */ + { 0x100, 0x350 }, /* manuf_info */ + { 0x450, 0xf0 }, /* feature_info */ + { 0x640, 0x64 }, /* upgrade_key_info */ + { 0x708, 0x70 }, /* manuf_key_info */ + { 0, 0 } + }; + __be32 buf[0x350 / 4]; + u8 *data = (u8 *)buf; + int i, rc; + u32 magic, crc; + + if (BP_NOMCP(bp)) + return 0; + + rc = bnx2x_nvram_read(bp, 0, data, 4); + if (rc) { + DP(NETIF_MSG_PROBE, "magic value read (rc %d)\n", rc); + goto test_nvram_exit; + } + + magic = be32_to_cpu(buf[0]); + if (magic != 0x669955aa) { + DP(NETIF_MSG_PROBE, "magic value (0x%08x)\n", magic); + rc = -ENODEV; + goto test_nvram_exit; + } + + for (i = 0; nvram_tbl[i].size; i++) { + + rc = bnx2x_nvram_read(bp, nvram_tbl[i].offset, data, + nvram_tbl[i].size); + if (rc) { + DP(NETIF_MSG_PROBE, + "nvram_tbl[%d] read data (rc %d)\n", i, rc); + goto test_nvram_exit; + } + + crc = ether_crc_le(nvram_tbl[i].size, data); + if (crc != CRC32_RESIDUAL) { + DP(NETIF_MSG_PROBE, + "nvram_tbl[%d] crc value (0x%08x)\n", i, crc); + rc = -ENODEV; + goto test_nvram_exit; + } + } + +test_nvram_exit: + return rc; +} + +/* Send an EMPTY ramrod on the first queue */ +static int bnx2x_test_intr(struct bnx2x *bp) +{ + struct bnx2x_queue_state_params params = {0}; + + if (!netif_running(bp->dev)) + return -ENODEV; + + params.q_obj = &bp->fp->q_obj; + params.cmd = BNX2X_Q_CMD_EMPTY; + + __set_bit(RAMROD_COMP_WAIT, ¶ms.ramrod_flags); + + return bnx2x_queue_state_change(bp, ¶ms); +} + +static void bnx2x_self_test(struct net_device *dev, + struct ethtool_test *etest, u64 *buf) +{ + struct bnx2x *bp = netdev_priv(dev); + u8 is_serdes; + if (bp->recovery_state != BNX2X_RECOVERY_DONE) { + printk(KERN_ERR "Handling parity error recovery. Try again later\n"); + etest->flags |= ETH_TEST_FL_FAILED; + return; + } + + memset(buf, 0, sizeof(u64) * BNX2X_NUM_TESTS); + + if (!netif_running(dev)) + return; + + /* offline tests are not supported in MF mode */ + if (IS_MF(bp)) + etest->flags &= ~ETH_TEST_FL_OFFLINE; + is_serdes = (bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) > 0; + + if (etest->flags & ETH_TEST_FL_OFFLINE) { + int port = BP_PORT(bp); + u32 val; + u8 link_up; + + /* save current value of input enable for TX port IF */ + val = REG_RD(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4); + /* disable input for TX port IF */ + REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, 0); + + link_up = bp->link_vars.link_up; + + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + bnx2x_nic_load(bp, LOAD_DIAG); + /* wait until link state is restored */ + bnx2x_wait_for_link(bp, 1, is_serdes); + + if (bnx2x_test_registers(bp) != 0) { + buf[0] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + if (bnx2x_test_memory(bp) != 0) { + buf[1] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + + buf[2] = bnx2x_test_loopback(bp); + if (buf[2] != 0) + etest->flags |= ETH_TEST_FL_FAILED; + + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + + /* restore input for TX port IF */ + REG_WR(bp, NIG_REG_EGRESS_UMP0_IN_EN + port*4, val); + + bnx2x_nic_load(bp, LOAD_NORMAL); + /* wait until link state is restored */ + bnx2x_wait_for_link(bp, link_up, is_serdes); + } + if (bnx2x_test_nvram(bp) != 0) { + buf[3] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + if (bnx2x_test_intr(bp) != 0) { + buf[4] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + + if (bnx2x_link_test(bp, is_serdes) != 0) { + buf[5] = 1; + etest->flags |= ETH_TEST_FL_FAILED; + } + +#ifdef BNX2X_EXTRA_DEBUG + bnx2x_panic_dump(bp); +#endif +} + +#define IS_PORT_STAT(i) \ + ((bnx2x_stats_arr[i].flags & STATS_FLAGS_BOTH) == STATS_FLAGS_PORT) +#define IS_FUNC_STAT(i) (bnx2x_stats_arr[i].flags & STATS_FLAGS_FUNC) +#define IS_MF_MODE_STAT(bp) \ + (IS_MF(bp) && !(bp->msg_enable & BNX2X_MSG_STATS)) + +/* ethtool statistics are displayed for all regular ethernet queues and the + * fcoe L2 queue if not disabled + */ +static inline int bnx2x_num_stat_queues(struct bnx2x *bp) +{ + return BNX2X_NUM_ETH_QUEUES(bp); +} + +static int bnx2x_get_sset_count(struct net_device *dev, int stringset) +{ + struct bnx2x *bp = netdev_priv(dev); + int i, num_stats; + + switch (stringset) { + case ETH_SS_STATS: + if (is_multi(bp)) { + num_stats = bnx2x_num_stat_queues(bp) * + BNX2X_NUM_Q_STATS; + if (!IS_MF_MODE_STAT(bp)) + num_stats += BNX2X_NUM_STATS; + } else { + if (IS_MF_MODE_STAT(bp)) { + num_stats = 0; + for (i = 0; i < BNX2X_NUM_STATS; i++) + if (IS_FUNC_STAT(i)) + num_stats++; + } else + num_stats = BNX2X_NUM_STATS; + } + return num_stats; + + case ETH_SS_TEST: + return BNX2X_NUM_TESTS; + + default: + return -EINVAL; + } +} + +static void bnx2x_get_strings(struct net_device *dev, u32 stringset, u8 *buf) +{ + struct bnx2x *bp = netdev_priv(dev); + int i, j, k; + char queue_name[MAX_QUEUE_NAME_LEN+1]; + + switch (stringset) { + case ETH_SS_STATS: + if (is_multi(bp)) { + k = 0; + for_each_eth_queue(bp, i) { + memset(queue_name, 0, sizeof(queue_name)); + sprintf(queue_name, "%d", i); + for (j = 0; j < BNX2X_NUM_Q_STATS; j++) + snprintf(buf + (k + j)*ETH_GSTRING_LEN, + ETH_GSTRING_LEN, + bnx2x_q_stats_arr[j].string, + queue_name); + k += BNX2X_NUM_Q_STATS; + } + if (IS_MF_MODE_STAT(bp)) + break; + for (j = 0; j < BNX2X_NUM_STATS; j++) + strcpy(buf + (k + j)*ETH_GSTRING_LEN, + bnx2x_stats_arr[j].string); + } else { + for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) { + if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i)) + continue; + strcpy(buf + j*ETH_GSTRING_LEN, + bnx2x_stats_arr[i].string); + j++; + } + } + break; + + case ETH_SS_TEST: + memcpy(buf, bnx2x_tests_str_arr, sizeof(bnx2x_tests_str_arr)); + break; + } +} + +static void bnx2x_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *buf) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 *hw_stats, *offset; + int i, j, k; + + if (is_multi(bp)) { + k = 0; + for_each_eth_queue(bp, i) { + hw_stats = (u32 *)&bp->fp[i].eth_q_stats; + for (j = 0; j < BNX2X_NUM_Q_STATS; j++) { + if (bnx2x_q_stats_arr[j].size == 0) { + /* skip this counter */ + buf[k + j] = 0; + continue; + } + offset = (hw_stats + + bnx2x_q_stats_arr[j].offset); + if (bnx2x_q_stats_arr[j].size == 4) { + /* 4-byte counter */ + buf[k + j] = (u64) *offset; + continue; + } + /* 8-byte counter */ + buf[k + j] = HILO_U64(*offset, *(offset + 1)); + } + k += BNX2X_NUM_Q_STATS; + } + if (IS_MF_MODE_STAT(bp)) + return; + hw_stats = (u32 *)&bp->eth_stats; + for (j = 0; j < BNX2X_NUM_STATS; j++) { + if (bnx2x_stats_arr[j].size == 0) { + /* skip this counter */ + buf[k + j] = 0; + continue; + } + offset = (hw_stats + bnx2x_stats_arr[j].offset); + if (bnx2x_stats_arr[j].size == 4) { + /* 4-byte counter */ + buf[k + j] = (u64) *offset; + continue; + } + /* 8-byte counter */ + buf[k + j] = HILO_U64(*offset, *(offset + 1)); + } + } else { + hw_stats = (u32 *)&bp->eth_stats; + for (i = 0, j = 0; i < BNX2X_NUM_STATS; i++) { + if (IS_MF_MODE_STAT(bp) && IS_PORT_STAT(i)) + continue; + if (bnx2x_stats_arr[i].size == 0) { + /* skip this counter */ + buf[j] = 0; + j++; + continue; + } + offset = (hw_stats + bnx2x_stats_arr[i].offset); + if (bnx2x_stats_arr[i].size == 4) { + /* 4-byte counter */ + buf[j] = (u64) *offset; + j++; + continue; + } + /* 8-byte counter */ + buf[j] = HILO_U64(*offset, *(offset + 1)); + j++; + } + } +} + +static int bnx2x_set_phys_id(struct net_device *dev, + enum ethtool_phys_id_state state) +{ + struct bnx2x *bp = netdev_priv(dev); + + if (!netif_running(dev)) + return -EAGAIN; + + if (!bp->port.pmf) + return -EOPNOTSUPP; + + switch (state) { + case ETHTOOL_ID_ACTIVE: + return 1; /* cycle on/off once per second */ + + case ETHTOOL_ID_ON: + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_ON, SPEED_1000); + break; + + case ETHTOOL_ID_OFF: + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_FRONT_PANEL_OFF, 0); + + break; + + case ETHTOOL_ID_INACTIVE: + bnx2x_set_led(&bp->link_params, &bp->link_vars, + LED_MODE_OPER, + bp->link_vars.line_speed); + } + + return 0; +} + +static int bnx2x_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *info, + void *rules __always_unused) +{ + struct bnx2x *bp = netdev_priv(dev); + + switch (info->cmd) { + case ETHTOOL_GRXRINGS: + info->data = BNX2X_NUM_ETH_QUEUES(bp); + return 0; + + default: + return -EOPNOTSUPP; + } +} + +static int bnx2x_get_rxfh_indir(struct net_device *dev, + struct ethtool_rxfh_indir *indir) +{ + struct bnx2x *bp = netdev_priv(dev); + size_t copy_size = + min_t(size_t, indir->size, T_ETH_INDIRECTION_TABLE_SIZE); + u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; + size_t i; + + if (bp->multi_mode == ETH_RSS_MODE_DISABLED) + return -EOPNOTSUPP; + + /* Get the current configuration of the RSS indirection table */ + bnx2x_get_rss_ind_table(&bp->rss_conf_obj, ind_table); + + /* + * We can't use a memcpy() as an internal storage of an + * indirection table is a u8 array while indir->ring_index + * points to an array of u32. + * + * Indirection table contains the FW Client IDs, so we need to + * align the returned table to the Client ID of the leading RSS + * queue. + */ + for (i = 0; i < copy_size; i++) + indir->ring_index[i] = ind_table[i] - bp->fp->cl_id; + + indir->size = T_ETH_INDIRECTION_TABLE_SIZE; + + return 0; +} + +static int bnx2x_set_rxfh_indir(struct net_device *dev, + const struct ethtool_rxfh_indir *indir) +{ + struct bnx2x *bp = netdev_priv(dev); + size_t i; + u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; + u32 num_eth_queues = BNX2X_NUM_ETH_QUEUES(bp); + + if (bp->multi_mode == ETH_RSS_MODE_DISABLED) + return -EOPNOTSUPP; + + /* validate the size */ + if (indir->size != T_ETH_INDIRECTION_TABLE_SIZE) + return -EINVAL; + + for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { + /* validate the indices */ + if (indir->ring_index[i] >= num_eth_queues) + return -EINVAL; + /* + * The same as in bnx2x_get_rxfh_indir: we can't use a memcpy() + * as an internal storage of an indirection table is a u8 array + * while indir->ring_index points to an array of u32. + * + * Indirection table contains the FW Client IDs, so we need to + * align the received table to the Client ID of the leading RSS + * queue + */ + ind_table[i] = indir->ring_index[i] + bp->fp->cl_id; + } + + return bnx2x_config_rss_pf(bp, ind_table, false); +} + +static const struct ethtool_ops bnx2x_ethtool_ops = { + .get_settings = bnx2x_get_settings, + .set_settings = bnx2x_set_settings, + .get_drvinfo = bnx2x_get_drvinfo, + .get_regs_len = bnx2x_get_regs_len, + .get_regs = bnx2x_get_regs, + .get_wol = bnx2x_get_wol, + .set_wol = bnx2x_set_wol, + .get_msglevel = bnx2x_get_msglevel, + .set_msglevel = bnx2x_set_msglevel, + .nway_reset = bnx2x_nway_reset, + .get_link = bnx2x_get_link, + .get_eeprom_len = bnx2x_get_eeprom_len, + .get_eeprom = bnx2x_get_eeprom, + .set_eeprom = bnx2x_set_eeprom, + .get_coalesce = bnx2x_get_coalesce, + .set_coalesce = bnx2x_set_coalesce, + .get_ringparam = bnx2x_get_ringparam, + .set_ringparam = bnx2x_set_ringparam, + .get_pauseparam = bnx2x_get_pauseparam, + .set_pauseparam = bnx2x_set_pauseparam, + .self_test = bnx2x_self_test, + .get_sset_count = bnx2x_get_sset_count, + .get_strings = bnx2x_get_strings, + .set_phys_id = bnx2x_set_phys_id, + .get_ethtool_stats = bnx2x_get_ethtool_stats, + .get_rxnfc = bnx2x_get_rxnfc, + .get_rxfh_indir = bnx2x_get_rxfh_indir, + .set_rxfh_indir = bnx2x_set_rxfh_indir, +}; + +void bnx2x_set_ethtool_ops(struct net_device *netdev) +{ + SET_ETHTOOL_OPS(netdev, &bnx2x_ethtool_ops); +} diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h new file mode 100644 index 000000000000..998652a1b858 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h @@ -0,0 +1,410 @@ +/* bnx2x_fw_defs.h: Broadcom Everest network driver. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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. + */ + +#ifndef BNX2X_FW_DEFS_H +#define BNX2X_FW_DEFS_H + +#define CSTORM_ASSERT_LIST_INDEX_OFFSET (IRO[148].base) +#define CSTORM_ASSERT_LIST_OFFSET(assertListEntry) \ + (IRO[147].base + ((assertListEntry) * IRO[147].m1)) +#define CSTORM_EVENT_RING_DATA_OFFSET(pfId) \ + (IRO[153].base + (((pfId)>>1) * IRO[153].m1) + (((pfId)&1) * \ + IRO[153].m2)) +#define CSTORM_EVENT_RING_PROD_OFFSET(pfId) \ + (IRO[154].base + (((pfId)>>1) * IRO[154].m1) + (((pfId)&1) * \ + IRO[154].m2)) +#define CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(funcId) \ + (IRO[159].base + ((funcId) * IRO[159].m1)) +#define CSTORM_FUNC_EN_OFFSET(funcId) \ + (IRO[149].base + ((funcId) * IRO[149].m1)) +#define CSTORM_IGU_MODE_OFFSET (IRO[157].base) +#define CSTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \ + (IRO[315].base + ((pfId) * IRO[315].m1)) +#define CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \ + (IRO[316].base + ((pfId) * IRO[316].m1)) +#define CSTORM_ISCSI_EQ_CONS_OFFSET(pfId, iscsiEqId) \ + (IRO[308].base + ((pfId) * IRO[308].m1) + ((iscsiEqId) * IRO[308].m2)) +#define CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(pfId, iscsiEqId) \ + (IRO[310].base + ((pfId) * IRO[310].m1) + ((iscsiEqId) * IRO[310].m2)) +#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(pfId, iscsiEqId) \ + (IRO[309].base + ((pfId) * IRO[309].m1) + ((iscsiEqId) * IRO[309].m2)) +#define CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(pfId, iscsiEqId) \ + (IRO[311].base + ((pfId) * IRO[311].m1) + ((iscsiEqId) * IRO[311].m2)) +#define CSTORM_ISCSI_EQ_PROD_OFFSET(pfId, iscsiEqId) \ + (IRO[307].base + ((pfId) * IRO[307].m1) + ((iscsiEqId) * IRO[307].m2)) +#define CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(pfId, iscsiEqId) \ + (IRO[313].base + ((pfId) * IRO[313].m1) + ((iscsiEqId) * IRO[313].m2)) +#define CSTORM_ISCSI_EQ_SB_NUM_OFFSET(pfId, iscsiEqId) \ + (IRO[312].base + ((pfId) * IRO[312].m1) + ((iscsiEqId) * IRO[312].m2)) +#define CSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \ + (IRO[314].base + ((pfId) * IRO[314].m1)) +#define CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ + (IRO[306].base + ((pfId) * IRO[306].m1)) +#define CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ + (IRO[305].base + ((pfId) * IRO[305].m1)) +#define CSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ + (IRO[304].base + ((pfId) * IRO[304].m1)) +#define CSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ + (IRO[151].base + ((funcId) * IRO[151].m1)) +#define CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(pfId) \ + (IRO[142].base + ((pfId) * IRO[142].m1)) +#define CSTORM_SP_STATUS_BLOCK_DATA_STATE_OFFSET(pfId) \ + (IRO[143].base + ((pfId) * IRO[143].m1)) +#define CSTORM_SP_STATUS_BLOCK_OFFSET(pfId) \ + (IRO[141].base + ((pfId) * IRO[141].m1)) +#define CSTORM_SP_STATUS_BLOCK_SIZE (IRO[141].size) +#define CSTORM_SP_SYNC_BLOCK_OFFSET(pfId) \ + (IRO[144].base + ((pfId) * IRO[144].m1)) +#define CSTORM_SP_SYNC_BLOCK_SIZE (IRO[144].size) +#define CSTORM_STATUS_BLOCK_DATA_FLAGS_OFFSET(sbId, hcIndex) \ + (IRO[136].base + ((sbId) * IRO[136].m1) + ((hcIndex) * IRO[136].m2)) +#define CSTORM_STATUS_BLOCK_DATA_OFFSET(sbId) \ + (IRO[133].base + ((sbId) * IRO[133].m1)) +#define CSTORM_STATUS_BLOCK_DATA_STATE_OFFSET(sbId) \ + (IRO[134].base + ((sbId) * IRO[134].m1)) +#define CSTORM_STATUS_BLOCK_DATA_TIMEOUT_OFFSET(sbId, hcIndex) \ + (IRO[135].base + ((sbId) * IRO[135].m1) + ((hcIndex) * IRO[135].m2)) +#define CSTORM_STATUS_BLOCK_OFFSET(sbId) \ + (IRO[132].base + ((sbId) * IRO[132].m1)) +#define CSTORM_STATUS_BLOCK_SIZE (IRO[132].size) +#define CSTORM_SYNC_BLOCK_OFFSET(sbId) \ + (IRO[137].base + ((sbId) * IRO[137].m1)) +#define CSTORM_SYNC_BLOCK_SIZE (IRO[137].size) +#define CSTORM_VF_PF_CHANNEL_STATE_OFFSET(vfId) \ + (IRO[155].base + ((vfId) * IRO[155].m1)) +#define CSTORM_VF_PF_CHANNEL_VALID_OFFSET(vfId) \ + (IRO[156].base + ((vfId) * IRO[156].m1)) +#define CSTORM_VF_TO_PF_OFFSET(funcId) \ + (IRO[150].base + ((funcId) * IRO[150].m1)) +#define TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET (IRO[204].base) +#define TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(pfId) \ + (IRO[203].base + ((pfId) * IRO[203].m1)) +#define TSTORM_ASSERT_LIST_INDEX_OFFSET (IRO[102].base) +#define TSTORM_ASSERT_LIST_OFFSET(assertListEntry) \ + (IRO[101].base + ((assertListEntry) * IRO[101].m1)) +#define TSTORM_COMMON_SAFC_WORKAROUND_ENABLE_OFFSET (IRO[107].base) +#define TSTORM_COMMON_SAFC_WORKAROUND_TIMEOUT_10USEC_OFFSET \ + (IRO[108].base) +#define TSTORM_FUNCTION_COMMON_CONFIG_OFFSET(pfId) \ + (IRO[201].base + ((pfId) * IRO[201].m1)) +#define TSTORM_FUNC_EN_OFFSET(funcId) \ + (IRO[103].base + ((funcId) * IRO[103].m1)) +#define TSTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \ + (IRO[271].base + ((pfId) * IRO[271].m1)) +#define TSTORM_ISCSI_L2_ISCSI_OOO_CID_TABLE_OFFSET(pfId) \ + (IRO[272].base + ((pfId) * IRO[272].m1)) +#define TSTORM_ISCSI_L2_ISCSI_OOO_CLIENT_ID_TABLE_OFFSET(pfId) \ + (IRO[273].base + ((pfId) * IRO[273].m1)) +#define TSTORM_ISCSI_L2_ISCSI_OOO_PROD_OFFSET(pfId) \ + (IRO[274].base + ((pfId) * IRO[274].m1)) +#define TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ + (IRO[270].base + ((pfId) * IRO[270].m1)) +#define TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ + (IRO[269].base + ((pfId) * IRO[269].m1)) +#define TSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ + (IRO[268].base + ((pfId) * IRO[268].m1)) +#define TSTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \ + (IRO[267].base + ((pfId) * IRO[267].m1)) +#define TSTORM_ISCSI_TCP_LOCAL_ADV_WND_OFFSET(pfId) \ + (IRO[276].base + ((pfId) * IRO[276].m1)) +#define TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \ + (IRO[263].base + ((pfId) * IRO[263].m1)) +#define TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(pfId) \ + (IRO[264].base + ((pfId) * IRO[264].m1)) +#define TSTORM_ISCSI_TCP_VARS_MID_LOCAL_MAC_ADDR_OFFSET(pfId) \ + (IRO[265].base + ((pfId) * IRO[265].m1)) +#define TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(pfId) \ + (IRO[266].base + ((pfId) * IRO[266].m1)) +#define TSTORM_MAC_FILTER_CONFIG_OFFSET(pfId) \ + (IRO[202].base + ((pfId) * IRO[202].m1)) +#define TSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ + (IRO[105].base + ((funcId) * IRO[105].m1)) +#define TSTORM_TCP_MAX_CWND_OFFSET(pfId) \ + (IRO[216].base + ((pfId) * IRO[216].m1)) +#define TSTORM_VF_TO_PF_OFFSET(funcId) \ + (IRO[104].base + ((funcId) * IRO[104].m1)) +#define USTORM_AGG_DATA_OFFSET (IRO[206].base) +#define USTORM_AGG_DATA_SIZE (IRO[206].size) +#define USTORM_ASSERT_LIST_INDEX_OFFSET (IRO[177].base) +#define USTORM_ASSERT_LIST_OFFSET(assertListEntry) \ + (IRO[176].base + ((assertListEntry) * IRO[176].m1)) +#define USTORM_CQE_PAGE_NEXT_OFFSET(portId, clientId) \ + (IRO[205].base + ((portId) * IRO[205].m1) + ((clientId) * \ + IRO[205].m2)) +#define USTORM_ETH_PAUSE_ENABLED_OFFSET(portId) \ + (IRO[183].base + ((portId) * IRO[183].m1)) +#define USTORM_FCOE_EQ_PROD_OFFSET(pfId) \ + (IRO[317].base + ((pfId) * IRO[317].m1)) +#define USTORM_FUNC_EN_OFFSET(funcId) \ + (IRO[178].base + ((funcId) * IRO[178].m1)) +#define USTORM_ISCSI_CQ_SIZE_OFFSET(pfId) \ + (IRO[281].base + ((pfId) * IRO[281].m1)) +#define USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(pfId) \ + (IRO[282].base + ((pfId) * IRO[282].m1)) +#define USTORM_ISCSI_ERROR_BITMAP_OFFSET(pfId) \ + (IRO[286].base + ((pfId) * IRO[286].m1)) +#define USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(pfId) \ + (IRO[283].base + ((pfId) * IRO[283].m1)) +#define USTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ + (IRO[279].base + ((pfId) * IRO[279].m1)) +#define USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ + (IRO[278].base + ((pfId) * IRO[278].m1)) +#define USTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ + (IRO[277].base + ((pfId) * IRO[277].m1)) +#define USTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \ + (IRO[280].base + ((pfId) * IRO[280].m1)) +#define USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(pfId) \ + (IRO[284].base + ((pfId) * IRO[284].m1)) +#define USTORM_ISCSI_RQ_SIZE_OFFSET(pfId) \ + (IRO[285].base + ((pfId) * IRO[285].m1)) +#define USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(pfId) \ + (IRO[182].base + ((pfId) * IRO[182].m1)) +#define USTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ + (IRO[180].base + ((funcId) * IRO[180].m1)) +#define USTORM_RX_PRODS_E1X_OFFSET(portId, clientId) \ + (IRO[209].base + ((portId) * IRO[209].m1) + ((clientId) * \ + IRO[209].m2)) +#define USTORM_RX_PRODS_E2_OFFSET(qzoneId) \ + (IRO[210].base + ((qzoneId) * IRO[210].m1)) +#define USTORM_TPA_BTR_OFFSET (IRO[207].base) +#define USTORM_TPA_BTR_SIZE (IRO[207].size) +#define USTORM_VF_TO_PF_OFFSET(funcId) \ + (IRO[179].base + ((funcId) * IRO[179].m1)) +#define XSTORM_AGG_INT_FINAL_CLEANUP_COMP_TYPE (IRO[67].base) +#define XSTORM_AGG_INT_FINAL_CLEANUP_INDEX (IRO[66].base) +#define XSTORM_ASSERT_LIST_INDEX_OFFSET (IRO[51].base) +#define XSTORM_ASSERT_LIST_OFFSET(assertListEntry) \ + (IRO[50].base + ((assertListEntry) * IRO[50].m1)) +#define XSTORM_CMNG_PER_PORT_VARS_OFFSET(portId) \ + (IRO[43].base + ((portId) * IRO[43].m1)) +#define XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(pfId) \ + (IRO[45].base + ((pfId) * IRO[45].m1)) +#define XSTORM_FUNC_EN_OFFSET(funcId) \ + (IRO[47].base + ((funcId) * IRO[47].m1)) +#define XSTORM_ISCSI_HQ_SIZE_OFFSET(pfId) \ + (IRO[294].base + ((pfId) * IRO[294].m1)) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(pfId) \ + (IRO[297].base + ((pfId) * IRO[297].m1)) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(pfId) \ + (IRO[298].base + ((pfId) * IRO[298].m1)) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(pfId) \ + (IRO[299].base + ((pfId) * IRO[299].m1)) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(pfId) \ + (IRO[300].base + ((pfId) * IRO[300].m1)) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(pfId) \ + (IRO[301].base + ((pfId) * IRO[301].m1)) +#define XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(pfId) \ + (IRO[302].base + ((pfId) * IRO[302].m1)) +#define XSTORM_ISCSI_LOCAL_VLAN_OFFSET(pfId) \ + (IRO[303].base + ((pfId) * IRO[303].m1)) +#define XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(pfId) \ + (IRO[293].base + ((pfId) * IRO[293].m1)) +#define XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(pfId) \ + (IRO[292].base + ((pfId) * IRO[292].m1)) +#define XSTORM_ISCSI_PAGE_SIZE_OFFSET(pfId) \ + (IRO[291].base + ((pfId) * IRO[291].m1)) +#define XSTORM_ISCSI_R2TQ_SIZE_OFFSET(pfId) \ + (IRO[296].base + ((pfId) * IRO[296].m1)) +#define XSTORM_ISCSI_SQ_SIZE_OFFSET(pfId) \ + (IRO[295].base + ((pfId) * IRO[295].m1)) +#define XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(pfId) \ + (IRO[290].base + ((pfId) * IRO[290].m1)) +#define XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(pfId) \ + (IRO[289].base + ((pfId) * IRO[289].m1)) +#define XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(pfId) \ + (IRO[288].base + ((pfId) * IRO[288].m1)) +#define XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(pfId) \ + (IRO[287].base + ((pfId) * IRO[287].m1)) +#define XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(pfId) \ + (IRO[44].base + ((pfId) * IRO[44].m1)) +#define XSTORM_RECORD_SLOW_PATH_OFFSET(funcId) \ + (IRO[49].base + ((funcId) * IRO[49].m1)) +#define XSTORM_SPQ_DATA_OFFSET(funcId) \ + (IRO[32].base + ((funcId) * IRO[32].m1)) +#define XSTORM_SPQ_DATA_SIZE (IRO[32].size) +#define XSTORM_SPQ_PAGE_BASE_OFFSET(funcId) \ + (IRO[30].base + ((funcId) * IRO[30].m1)) +#define XSTORM_SPQ_PROD_OFFSET(funcId) \ + (IRO[31].base + ((funcId) * IRO[31].m1)) +#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(portId) \ + (IRO[211].base + ((portId) * IRO[211].m1)) +#define XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(portId) \ + (IRO[212].base + ((portId) * IRO[212].m1)) +#define XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(pfId) \ + (IRO[214].base + (((pfId)>>1) * IRO[214].m1) + (((pfId)&1) * \ + IRO[214].m2)) +#define XSTORM_VF_TO_PF_OFFSET(funcId) \ + (IRO[48].base + ((funcId) * IRO[48].m1)) +#define COMMON_ASM_INVALID_ASSERT_OPCODE 0x0 + +/** +* This file defines HSI constants for the ETH flow +*/ +#ifdef _EVEREST_MICROCODE +#include "Microcode\Generated\DataTypes\eth_rx_bd.h" +#include "Microcode\Generated\DataTypes\eth_tx_bd.h" +#include "Microcode\Generated\DataTypes\eth_rx_cqe.h" +#include "Microcode\Generated\DataTypes\eth_rx_sge.h" +#include "Microcode\Generated\DataTypes\eth_rx_cqe_next_page.h" +#endif + + +/* Ethernet Ring parameters */ +#define X_ETH_LOCAL_RING_SIZE 13 +#define FIRST_BD_IN_PKT 0 +#define PARSE_BD_INDEX 1 +#define NUM_OF_ETH_BDS_IN_PAGE ((PAGE_SIZE)/(STRUCT_SIZE(eth_tx_bd)/8)) +#define U_ETH_NUM_OF_SGES_TO_FETCH 8 +#define U_ETH_MAX_SGES_FOR_PACKET 3 + +/* Rx ring params */ +#define U_ETH_LOCAL_BD_RING_SIZE 8 +#define U_ETH_LOCAL_SGE_RING_SIZE 10 +#define U_ETH_SGL_SIZE 8 + /* The fw will padd the buffer with this value, so the IP header \ + will be align to 4 Byte */ +#define IP_HEADER_ALIGNMENT_PADDING 2 + +#define U_ETH_SGES_PER_PAGE_INVERSE_MASK \ + (0xFFFF - ((PAGE_SIZE/((STRUCT_SIZE(eth_rx_sge))/8))-1)) + +#define TU_ETH_CQES_PER_PAGE (PAGE_SIZE/(STRUCT_SIZE(eth_rx_cqe)/8)) +#define U_ETH_BDS_PER_PAGE (PAGE_SIZE/(STRUCT_SIZE(eth_rx_bd)/8)) +#define U_ETH_SGES_PER_PAGE (PAGE_SIZE/(STRUCT_SIZE(eth_rx_sge)/8)) + +#define U_ETH_BDS_PER_PAGE_MASK (U_ETH_BDS_PER_PAGE-1) +#define U_ETH_CQE_PER_PAGE_MASK (TU_ETH_CQES_PER_PAGE-1) +#define U_ETH_SGES_PER_PAGE_MASK (U_ETH_SGES_PER_PAGE-1) + +#define U_ETH_UNDEFINED_Q 0xFF + +#define T_ETH_INDIRECTION_TABLE_SIZE 128 +#define T_ETH_RSS_KEY 10 +#define ETH_NUM_OF_RSS_ENGINES_E2 72 + +#define FILTER_RULES_COUNT 16 +#define MULTICAST_RULES_COUNT 16 +#define CLASSIFY_RULES_COUNT 16 + +/*The CRC32 seed, that is used for the hash(reduction) multicast address */ +#define ETH_CRC32_HASH_SEED 0x00000000 + +#define ETH_CRC32_HASH_BIT_SIZE (8) +#define ETH_CRC32_HASH_MASK EVAL((1< + * Written by: Vladislav Zolotarov + * Based on the original idea of John Wright . + */ + +#ifndef BNX2X_INIT_FILE_HDR_H +#define BNX2X_INIT_FILE_HDR_H + +struct bnx2x_fw_file_section { + __be32 len; + __be32 offset; +}; + +struct bnx2x_fw_file_hdr { + struct bnx2x_fw_file_section init_ops; + struct bnx2x_fw_file_section init_ops_offsets; + struct bnx2x_fw_file_section init_data; + struct bnx2x_fw_file_section tsem_int_table_data; + struct bnx2x_fw_file_section tsem_pram_data; + struct bnx2x_fw_file_section usem_int_table_data; + struct bnx2x_fw_file_section usem_pram_data; + struct bnx2x_fw_file_section csem_int_table_data; + struct bnx2x_fw_file_section csem_pram_data; + struct bnx2x_fw_file_section xsem_int_table_data; + struct bnx2x_fw_file_section xsem_pram_data; + struct bnx2x_fw_file_section iro_arr; + struct bnx2x_fw_file_section fw_version; +}; + +#endif /* BNX2X_INIT_FILE_HDR_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h new file mode 100644 index 000000000000..dc24de40e336 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -0,0 +1,5131 @@ +/* bnx2x_hsi.h: Broadcom Everest network driver. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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. + */ +#ifndef BNX2X_HSI_H +#define BNX2X_HSI_H + +#include "bnx2x_fw_defs.h" + +#define FW_ENCODE_32BIT_PATTERN 0x1e1e1e1e + +struct license_key { + u32 reserved[6]; + + u32 max_iscsi_conn; +#define BNX2X_MAX_ISCSI_TRGT_CONN_MASK 0xFFFF +#define BNX2X_MAX_ISCSI_TRGT_CONN_SHIFT 0 +#define BNX2X_MAX_ISCSI_INIT_CONN_MASK 0xFFFF0000 +#define BNX2X_MAX_ISCSI_INIT_CONN_SHIFT 16 + + u32 reserved_a; + + u32 max_fcoe_conn; +#define BNX2X_MAX_FCOE_TRGT_CONN_MASK 0xFFFF +#define BNX2X_MAX_FCOE_TRGT_CONN_SHIFT 0 +#define BNX2X_MAX_FCOE_INIT_CONN_MASK 0xFFFF0000 +#define BNX2X_MAX_FCOE_INIT_CONN_SHIFT 16 + + u32 reserved_b[4]; +}; + + +#define PORT_0 0 +#define PORT_1 1 +#define PORT_MAX 2 + +/**************************************************************************** + * Shared HW configuration * + ****************************************************************************/ +#define PIN_CFG_NA 0x00000000 +#define PIN_CFG_GPIO0_P0 0x00000001 +#define PIN_CFG_GPIO1_P0 0x00000002 +#define PIN_CFG_GPIO2_P0 0x00000003 +#define PIN_CFG_GPIO3_P0 0x00000004 +#define PIN_CFG_GPIO0_P1 0x00000005 +#define PIN_CFG_GPIO1_P1 0x00000006 +#define PIN_CFG_GPIO2_P1 0x00000007 +#define PIN_CFG_GPIO3_P1 0x00000008 +#define PIN_CFG_EPIO0 0x00000009 +#define PIN_CFG_EPIO1 0x0000000a +#define PIN_CFG_EPIO2 0x0000000b +#define PIN_CFG_EPIO3 0x0000000c +#define PIN_CFG_EPIO4 0x0000000d +#define PIN_CFG_EPIO5 0x0000000e +#define PIN_CFG_EPIO6 0x0000000f +#define PIN_CFG_EPIO7 0x00000010 +#define PIN_CFG_EPIO8 0x00000011 +#define PIN_CFG_EPIO9 0x00000012 +#define PIN_CFG_EPIO10 0x00000013 +#define PIN_CFG_EPIO11 0x00000014 +#define PIN_CFG_EPIO12 0x00000015 +#define PIN_CFG_EPIO13 0x00000016 +#define PIN_CFG_EPIO14 0x00000017 +#define PIN_CFG_EPIO15 0x00000018 +#define PIN_CFG_EPIO16 0x00000019 +#define PIN_CFG_EPIO17 0x0000001a +#define PIN_CFG_EPIO18 0x0000001b +#define PIN_CFG_EPIO19 0x0000001c +#define PIN_CFG_EPIO20 0x0000001d +#define PIN_CFG_EPIO21 0x0000001e +#define PIN_CFG_EPIO22 0x0000001f +#define PIN_CFG_EPIO23 0x00000020 +#define PIN_CFG_EPIO24 0x00000021 +#define PIN_CFG_EPIO25 0x00000022 +#define PIN_CFG_EPIO26 0x00000023 +#define PIN_CFG_EPIO27 0x00000024 +#define PIN_CFG_EPIO28 0x00000025 +#define PIN_CFG_EPIO29 0x00000026 +#define PIN_CFG_EPIO30 0x00000027 +#define PIN_CFG_EPIO31 0x00000028 + +/* EPIO definition */ +#define EPIO_CFG_NA 0x00000000 +#define EPIO_CFG_EPIO0 0x00000001 +#define EPIO_CFG_EPIO1 0x00000002 +#define EPIO_CFG_EPIO2 0x00000003 +#define EPIO_CFG_EPIO3 0x00000004 +#define EPIO_CFG_EPIO4 0x00000005 +#define EPIO_CFG_EPIO5 0x00000006 +#define EPIO_CFG_EPIO6 0x00000007 +#define EPIO_CFG_EPIO7 0x00000008 +#define EPIO_CFG_EPIO8 0x00000009 +#define EPIO_CFG_EPIO9 0x0000000a +#define EPIO_CFG_EPIO10 0x0000000b +#define EPIO_CFG_EPIO11 0x0000000c +#define EPIO_CFG_EPIO12 0x0000000d +#define EPIO_CFG_EPIO13 0x0000000e +#define EPIO_CFG_EPIO14 0x0000000f +#define EPIO_CFG_EPIO15 0x00000010 +#define EPIO_CFG_EPIO16 0x00000011 +#define EPIO_CFG_EPIO17 0x00000012 +#define EPIO_CFG_EPIO18 0x00000013 +#define EPIO_CFG_EPIO19 0x00000014 +#define EPIO_CFG_EPIO20 0x00000015 +#define EPIO_CFG_EPIO21 0x00000016 +#define EPIO_CFG_EPIO22 0x00000017 +#define EPIO_CFG_EPIO23 0x00000018 +#define EPIO_CFG_EPIO24 0x00000019 +#define EPIO_CFG_EPIO25 0x0000001a +#define EPIO_CFG_EPIO26 0x0000001b +#define EPIO_CFG_EPIO27 0x0000001c +#define EPIO_CFG_EPIO28 0x0000001d +#define EPIO_CFG_EPIO29 0x0000001e +#define EPIO_CFG_EPIO30 0x0000001f +#define EPIO_CFG_EPIO31 0x00000020 + + +struct shared_hw_cfg { /* NVRAM Offset */ + /* Up to 16 bytes of NULL-terminated string */ + u8 part_num[16]; /* 0x104 */ + + u32 config; /* 0x114 */ + #define SHARED_HW_CFG_MDIO_VOLTAGE_MASK 0x00000001 + #define SHARED_HW_CFG_MDIO_VOLTAGE_SHIFT 0 + #define SHARED_HW_CFG_MDIO_VOLTAGE_1_2V 0x00000000 + #define SHARED_HW_CFG_MDIO_VOLTAGE_2_5V 0x00000001 + #define SHARED_HW_CFG_MCP_RST_ON_CORE_RST_EN 0x00000002 + + #define SHARED_HW_CFG_PORT_SWAP 0x00000004 + + #define SHARED_HW_CFG_BEACON_WOL_EN 0x00000008 + + #define SHARED_HW_CFG_PCIE_GEN3_DISABLED 0x00000000 + #define SHARED_HW_CFG_PCIE_GEN3_ENABLED 0x00000010 + + #define SHARED_HW_CFG_MFW_SELECT_MASK 0x00000700 + #define SHARED_HW_CFG_MFW_SELECT_SHIFT 8 + /* Whatever MFW found in NVM + (if multiple found, priority order is: NC-SI, UMP, IPMI) */ + #define SHARED_HW_CFG_MFW_SELECT_DEFAULT 0x00000000 + #define SHARED_HW_CFG_MFW_SELECT_NC_SI 0x00000100 + #define SHARED_HW_CFG_MFW_SELECT_UMP 0x00000200 + #define SHARED_HW_CFG_MFW_SELECT_IPMI 0x00000300 + /* Use SPIO4 as an arbiter between: 0-NC_SI, 1-IPMI + (can only be used when an add-in board, not BMC, pulls-down SPIO4) */ + #define SHARED_HW_CFG_MFW_SELECT_SPIO4_NC_SI_IPMI 0x00000400 + /* Use SPIO4 as an arbiter between: 0-UMP, 1-IPMI + (can only be used when an add-in board, not BMC, pulls-down SPIO4) */ + #define SHARED_HW_CFG_MFW_SELECT_SPIO4_UMP_IPMI 0x00000500 + /* Use SPIO4 as an arbiter between: 0-NC-SI, 1-UMP + (can only be used when an add-in board, not BMC, pulls-down SPIO4) */ + #define SHARED_HW_CFG_MFW_SELECT_SPIO4_NC_SI_UMP 0x00000600 + + #define SHARED_HW_CFG_LED_MODE_MASK 0x000f0000 + #define SHARED_HW_CFG_LED_MODE_SHIFT 16 + #define SHARED_HW_CFG_LED_MAC1 0x00000000 + #define SHARED_HW_CFG_LED_PHY1 0x00010000 + #define SHARED_HW_CFG_LED_PHY2 0x00020000 + #define SHARED_HW_CFG_LED_PHY3 0x00030000 + #define SHARED_HW_CFG_LED_MAC2 0x00040000 + #define SHARED_HW_CFG_LED_PHY4 0x00050000 + #define SHARED_HW_CFG_LED_PHY5 0x00060000 + #define SHARED_HW_CFG_LED_PHY6 0x00070000 + #define SHARED_HW_CFG_LED_MAC3 0x00080000 + #define SHARED_HW_CFG_LED_PHY7 0x00090000 + #define SHARED_HW_CFG_LED_PHY9 0x000a0000 + #define SHARED_HW_CFG_LED_PHY11 0x000b0000 + #define SHARED_HW_CFG_LED_MAC4 0x000c0000 + #define SHARED_HW_CFG_LED_PHY8 0x000d0000 + #define SHARED_HW_CFG_LED_EXTPHY1 0x000e0000 + + + #define SHARED_HW_CFG_AN_ENABLE_MASK 0x3f000000 + #define SHARED_HW_CFG_AN_ENABLE_SHIFT 24 + #define SHARED_HW_CFG_AN_ENABLE_CL37 0x01000000 + #define SHARED_HW_CFG_AN_ENABLE_CL73 0x02000000 + #define SHARED_HW_CFG_AN_ENABLE_BAM 0x04000000 + #define SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION 0x08000000 + #define SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT 0x10000000 + #define SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY 0x20000000 + + #define SHARED_HW_CFG_SRIOV_MASK 0x40000000 + #define SHARED_HW_CFG_SRIOV_DISABLED 0x00000000 + #define SHARED_HW_CFG_SRIOV_ENABLED 0x40000000 + + #define SHARED_HW_CFG_ATC_MASK 0x80000000 + #define SHARED_HW_CFG_ATC_DISABLED 0x00000000 + #define SHARED_HW_CFG_ATC_ENABLED 0x80000000 + + u32 config2; /* 0x118 */ + /* one time auto detect grace period (in sec) */ + #define SHARED_HW_CFG_GRACE_PERIOD_MASK 0x000000ff + #define SHARED_HW_CFG_GRACE_PERIOD_SHIFT 0 + + #define SHARED_HW_CFG_PCIE_GEN2_ENABLED 0x00000100 + #define SHARED_HW_CFG_PCIE_GEN2_DISABLED 0x00000000 + + /* The default value for the core clock is 250MHz and it is + achieved by setting the clock change to 4 */ + #define SHARED_HW_CFG_CLOCK_CHANGE_MASK 0x00000e00 + #define SHARED_HW_CFG_CLOCK_CHANGE_SHIFT 9 + + #define SHARED_HW_CFG_SMBUS_TIMING_MASK 0x00001000 + #define SHARED_HW_CFG_SMBUS_TIMING_100KHZ 0x00000000 + #define SHARED_HW_CFG_SMBUS_TIMING_400KHZ 0x00001000 + + #define SHARED_HW_CFG_HIDE_PORT1 0x00002000 + + #define SHARED_HW_CFG_WOL_CAPABLE_MASK 0x00004000 + #define SHARED_HW_CFG_WOL_CAPABLE_DISABLED 0x00000000 + #define SHARED_HW_CFG_WOL_CAPABLE_ENABLED 0x00004000 + + /* Output low when PERST is asserted */ + #define SHARED_HW_CFG_SPIO4_FOLLOW_PERST_MASK 0x00008000 + #define SHARED_HW_CFG_SPIO4_FOLLOW_PERST_DISABLED 0x00000000 + #define SHARED_HW_CFG_SPIO4_FOLLOW_PERST_ENABLED 0x00008000 + + #define SHARED_HW_CFG_PCIE_GEN2_PREEMPHASIS_MASK 0x00070000 + #define SHARED_HW_CFG_PCIE_GEN2_PREEMPHASIS_SHIFT 16 + #define SHARED_HW_CFG_PCIE_GEN2_PREEMPHASIS_HW 0x00000000 + #define SHARED_HW_CFG_PCIE_GEN2_PREEMPHASIS_0DB 0x00010000 + #define SHARED_HW_CFG_PCIE_GEN2_PREEMPHASIS_3_5DB 0x00020000 + #define SHARED_HW_CFG_PCIE_GEN2_PREEMPHASIS_6_0DB 0x00030000 + + /* The fan failure mechanism is usually related to the PHY type + since the power consumption of the board is determined by the PHY. + Currently, fan is required for most designs with SFX7101, BCM8727 + and BCM8481. If a fan is not required for a board which uses one + of those PHYs, this field should be set to "Disabled". If a fan is + required for a different PHY type, this option should be set to + "Enabled". The fan failure indication is expected on SPIO5 */ + #define SHARED_HW_CFG_FAN_FAILURE_MASK 0x00180000 + #define SHARED_HW_CFG_FAN_FAILURE_SHIFT 19 + #define SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE 0x00000000 + #define SHARED_HW_CFG_FAN_FAILURE_DISABLED 0x00080000 + #define SHARED_HW_CFG_FAN_FAILURE_ENABLED 0x00100000 + + /* ASPM Power Management support */ + #define SHARED_HW_CFG_ASPM_SUPPORT_MASK 0x00600000 + #define SHARED_HW_CFG_ASPM_SUPPORT_SHIFT 21 + #define SHARED_HW_CFG_ASPM_SUPPORT_L0S_L1_ENABLED 0x00000000 + #define SHARED_HW_CFG_ASPM_SUPPORT_L0S_DISABLED 0x00200000 + #define SHARED_HW_CFG_ASPM_SUPPORT_L1_DISABLED 0x00400000 + #define SHARED_HW_CFG_ASPM_SUPPORT_L0S_L1_DISABLED 0x00600000 + + /* The value of PM_TL_IGNORE_REQS (bit0) in PCI register + tl_control_0 (register 0x2800) */ + #define SHARED_HW_CFG_PREVENT_L1_ENTRY_MASK 0x00800000 + #define SHARED_HW_CFG_PREVENT_L1_ENTRY_DISABLED 0x00000000 + #define SHARED_HW_CFG_PREVENT_L1_ENTRY_ENABLED 0x00800000 + + #define SHARED_HW_CFG_PORT_MODE_MASK 0x01000000 + #define SHARED_HW_CFG_PORT_MODE_2 0x00000000 + #define SHARED_HW_CFG_PORT_MODE_4 0x01000000 + + #define SHARED_HW_CFG_PATH_SWAP_MASK 0x02000000 + #define SHARED_HW_CFG_PATH_SWAP_DISABLED 0x00000000 + #define SHARED_HW_CFG_PATH_SWAP_ENABLED 0x02000000 + + /* Set the MDC/MDIO access for the first external phy */ + #define SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK 0x1C000000 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT 26 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE 0x00000000 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0 0x04000000 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1 0x08000000 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH 0x0c000000 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED 0x10000000 + + /* Set the MDC/MDIO access for the second external phy */ + #define SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK 0xE0000000 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT 29 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS2_PHY_TYPE 0x00000000 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS2_EMAC0 0x20000000 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS2_EMAC1 0x40000000 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS2_BOTH 0x60000000 + #define SHARED_HW_CFG_MDC_MDIO_ACCESS2_SWAPPED 0x80000000 + + + u32 power_dissipated; /* 0x11c */ + #define SHARED_HW_CFG_POWER_MGNT_SCALE_MASK 0x00ff0000 + #define SHARED_HW_CFG_POWER_MGNT_SCALE_SHIFT 16 + #define SHARED_HW_CFG_POWER_MGNT_UNKNOWN_SCALE 0x00000000 + #define SHARED_HW_CFG_POWER_MGNT_DOT_1_WATT 0x00010000 + #define SHARED_HW_CFG_POWER_MGNT_DOT_01_WATT 0x00020000 + #define SHARED_HW_CFG_POWER_MGNT_DOT_001_WATT 0x00030000 + + #define SHARED_HW_CFG_POWER_DIS_CMN_MASK 0xff000000 + #define SHARED_HW_CFG_POWER_DIS_CMN_SHIFT 24 + + u32 ump_nc_si_config; /* 0x120 */ + #define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_MASK 0x00000003 + #define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_SHIFT 0 + #define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_MAC 0x00000000 + #define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_PHY 0x00000001 + #define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_MII 0x00000000 + #define SHARED_HW_CFG_UMP_NC_SI_MII_MODE_RMII 0x00000002 + + #define SHARED_HW_CFG_UMP_NC_SI_NUM_DEVS_MASK 0x00000f00 + #define SHARED_HW_CFG_UMP_NC_SI_NUM_DEVS_SHIFT 8 + + #define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_MASK 0x00ff0000 + #define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_SHIFT 16 + #define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_NONE 0x00000000 + #define SHARED_HW_CFG_UMP_NC_SI_EXT_PHY_TYPE_BCM5221 0x00010000 + + u32 board; /* 0x124 */ + #define SHARED_HW_CFG_E3_I2C_MUX0_MASK 0x0000003F + #define SHARED_HW_CFG_E3_I2C_MUX0_SHIFT 0 + #define SHARED_HW_CFG_E3_I2C_MUX1_MASK 0x00000FC0 + #define SHARED_HW_CFG_E3_I2C_MUX1_SHIFT 6 + /* Use the PIN_CFG_XXX defines on top */ + #define SHARED_HW_CFG_BOARD_REV_MASK 0x00ff0000 + #define SHARED_HW_CFG_BOARD_REV_SHIFT 16 + + #define SHARED_HW_CFG_BOARD_MAJOR_VER_MASK 0x0f000000 + #define SHARED_HW_CFG_BOARD_MAJOR_VER_SHIFT 24 + + #define SHARED_HW_CFG_BOARD_MINOR_VER_MASK 0xf0000000 + #define SHARED_HW_CFG_BOARD_MINOR_VER_SHIFT 28 + + u32 wc_lane_config; /* 0x128 */ + #define SHARED_HW_CFG_LANE_SWAP_CFG_MASK 0x0000FFFF + #define SHARED_HW_CFG_LANE_SWAP_CFG_SHIFT 0 + #define SHARED_HW_CFG_LANE_SWAP_CFG_32103210 0x00001b1b + #define SHARED_HW_CFG_LANE_SWAP_CFG_32100123 0x00001be4 + #define SHARED_HW_CFG_LANE_SWAP_CFG_01233210 0x0000e41b + #define SHARED_HW_CFG_LANE_SWAP_CFG_01230123 0x0000e4e4 + #define SHARED_HW_CFG_LANE_SWAP_CFG_TX_MASK 0x000000FF + #define SHARED_HW_CFG_LANE_SWAP_CFG_TX_SHIFT 0 + #define SHARED_HW_CFG_LANE_SWAP_CFG_RX_MASK 0x0000FF00 + #define SHARED_HW_CFG_LANE_SWAP_CFG_RX_SHIFT 8 + + /* TX lane Polarity swap */ + #define SHARED_HW_CFG_TX_LANE0_POL_FLIP_ENABLED 0x00010000 + #define SHARED_HW_CFG_TX_LANE1_POL_FLIP_ENABLED 0x00020000 + #define SHARED_HW_CFG_TX_LANE2_POL_FLIP_ENABLED 0x00040000 + #define SHARED_HW_CFG_TX_LANE3_POL_FLIP_ENABLED 0x00080000 + /* TX lane Polarity swap */ + #define SHARED_HW_CFG_RX_LANE0_POL_FLIP_ENABLED 0x00100000 + #define SHARED_HW_CFG_RX_LANE1_POL_FLIP_ENABLED 0x00200000 + #define SHARED_HW_CFG_RX_LANE2_POL_FLIP_ENABLED 0x00400000 + #define SHARED_HW_CFG_RX_LANE3_POL_FLIP_ENABLED 0x00800000 + + /* Selects the port layout of the board */ + #define SHARED_HW_CFG_E3_PORT_LAYOUT_MASK 0x0F000000 + #define SHARED_HW_CFG_E3_PORT_LAYOUT_SHIFT 24 + #define SHARED_HW_CFG_E3_PORT_LAYOUT_2P_01 0x00000000 + #define SHARED_HW_CFG_E3_PORT_LAYOUT_2P_10 0x01000000 + #define SHARED_HW_CFG_E3_PORT_LAYOUT_4P_0123 0x02000000 + #define SHARED_HW_CFG_E3_PORT_LAYOUT_4P_1032 0x03000000 + #define SHARED_HW_CFG_E3_PORT_LAYOUT_4P_2301 0x04000000 + #define SHARED_HW_CFG_E3_PORT_LAYOUT_4P_3210 0x05000000 +}; + + +/**************************************************************************** + * Port HW configuration * + ****************************************************************************/ +struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ + + u32 pci_id; + #define PORT_HW_CFG_PCI_VENDOR_ID_MASK 0xffff0000 + #define PORT_HW_CFG_PCI_DEVICE_ID_MASK 0x0000ffff + + u32 pci_sub_id; + #define PORT_HW_CFG_PCI_SUBSYS_DEVICE_ID_MASK 0xffff0000 + #define PORT_HW_CFG_PCI_SUBSYS_VENDOR_ID_MASK 0x0000ffff + + u32 power_dissipated; + #define PORT_HW_CFG_POWER_DIS_D0_MASK 0x000000ff + #define PORT_HW_CFG_POWER_DIS_D0_SHIFT 0 + #define PORT_HW_CFG_POWER_DIS_D1_MASK 0x0000ff00 + #define PORT_HW_CFG_POWER_DIS_D1_SHIFT 8 + #define PORT_HW_CFG_POWER_DIS_D2_MASK 0x00ff0000 + #define PORT_HW_CFG_POWER_DIS_D2_SHIFT 16 + #define PORT_HW_CFG_POWER_DIS_D3_MASK 0xff000000 + #define PORT_HW_CFG_POWER_DIS_D3_SHIFT 24 + + u32 power_consumed; + #define PORT_HW_CFG_POWER_CONS_D0_MASK 0x000000ff + #define PORT_HW_CFG_POWER_CONS_D0_SHIFT 0 + #define PORT_HW_CFG_POWER_CONS_D1_MASK 0x0000ff00 + #define PORT_HW_CFG_POWER_CONS_D1_SHIFT 8 + #define PORT_HW_CFG_POWER_CONS_D2_MASK 0x00ff0000 + #define PORT_HW_CFG_POWER_CONS_D2_SHIFT 16 + #define PORT_HW_CFG_POWER_CONS_D3_MASK 0xff000000 + #define PORT_HW_CFG_POWER_CONS_D3_SHIFT 24 + + u32 mac_upper; + #define PORT_HW_CFG_UPPERMAC_MASK 0x0000ffff + #define PORT_HW_CFG_UPPERMAC_SHIFT 0 + u32 mac_lower; + + u32 iscsi_mac_upper; /* Upper 16 bits are always zeroes */ + u32 iscsi_mac_lower; + + u32 rdma_mac_upper; /* Upper 16 bits are always zeroes */ + u32 rdma_mac_lower; + + u32 serdes_config; + #define PORT_HW_CFG_SERDES_TX_DRV_PRE_EMPHASIS_MASK 0x0000ffff + #define PORT_HW_CFG_SERDES_TX_DRV_PRE_EMPHASIS_SHIFT 0 + + #define PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_MASK 0xffff0000 + #define PORT_HW_CFG_SERDES_RX_DRV_EQUALIZER_SHIFT 16 + + + /* Default values: 2P-64, 4P-32 */ + u32 pf_config; /* 0x158 */ + #define PORT_HW_CFG_PF_NUM_VF_MASK 0x0000007F + #define PORT_HW_CFG_PF_NUM_VF_SHIFT 0 + + /* Default values: 17 */ + #define PORT_HW_CFG_PF_NUM_MSIX_VECTORS_MASK 0x00007F00 + #define PORT_HW_CFG_PF_NUM_MSIX_VECTORS_SHIFT 8 + + #define PORT_HW_CFG_ENABLE_FLR_MASK 0x00010000 + #define PORT_HW_CFG_FLR_ENABLED 0x00010000 + + u32 vf_config; /* 0x15C */ + #define PORT_HW_CFG_VF_NUM_MSIX_VECTORS_MASK 0x0000007F + #define PORT_HW_CFG_VF_NUM_MSIX_VECTORS_SHIFT 0 + + #define PORT_HW_CFG_VF_PCI_DEVICE_ID_MASK 0xFFFF0000 + #define PORT_HW_CFG_VF_PCI_DEVICE_ID_SHIFT 16 + + u32 mf_pci_id; /* 0x160 */ + #define PORT_HW_CFG_MF_PCI_DEVICE_ID_MASK 0x0000FFFF + #define PORT_HW_CFG_MF_PCI_DEVICE_ID_SHIFT 0 + + /* Controls the TX laser of the SFP+ module */ + u32 sfp_ctrl; /* 0x164 */ + #define PORT_HW_CFG_TX_LASER_MASK 0x000000FF + #define PORT_HW_CFG_TX_LASER_SHIFT 0 + #define PORT_HW_CFG_TX_LASER_MDIO 0x00000000 + #define PORT_HW_CFG_TX_LASER_GPIO0 0x00000001 + #define PORT_HW_CFG_TX_LASER_GPIO1 0x00000002 + #define PORT_HW_CFG_TX_LASER_GPIO2 0x00000003 + #define PORT_HW_CFG_TX_LASER_GPIO3 0x00000004 + + /* Controls the fault module LED of the SFP+ */ + #define PORT_HW_CFG_FAULT_MODULE_LED_MASK 0x0000FF00 + #define PORT_HW_CFG_FAULT_MODULE_LED_SHIFT 8 + #define PORT_HW_CFG_FAULT_MODULE_LED_GPIO0 0x00000000 + #define PORT_HW_CFG_FAULT_MODULE_LED_GPIO1 0x00000100 + #define PORT_HW_CFG_FAULT_MODULE_LED_GPIO2 0x00000200 + #define PORT_HW_CFG_FAULT_MODULE_LED_GPIO3 0x00000300 + #define PORT_HW_CFG_FAULT_MODULE_LED_DISABLED 0x00000400 + + /* The output pin TX_DIS that controls the TX laser of the SFP+ + module. Use the PIN_CFG_XXX defines on top */ + u32 e3_sfp_ctrl; /* 0x168 */ + #define PORT_HW_CFG_E3_TX_LASER_MASK 0x000000FF + #define PORT_HW_CFG_E3_TX_LASER_SHIFT 0 + + /* The output pin for SFPP_TYPE which turns on the Fault module LED */ + #define PORT_HW_CFG_E3_FAULT_MDL_LED_MASK 0x0000FF00 + #define PORT_HW_CFG_E3_FAULT_MDL_LED_SHIFT 8 + + /* The input pin MOD_ABS that indicates whether SFP+ module is + present or not. Use the PIN_CFG_XXX defines on top */ + #define PORT_HW_CFG_E3_MOD_ABS_MASK 0x00FF0000 + #define PORT_HW_CFG_E3_MOD_ABS_SHIFT 16 + + /* The output pin PWRDIS_SFP_X which disable the power of the SFP+ + module. Use the PIN_CFG_XXX defines on top */ + #define PORT_HW_CFG_E3_PWR_DIS_MASK 0xFF000000 + #define PORT_HW_CFG_E3_PWR_DIS_SHIFT 24 + + /* + * The input pin which signals module transmit fault. Use the + * PIN_CFG_XXX defines on top + */ + u32 e3_cmn_pin_cfg; /* 0x16C */ + #define PORT_HW_CFG_E3_TX_FAULT_MASK 0x000000FF + #define PORT_HW_CFG_E3_TX_FAULT_SHIFT 0 + + /* The output pin which reset the PHY. Use the PIN_CFG_XXX defines on + top */ + #define PORT_HW_CFG_E3_PHY_RESET_MASK 0x0000FF00 + #define PORT_HW_CFG_E3_PHY_RESET_SHIFT 8 + + /* + * The output pin which powers down the PHY. Use the PIN_CFG_XXX + * defines on top + */ + #define PORT_HW_CFG_E3_PWR_DOWN_MASK 0x00FF0000 + #define PORT_HW_CFG_E3_PWR_DOWN_SHIFT 16 + + /* The output pin values BSC_SEL which selects the I2C for this port + in the I2C Mux */ + #define PORT_HW_CFG_E3_I2C_MUX0_MASK 0x01000000 + #define PORT_HW_CFG_E3_I2C_MUX1_MASK 0x02000000 + + + /* + * The input pin I_FAULT which indicate over-current has occurred. + * Use the PIN_CFG_XXX defines on top + */ + u32 e3_cmn_pin_cfg1; /* 0x170 */ + #define PORT_HW_CFG_E3_OVER_CURRENT_MASK 0x000000FF + #define PORT_HW_CFG_E3_OVER_CURRENT_SHIFT 0 + u32 reserved0[7]; /* 0x174 */ + + u32 aeu_int_mask; /* 0x190 */ + + u32 media_type; /* 0x194 */ + #define PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK 0x000000FF + #define PORT_HW_CFG_MEDIA_TYPE_PHY0_SHIFT 0 + + #define PORT_HW_CFG_MEDIA_TYPE_PHY1_MASK 0x0000FF00 + #define PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT 8 + + #define PORT_HW_CFG_MEDIA_TYPE_PHY2_MASK 0x00FF0000 + #define PORT_HW_CFG_MEDIA_TYPE_PHY2_SHIFT 16 + + /* 4 times 16 bits for all 4 lanes. In case external PHY is present + (not direct mode), those values will not take effect on the 4 XGXS + lanes. For some external PHYs (such as 8706 and 8726) the values + will be used to configure the external PHY in those cases, not + all 4 values are needed. */ + u16 xgxs_config_rx[4]; /* 0x198 */ + u16 xgxs_config_tx[4]; /* 0x1A0 */ + + /* For storing FCOE mac on shared memory */ + u32 fcoe_fip_mac_upper; + #define PORT_HW_CFG_FCOE_UPPERMAC_MASK 0x0000ffff + #define PORT_HW_CFG_FCOE_UPPERMAC_SHIFT 0 + u32 fcoe_fip_mac_lower; + + u32 fcoe_wwn_port_name_upper; + u32 fcoe_wwn_port_name_lower; + + u32 fcoe_wwn_node_name_upper; + u32 fcoe_wwn_node_name_lower; + + u32 Reserved1[49]; /* 0x1C0 */ + + /* Enable RJ45 magjack pair swapping on 10GBase-T PHY (0=default), + 84833 only */ + u32 xgbt_phy_cfg; /* 0x284 */ + #define PORT_HW_CFG_RJ45_PAIR_SWAP_MASK 0x000000FF + #define PORT_HW_CFG_RJ45_PAIR_SWAP_SHIFT 0 + + u32 default_cfg; /* 0x288 */ + #define PORT_HW_CFG_GPIO0_CONFIG_MASK 0x00000003 + #define PORT_HW_CFG_GPIO0_CONFIG_SHIFT 0 + #define PORT_HW_CFG_GPIO0_CONFIG_NA 0x00000000 + #define PORT_HW_CFG_GPIO0_CONFIG_LOW 0x00000001 + #define PORT_HW_CFG_GPIO0_CONFIG_HIGH 0x00000002 + #define PORT_HW_CFG_GPIO0_CONFIG_INPUT 0x00000003 + + #define PORT_HW_CFG_GPIO1_CONFIG_MASK 0x0000000C + #define PORT_HW_CFG_GPIO1_CONFIG_SHIFT 2 + #define PORT_HW_CFG_GPIO1_CONFIG_NA 0x00000000 + #define PORT_HW_CFG_GPIO1_CONFIG_LOW 0x00000004 + #define PORT_HW_CFG_GPIO1_CONFIG_HIGH 0x00000008 + #define PORT_HW_CFG_GPIO1_CONFIG_INPUT 0x0000000c + + #define PORT_HW_CFG_GPIO2_CONFIG_MASK 0x00000030 + #define PORT_HW_CFG_GPIO2_CONFIG_SHIFT 4 + #define PORT_HW_CFG_GPIO2_CONFIG_NA 0x00000000 + #define PORT_HW_CFG_GPIO2_CONFIG_LOW 0x00000010 + #define PORT_HW_CFG_GPIO2_CONFIG_HIGH 0x00000020 + #define PORT_HW_CFG_GPIO2_CONFIG_INPUT 0x00000030 + + #define PORT_HW_CFG_GPIO3_CONFIG_MASK 0x000000C0 + #define PORT_HW_CFG_GPIO3_CONFIG_SHIFT 6 + #define PORT_HW_CFG_GPIO3_CONFIG_NA 0x00000000 + #define PORT_HW_CFG_GPIO3_CONFIG_LOW 0x00000040 + #define PORT_HW_CFG_GPIO3_CONFIG_HIGH 0x00000080 + #define PORT_HW_CFG_GPIO3_CONFIG_INPUT 0x000000c0 + + /* When KR link is required to be set to force which is not + KR-compliant, this parameter determine what is the trigger for it. + When GPIO is selected, low input will force the speed. Currently + default speed is 1G. In the future, it may be widen to select the + forced speed in with another parameter. Note when force-1G is + enabled, it override option 56: Link Speed option. */ + #define PORT_HW_CFG_FORCE_KR_ENABLER_MASK 0x00000F00 + #define PORT_HW_CFG_FORCE_KR_ENABLER_SHIFT 8 + #define PORT_HW_CFG_FORCE_KR_ENABLER_NOT_FORCED 0x00000000 + #define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO0_P0 0x00000100 + #define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO1_P0 0x00000200 + #define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO2_P0 0x00000300 + #define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO3_P0 0x00000400 + #define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO0_P1 0x00000500 + #define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO1_P1 0x00000600 + #define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO2_P1 0x00000700 + #define PORT_HW_CFG_FORCE_KR_ENABLER_GPIO3_P1 0x00000800 + #define PORT_HW_CFG_FORCE_KR_ENABLER_FORCED 0x00000900 + /* Enable to determine with which GPIO to reset the external phy */ + #define PORT_HW_CFG_EXT_PHY_GPIO_RST_MASK 0x000F0000 + #define PORT_HW_CFG_EXT_PHY_GPIO_RST_SHIFT 16 + #define PORT_HW_CFG_EXT_PHY_GPIO_RST_PHY_TYPE 0x00000000 + #define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P0 0x00010000 + #define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P0 0x00020000 + #define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P0 0x00030000 + #define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P0 0x00040000 + #define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P1 0x00050000 + #define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO1_P1 0x00060000 + #define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO2_P1 0x00070000 + #define PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO3_P1 0x00080000 + + /* Enable BAM on KR */ + #define PORT_HW_CFG_ENABLE_BAM_ON_KR_MASK 0x00100000 + #define PORT_HW_CFG_ENABLE_BAM_ON_KR_SHIFT 20 + #define PORT_HW_CFG_ENABLE_BAM_ON_KR_DISABLED 0x00000000 + #define PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED 0x00100000 + + /* Enable Common Mode Sense */ + #define PORT_HW_CFG_ENABLE_CMS_MASK 0x00200000 + #define PORT_HW_CFG_ENABLE_CMS_SHIFT 21 + #define PORT_HW_CFG_ENABLE_CMS_DISABLED 0x00000000 + #define PORT_HW_CFG_ENABLE_CMS_ENABLED 0x00200000 + + /* Enable RJ45 magjack pair swapping on 10GBase-T PHY, 84833 only */ + #define PORT_HW_CFG_RJ45_PR_SWP_MASK 0x00400000 + #define PORT_HW_CFG_RJ45_PR_SWP_SHIFT 22 + #define PORT_HW_CFG_RJ45_PR_SWP_DISABLED 0x00000000 + #define PORT_HW_CFG_RJ45_PR_SWP_ENABLED 0x00400000 + + /* Determine the Serdes electrical interface */ + #define PORT_HW_CFG_NET_SERDES_IF_MASK 0x0F000000 + #define PORT_HW_CFG_NET_SERDES_IF_SHIFT 24 + #define PORT_HW_CFG_NET_SERDES_IF_SGMII 0x00000000 + #define PORT_HW_CFG_NET_SERDES_IF_XFI 0x01000000 + #define PORT_HW_CFG_NET_SERDES_IF_SFI 0x02000000 + #define PORT_HW_CFG_NET_SERDES_IF_KR 0x03000000 + #define PORT_HW_CFG_NET_SERDES_IF_DXGXS 0x04000000 + #define PORT_HW_CFG_NET_SERDES_IF_KR2 0x05000000 + + + u32 speed_capability_mask2; /* 0x28C */ + #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_MASK 0x0000FFFF + #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_SHIFT 0 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_10M_FULL 0x00000001 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D3__ 0x00000002 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D3___ 0x00000004 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_100M_FULL 0x00000008 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_1G 0x00000010 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_2_DOT_5G 0x00000020 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_10G 0x00000040 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D3_20G 0x00000080 + + #define PORT_HW_CFG_SPEED_CAPABILITY2_D0_MASK 0xFFFF0000 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D0_SHIFT 16 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D0_10M_FULL 0x00010000 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D0__ 0x00020000 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D0___ 0x00040000 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D0_100M_FULL 0x00080000 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D0_1G 0x00100000 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D0_2_DOT_5G 0x00200000 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D0_10G 0x00400000 + #define PORT_HW_CFG_SPEED_CAPABILITY2_D0_20G 0x00800000 + + + /* In the case where two media types (e.g. copper and fiber) are + present and electrically active at the same time, PHY Selection + will determine which of the two PHYs will be designated as the + Active PHY and used for a connection to the network. */ + u32 multi_phy_config; /* 0x290 */ + #define PORT_HW_CFG_PHY_SELECTION_MASK 0x00000007 + #define PORT_HW_CFG_PHY_SELECTION_SHIFT 0 + #define PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT 0x00000000 + #define PORT_HW_CFG_PHY_SELECTION_FIRST_PHY 0x00000001 + #define PORT_HW_CFG_PHY_SELECTION_SECOND_PHY 0x00000002 + #define PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY 0x00000003 + #define PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY 0x00000004 + + /* When enabled, all second phy nvram parameters will be swapped + with the first phy parameters */ + #define PORT_HW_CFG_PHY_SWAPPED_MASK 0x00000008 + #define PORT_HW_CFG_PHY_SWAPPED_SHIFT 3 + #define PORT_HW_CFG_PHY_SWAPPED_DISABLED 0x00000000 + #define PORT_HW_CFG_PHY_SWAPPED_ENABLED 0x00000008 + + + /* Address of the second external phy */ + u32 external_phy_config2; /* 0x294 */ + #define PORT_HW_CFG_XGXS_EXT_PHY2_ADDR_MASK 0x000000FF + #define PORT_HW_CFG_XGXS_EXT_PHY2_ADDR_SHIFT 0 + + /* The second XGXS external PHY type */ + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_MASK 0x0000FF00 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_SHIFT 8 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_DIRECT 0x00000000 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8071 0x00000100 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8072 0x00000200 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8073 0x00000300 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8705 0x00000400 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8706 0x00000500 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8726 0x00000600 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8481 0x00000700 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_SFX7101 0x00000800 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8727 0x00000900 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8727_NOC 0x00000a00 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84823 0x00000b00 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM54640 0x00000c00 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84833 0x00000d00 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM54618SE 0x00000e00 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8722 0x00000f00 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_FAILURE 0x0000fd00 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_NOT_CONN 0x0000ff00 + + + /* 4 times 16 bits for all 4 lanes. For some external PHYs (such as + 8706, 8726 and 8727) not all 4 values are needed. */ + u16 xgxs_config2_rx[4]; /* 0x296 */ + u16 xgxs_config2_tx[4]; /* 0x2A0 */ + + u32 lane_config; + #define PORT_HW_CFG_LANE_SWAP_CFG_MASK 0x0000ffff + #define PORT_HW_CFG_LANE_SWAP_CFG_SHIFT 0 + /* AN and forced */ + #define PORT_HW_CFG_LANE_SWAP_CFG_01230123 0x00001b1b + /* forced only */ + #define PORT_HW_CFG_LANE_SWAP_CFG_01233210 0x00001be4 + /* forced only */ + #define PORT_HW_CFG_LANE_SWAP_CFG_31203120 0x0000d8d8 + /* forced only */ + #define PORT_HW_CFG_LANE_SWAP_CFG_32103210 0x0000e4e4 + #define PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK 0x000000ff + #define PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT 0 + #define PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK 0x0000ff00 + #define PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT 8 + #define PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK 0x0000c000 + #define PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT 14 + + /* Indicate whether to swap the external phy polarity */ + #define PORT_HW_CFG_SWAP_PHY_POLARITY_MASK 0x00010000 + #define PORT_HW_CFG_SWAP_PHY_POLARITY_DISABLED 0x00000000 + #define PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED 0x00010000 + + + u32 external_phy_config; + #define PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK 0x000000ff + #define PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT 0 + + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK 0x0000ff00 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SHIFT 8 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT 0x00000000 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8071 0x00000100 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8072 0x00000200 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073 0x00000300 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705 0x00000400 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706 0x00000500 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726 0x00000600 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481 0x00000700 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101 0x00000800 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 0x00000900 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC 0x00000a00 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823 0x00000b00 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54640 0x00000c00 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833 0x00000d00 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE 0x00000e00 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722 0x00000f00 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT_WC 0x0000fc00 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00 + + #define PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK 0x00ff0000 + #define PORT_HW_CFG_SERDES_EXT_PHY_ADDR_SHIFT 16 + + #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK 0xff000000 + #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_SHIFT 24 + #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT 0x00000000 + #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482 0x01000000 + #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT_SD 0x02000000 + #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN 0xff000000 + + u32 speed_capability_mask; + #define PORT_HW_CFG_SPEED_CAPABILITY_D3_MASK 0x0000ffff + #define PORT_HW_CFG_SPEED_CAPABILITY_D3_SHIFT 0 + #define PORT_HW_CFG_SPEED_CAPABILITY_D3_10M_FULL 0x00000001 + #define PORT_HW_CFG_SPEED_CAPABILITY_D3_10M_HALF 0x00000002 + #define PORT_HW_CFG_SPEED_CAPABILITY_D3_100M_HALF 0x00000004 + #define PORT_HW_CFG_SPEED_CAPABILITY_D3_100M_FULL 0x00000008 + #define PORT_HW_CFG_SPEED_CAPABILITY_D3_1G 0x00000010 + #define PORT_HW_CFG_SPEED_CAPABILITY_D3_2_5G 0x00000020 + #define PORT_HW_CFG_SPEED_CAPABILITY_D3_10G 0x00000040 + #define PORT_HW_CFG_SPEED_CAPABILITY_D3_20G 0x00000080 + #define PORT_HW_CFG_SPEED_CAPABILITY_D3_RESERVED 0x0000f000 + + #define PORT_HW_CFG_SPEED_CAPABILITY_D0_MASK 0xffff0000 + #define PORT_HW_CFG_SPEED_CAPABILITY_D0_SHIFT 16 + #define PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL 0x00010000 + #define PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF 0x00020000 + #define PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF 0x00040000 + #define PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL 0x00080000 + #define PORT_HW_CFG_SPEED_CAPABILITY_D0_1G 0x00100000 + #define PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G 0x00200000 + #define PORT_HW_CFG_SPEED_CAPABILITY_D0_10G 0x00400000 + #define PORT_HW_CFG_SPEED_CAPABILITY_D0_20G 0x00800000 + #define PORT_HW_CFG_SPEED_CAPABILITY_D0_RESERVED 0xf0000000 + + /* A place to hold the original MAC address as a backup */ + u32 backup_mac_upper; /* 0x2B4 */ + u32 backup_mac_lower; /* 0x2B8 */ + +}; + + +/**************************************************************************** + * Shared Feature configuration * + ****************************************************************************/ +struct shared_feat_cfg { /* NVRAM Offset */ + + u32 config; /* 0x450 */ + #define SHARED_FEATURE_BMC_ECHO_MODE_EN 0x00000001 + + /* Use NVRAM values instead of HW default values */ + #define SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_MASK \ + 0x00000002 + #define SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_DISABLED \ + 0x00000000 + #define SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_ENABLED \ + 0x00000002 + + #define SHARED_FEAT_CFG_NCSI_ID_METHOD_MASK 0x00000008 + #define SHARED_FEAT_CFG_NCSI_ID_METHOD_SPIO 0x00000000 + #define SHARED_FEAT_CFG_NCSI_ID_METHOD_NVRAM 0x00000008 + + #define SHARED_FEAT_CFG_NCSI_ID_MASK 0x00000030 + #define SHARED_FEAT_CFG_NCSI_ID_SHIFT 4 + + /* Override the OTP back to single function mode. When using GPIO, + high means only SF, 0 is according to CLP configuration */ + #define SHARED_FEAT_CFG_FORCE_SF_MODE_MASK 0x00000700 + #define SHARED_FEAT_CFG_FORCE_SF_MODE_SHIFT 8 + #define SHARED_FEAT_CFG_FORCE_SF_MODE_MF_ALLOWED 0x00000000 + #define SHARED_FEAT_CFG_FORCE_SF_MODE_FORCED_SF 0x00000100 + #define SHARED_FEAT_CFG_FORCE_SF_MODE_SPIO4 0x00000200 + #define SHARED_FEAT_CFG_FORCE_SF_MODE_SWITCH_INDEPT 0x00000300 + + /* The interval in seconds between sending LLDP packets. Set to zero + to disable the feature */ + #define SHARED_FEAT_CFG_LLDP_XMIT_INTERVAL_MASK 0x00ff0000 + #define SHARED_FEAT_CFG_LLDP_XMIT_INTERVAL_SHIFT 16 + + /* The assigned device type ID for LLDP usage */ + #define SHARED_FEAT_CFG_LLDP_DEVICE_TYPE_ID_MASK 0xff000000 + #define SHARED_FEAT_CFG_LLDP_DEVICE_TYPE_ID_SHIFT 24 + +}; + + +/**************************************************************************** + * Port Feature configuration * + ****************************************************************************/ +struct port_feat_cfg { /* port 0: 0x454 port 1: 0x4c8 */ + + u32 config; + #define PORT_FEATURE_BAR1_SIZE_MASK 0x0000000f + #define PORT_FEATURE_BAR1_SIZE_SHIFT 0 + #define PORT_FEATURE_BAR1_SIZE_DISABLED 0x00000000 + #define PORT_FEATURE_BAR1_SIZE_64K 0x00000001 + #define PORT_FEATURE_BAR1_SIZE_128K 0x00000002 + #define PORT_FEATURE_BAR1_SIZE_256K 0x00000003 + #define PORT_FEATURE_BAR1_SIZE_512K 0x00000004 + #define PORT_FEATURE_BAR1_SIZE_1M 0x00000005 + #define PORT_FEATURE_BAR1_SIZE_2M 0x00000006 + #define PORT_FEATURE_BAR1_SIZE_4M 0x00000007 + #define PORT_FEATURE_BAR1_SIZE_8M 0x00000008 + #define PORT_FEATURE_BAR1_SIZE_16M 0x00000009 + #define PORT_FEATURE_BAR1_SIZE_32M 0x0000000a + #define PORT_FEATURE_BAR1_SIZE_64M 0x0000000b + #define PORT_FEATURE_BAR1_SIZE_128M 0x0000000c + #define PORT_FEATURE_BAR1_SIZE_256M 0x0000000d + #define PORT_FEATURE_BAR1_SIZE_512M 0x0000000e + #define PORT_FEATURE_BAR1_SIZE_1G 0x0000000f + #define PORT_FEATURE_BAR2_SIZE_MASK 0x000000f0 + #define PORT_FEATURE_BAR2_SIZE_SHIFT 4 + #define PORT_FEATURE_BAR2_SIZE_DISABLED 0x00000000 + #define PORT_FEATURE_BAR2_SIZE_64K 0x00000010 + #define PORT_FEATURE_BAR2_SIZE_128K 0x00000020 + #define PORT_FEATURE_BAR2_SIZE_256K 0x00000030 + #define PORT_FEATURE_BAR2_SIZE_512K 0x00000040 + #define PORT_FEATURE_BAR2_SIZE_1M 0x00000050 + #define PORT_FEATURE_BAR2_SIZE_2M 0x00000060 + #define PORT_FEATURE_BAR2_SIZE_4M 0x00000070 + #define PORT_FEATURE_BAR2_SIZE_8M 0x00000080 + #define PORT_FEATURE_BAR2_SIZE_16M 0x00000090 + #define PORT_FEATURE_BAR2_SIZE_32M 0x000000a0 + #define PORT_FEATURE_BAR2_SIZE_64M 0x000000b0 + #define PORT_FEATURE_BAR2_SIZE_128M 0x000000c0 + #define PORT_FEATURE_BAR2_SIZE_256M 0x000000d0 + #define PORT_FEATURE_BAR2_SIZE_512M 0x000000e0 + #define PORT_FEATURE_BAR2_SIZE_1G 0x000000f0 + + #define PORT_FEAT_CFG_DCBX_MASK 0x00000100 + #define PORT_FEAT_CFG_DCBX_DISABLED 0x00000000 + #define PORT_FEAT_CFG_DCBX_ENABLED 0x00000100 + + #define PORT_FEAT_CFG_AUTOGREEN_MASK 0x00000200 + #define PORT_FEAT_CFG_AUTOGREEN_SHIFT 9 + #define PORT_FEAT_CFG_AUTOGREEN_DISABLED 0x00000000 + #define PORT_FEAT_CFG_AUTOGREEN_ENABLED 0x00000200 + + #define PORT_FEATURE_EN_SIZE_MASK 0x0f000000 + #define PORT_FEATURE_EN_SIZE_SHIFT 24 + #define PORT_FEATURE_WOL_ENABLED 0x01000000 + #define PORT_FEATURE_MBA_ENABLED 0x02000000 + #define PORT_FEATURE_MFW_ENABLED 0x04000000 + + /* Advertise expansion ROM even if MBA is disabled */ + #define PORT_FEAT_CFG_FORCE_EXP_ROM_ADV_MASK 0x08000000 + #define PORT_FEAT_CFG_FORCE_EXP_ROM_ADV_DISABLED 0x00000000 + #define PORT_FEAT_CFG_FORCE_EXP_ROM_ADV_ENABLED 0x08000000 + + /* Check the optic vendor via i2c against a list of approved modules + in a separate nvram image */ + #define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK 0xe0000000 + #define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_SHIFT 29 + #define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT \ + 0x00000000 + #define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER \ + 0x20000000 + #define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_WARNING_MSG 0x40000000 + #define PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN 0x60000000 + + u32 wol_config; + /* Default is used when driver sets to "auto" mode */ + #define PORT_FEATURE_WOL_DEFAULT_MASK 0x00000003 + #define PORT_FEATURE_WOL_DEFAULT_SHIFT 0 + #define PORT_FEATURE_WOL_DEFAULT_DISABLE 0x00000000 + #define PORT_FEATURE_WOL_DEFAULT_MAGIC 0x00000001 + #define PORT_FEATURE_WOL_DEFAULT_ACPI 0x00000002 + #define PORT_FEATURE_WOL_DEFAULT_MAGIC_AND_ACPI 0x00000003 + #define PORT_FEATURE_WOL_RES_PAUSE_CAP 0x00000004 + #define PORT_FEATURE_WOL_RES_ASYM_PAUSE_CAP 0x00000008 + #define PORT_FEATURE_WOL_ACPI_UPON_MGMT 0x00000010 + + u32 mba_config; + #define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_MASK 0x00000007 + #define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_SHIFT 0 + #define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_PXE 0x00000000 + #define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_RPL 0x00000001 + #define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_BOOTP 0x00000002 + #define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_ISCSIB 0x00000003 + #define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_FCOE_BOOT 0x00000004 + #define PORT_FEATURE_MBA_BOOT_AGENT_TYPE_NONE 0x00000007 + + #define PORT_FEATURE_MBA_BOOT_RETRY_MASK 0x00000038 + #define PORT_FEATURE_MBA_BOOT_RETRY_SHIFT 3 + + #define PORT_FEATURE_MBA_RES_PAUSE_CAP 0x00000100 + #define PORT_FEATURE_MBA_RES_ASYM_PAUSE_CAP 0x00000200 + #define PORT_FEATURE_MBA_SETUP_PROMPT_ENABLE 0x00000400 + #define PORT_FEATURE_MBA_HOTKEY_MASK 0x00000800 + #define PORT_FEATURE_MBA_HOTKEY_CTRL_S 0x00000000 + #define PORT_FEATURE_MBA_HOTKEY_CTRL_B 0x00000800 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_MASK 0x000ff000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_SHIFT 12 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_DISABLED 0x00000000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_2K 0x00001000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_4K 0x00002000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_8K 0x00003000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_16K 0x00004000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_32K 0x00005000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_64K 0x00006000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_128K 0x00007000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_256K 0x00008000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_512K 0x00009000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_1M 0x0000a000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_2M 0x0000b000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_4M 0x0000c000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_8M 0x0000d000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_16M 0x0000e000 + #define PORT_FEATURE_MBA_EXP_ROM_SIZE_32M 0x0000f000 + #define PORT_FEATURE_MBA_MSG_TIMEOUT_MASK 0x00f00000 + #define PORT_FEATURE_MBA_MSG_TIMEOUT_SHIFT 20 + #define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_MASK 0x03000000 + #define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_SHIFT 24 + #define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_AUTO 0x00000000 + #define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_BBS 0x01000000 + #define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_INT18H 0x02000000 + #define PORT_FEATURE_MBA_BIOS_BOOTSTRAP_INT19H 0x03000000 + #define PORT_FEATURE_MBA_LINK_SPEED_MASK 0x3c000000 + #define PORT_FEATURE_MBA_LINK_SPEED_SHIFT 26 + #define PORT_FEATURE_MBA_LINK_SPEED_AUTO 0x00000000 + #define PORT_FEATURE_MBA_LINK_SPEED_10HD 0x04000000 + #define PORT_FEATURE_MBA_LINK_SPEED_10FD 0x08000000 + #define PORT_FEATURE_MBA_LINK_SPEED_100HD 0x0c000000 + #define PORT_FEATURE_MBA_LINK_SPEED_100FD 0x10000000 + #define PORT_FEATURE_MBA_LINK_SPEED_1GBPS 0x14000000 + #define PORT_FEATURE_MBA_LINK_SPEED_2_5GBPS 0x18000000 + #define PORT_FEATURE_MBA_LINK_SPEED_10GBPS_CX4 0x1c000000 + #define PORT_FEATURE_MBA_LINK_SPEED_20GBPS 0x20000000 + u32 bmc_config; + #define PORT_FEATURE_BMC_LINK_OVERRIDE_MASK 0x00000001 + #define PORT_FEATURE_BMC_LINK_OVERRIDE_DEFAULT 0x00000000 + #define PORT_FEATURE_BMC_LINK_OVERRIDE_EN 0x00000001 + + u32 mba_vlan_cfg; + #define PORT_FEATURE_MBA_VLAN_TAG_MASK 0x0000ffff + #define PORT_FEATURE_MBA_VLAN_TAG_SHIFT 0 + #define PORT_FEATURE_MBA_VLAN_EN 0x00010000 + + u32 resource_cfg; + #define PORT_FEATURE_RESOURCE_CFG_VALID 0x00000001 + #define PORT_FEATURE_RESOURCE_CFG_DIAG 0x00000002 + #define PORT_FEATURE_RESOURCE_CFG_L2 0x00000004 + #define PORT_FEATURE_RESOURCE_CFG_ISCSI 0x00000008 + #define PORT_FEATURE_RESOURCE_CFG_RDMA 0x00000010 + + u32 smbus_config; + #define PORT_FEATURE_SMBUS_ADDR_MASK 0x000000fe + #define PORT_FEATURE_SMBUS_ADDR_SHIFT 1 + + u32 vf_config; + #define PORT_FEAT_CFG_VF_BAR2_SIZE_MASK 0x0000000f + #define PORT_FEAT_CFG_VF_BAR2_SIZE_SHIFT 0 + #define PORT_FEAT_CFG_VF_BAR2_SIZE_DISABLED 0x00000000 + #define PORT_FEAT_CFG_VF_BAR2_SIZE_4K 0x00000001 + #define PORT_FEAT_CFG_VF_BAR2_SIZE_8K 0x00000002 + #define PORT_FEAT_CFG_VF_BAR2_SIZE_16K 0x00000003 + #define PORT_FEAT_CFG_VF_BAR2_SIZE_32K 0x00000004 + #define PORT_FEAT_CFG_VF_BAR2_SIZE_64K 0x00000005 + #define PORT_FEAT_CFG_VF_BAR2_SIZE_128K 0x00000006 + #define PORT_FEAT_CFG_VF_BAR2_SIZE_256K 0x00000007 + #define PORT_FEAT_CFG_VF_BAR2_SIZE_512K 0x00000008 + #define PORT_FEAT_CFG_VF_BAR2_SIZE_1M 0x00000009 + #define PORT_FEAT_CFG_VF_BAR2_SIZE_2M 0x0000000a + #define PORT_FEAT_CFG_VF_BAR2_SIZE_4M 0x0000000b + #define PORT_FEAT_CFG_VF_BAR2_SIZE_8M 0x0000000c + #define PORT_FEAT_CFG_VF_BAR2_SIZE_16M 0x0000000d + #define PORT_FEAT_CFG_VF_BAR2_SIZE_32M 0x0000000e + #define PORT_FEAT_CFG_VF_BAR2_SIZE_64M 0x0000000f + + u32 link_config; /* Used as HW defaults for the driver */ + #define PORT_FEATURE_CONNECTED_SWITCH_MASK 0x03000000 + #define PORT_FEATURE_CONNECTED_SWITCH_SHIFT 24 + /* (forced) low speed switch (< 10G) */ + #define PORT_FEATURE_CON_SWITCH_1G_SWITCH 0x00000000 + /* (forced) high speed switch (>= 10G) */ + #define PORT_FEATURE_CON_SWITCH_10G_SWITCH 0x01000000 + #define PORT_FEATURE_CON_SWITCH_AUTO_DETECT 0x02000000 + #define PORT_FEATURE_CON_SWITCH_ONE_TIME_DETECT 0x03000000 + + #define PORT_FEATURE_LINK_SPEED_MASK 0x000f0000 + #define PORT_FEATURE_LINK_SPEED_SHIFT 16 + #define PORT_FEATURE_LINK_SPEED_AUTO 0x00000000 + #define PORT_FEATURE_LINK_SPEED_10M_FULL 0x00010000 + #define PORT_FEATURE_LINK_SPEED_10M_HALF 0x00020000 + #define PORT_FEATURE_LINK_SPEED_100M_HALF 0x00030000 + #define PORT_FEATURE_LINK_SPEED_100M_FULL 0x00040000 + #define PORT_FEATURE_LINK_SPEED_1G 0x00050000 + #define PORT_FEATURE_LINK_SPEED_2_5G 0x00060000 + #define PORT_FEATURE_LINK_SPEED_10G_CX4 0x00070000 + #define PORT_FEATURE_LINK_SPEED_20G 0x00080000 + + #define PORT_FEATURE_FLOW_CONTROL_MASK 0x00000700 + #define PORT_FEATURE_FLOW_CONTROL_SHIFT 8 + #define PORT_FEATURE_FLOW_CONTROL_AUTO 0x00000000 + #define PORT_FEATURE_FLOW_CONTROL_TX 0x00000100 + #define PORT_FEATURE_FLOW_CONTROL_RX 0x00000200 + #define PORT_FEATURE_FLOW_CONTROL_BOTH 0x00000300 + #define PORT_FEATURE_FLOW_CONTROL_NONE 0x00000400 + + /* The default for MCP link configuration, + uses the same defines as link_config */ + u32 mfw_wol_link_cfg; + + /* The default for the driver of the second external phy, + uses the same defines as link_config */ + u32 link_config2; /* 0x47C */ + + /* The default for MCP of the second external phy, + uses the same defines as link_config */ + u32 mfw_wol_link_cfg2; /* 0x480 */ + + u32 Reserved2[17]; /* 0x484 */ + +}; + + +/**************************************************************************** + * Device Information * + ****************************************************************************/ +struct shm_dev_info { /* size */ + + u32 bc_rev; /* 8 bits each: major, minor, build */ /* 4 */ + + struct shared_hw_cfg shared_hw_config; /* 40 */ + + struct port_hw_cfg port_hw_config[PORT_MAX]; /* 400*2=800 */ + + struct shared_feat_cfg shared_feature_config; /* 4 */ + + struct port_feat_cfg port_feature_config[PORT_MAX];/* 116*2=232 */ + +}; + + +#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) + #error "Missing either LITTLE_ENDIAN or BIG_ENDIAN definition." +#endif + +#define FUNC_0 0 +#define FUNC_1 1 +#define FUNC_2 2 +#define FUNC_3 3 +#define FUNC_4 4 +#define FUNC_5 5 +#define FUNC_6 6 +#define FUNC_7 7 +#define E1_FUNC_MAX 2 +#define E1H_FUNC_MAX 8 +#define E2_FUNC_MAX 4 /* per path */ + +#define VN_0 0 +#define VN_1 1 +#define VN_2 2 +#define VN_3 3 +#define E1VN_MAX 1 +#define E1HVN_MAX 4 + +#define E2_VF_MAX 64 /* HC_REG_VF_CONFIGURATION_SIZE */ +/* This value (in milliseconds) determines the frequency of the driver + * issuing the PULSE message code. The firmware monitors this periodic + * pulse to determine when to switch to an OS-absent mode. */ +#define DRV_PULSE_PERIOD_MS 250 + +/* This value (in milliseconds) determines how long the driver should + * wait for an acknowledgement from the firmware before timing out. Once + * the firmware has timed out, the driver will assume there is no firmware + * running and there won't be any firmware-driver synchronization during a + * driver reset. */ +#define FW_ACK_TIME_OUT_MS 5000 + +#define FW_ACK_POLL_TIME_MS 1 + +#define FW_ACK_NUM_OF_POLL (FW_ACK_TIME_OUT_MS/FW_ACK_POLL_TIME_MS) + +/* LED Blink rate that will achieve ~15.9Hz */ +#define LED_BLINK_RATE_VAL 480 + +/**************************************************************************** + * Driver <-> FW Mailbox * + ****************************************************************************/ +struct drv_port_mb { + + u32 link_status; + /* Driver should update this field on any link change event */ + + #define LINK_STATUS_LINK_FLAG_MASK 0x00000001 + #define LINK_STATUS_LINK_UP 0x00000001 + #define LINK_STATUS_SPEED_AND_DUPLEX_MASK 0x0000001E + #define LINK_STATUS_SPEED_AND_DUPLEX_AN_NOT_COMPLETE (0<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_10THD (1<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_10TFD (2<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_100TXHD (3<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_100T4 (4<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_100TXFD (5<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_1000THD (6<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_1000TFD (7<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_1000XFD (7<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_2500THD (8<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_2500TFD (9<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_2500XFD (9<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_10GTFD (10<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_10GXFD (10<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_20GTFD (11<<1) + #define LINK_STATUS_SPEED_AND_DUPLEX_20GXFD (11<<1) + + #define LINK_STATUS_AUTO_NEGOTIATE_FLAG_MASK 0x00000020 + #define LINK_STATUS_AUTO_NEGOTIATE_ENABLED 0x00000020 + + #define LINK_STATUS_AUTO_NEGOTIATE_COMPLETE 0x00000040 + #define LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK 0x00000080 + #define LINK_STATUS_PARALLEL_DETECTION_USED 0x00000080 + + #define LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE 0x00000200 + #define LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE 0x00000400 + #define LINK_STATUS_LINK_PARTNER_100T4_CAPABLE 0x00000800 + #define LINK_STATUS_LINK_PARTNER_100TXFD_CAPABLE 0x00001000 + #define LINK_STATUS_LINK_PARTNER_100TXHD_CAPABLE 0x00002000 + #define LINK_STATUS_LINK_PARTNER_10TFD_CAPABLE 0x00004000 + #define LINK_STATUS_LINK_PARTNER_10THD_CAPABLE 0x00008000 + + #define LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK 0x00010000 + #define LINK_STATUS_TX_FLOW_CONTROL_ENABLED 0x00010000 + + #define LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK 0x00020000 + #define LINK_STATUS_RX_FLOW_CONTROL_ENABLED 0x00020000 + + #define LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK 0x000C0000 + #define LINK_STATUS_LINK_PARTNER_NOT_PAUSE_CAPABLE (0<<18) + #define LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE (1<<18) + #define LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE (2<<18) + #define LINK_STATUS_LINK_PARTNER_BOTH_PAUSE (3<<18) + + #define LINK_STATUS_SERDES_LINK 0x00100000 + + #define LINK_STATUS_LINK_PARTNER_2500XFD_CAPABLE 0x00200000 + #define LINK_STATUS_LINK_PARTNER_2500XHD_CAPABLE 0x00400000 + #define LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE 0x00800000 + #define LINK_STATUS_LINK_PARTNER_20GXFD_CAPABLE 0x10000000 + + #define LINK_STATUS_PFC_ENABLED 0x20000000 + + #define LINK_STATUS_PHYSICAL_LINK_FLAG 0x40000000 + + u32 port_stx; + + u32 stat_nig_timer; + + /* MCP firmware does not use this field */ + u32 ext_phy_fw_version; + +}; + + +struct drv_func_mb { + + u32 drv_mb_header; + #define DRV_MSG_CODE_MASK 0xffff0000 + #define DRV_MSG_CODE_LOAD_REQ 0x10000000 + #define DRV_MSG_CODE_LOAD_DONE 0x11000000 + #define DRV_MSG_CODE_UNLOAD_REQ_WOL_EN 0x20000000 + #define DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS 0x20010000 + #define DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP 0x20020000 + #define DRV_MSG_CODE_UNLOAD_DONE 0x21000000 + #define DRV_MSG_CODE_DCC_OK 0x30000000 + #define DRV_MSG_CODE_DCC_FAILURE 0x31000000 + #define DRV_MSG_CODE_DIAG_ENTER_REQ 0x50000000 + #define DRV_MSG_CODE_DIAG_EXIT_REQ 0x60000000 + #define DRV_MSG_CODE_VALIDATE_KEY 0x70000000 + #define DRV_MSG_CODE_GET_CURR_KEY 0x80000000 + #define DRV_MSG_CODE_GET_UPGRADE_KEY 0x81000000 + #define DRV_MSG_CODE_GET_MANUF_KEY 0x82000000 + #define DRV_MSG_CODE_LOAD_L2B_PRAM 0x90000000 + /* + * The optic module verification command requires bootcode + * v5.0.6 or later, te specific optic module verification command + * requires bootcode v5.2.12 or later + */ + #define DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL 0xa0000000 + #define REQ_BC_VER_4_VRFY_FIRST_PHY_OPT_MDL 0x00050006 + #define DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL 0xa1000000 + #define REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL 0x00050234 + #define REQ_BC_VER_4_SFP_TX_DISABLE_SUPPORTED 0x00070014 + + #define DRV_MSG_CODE_DCBX_ADMIN_PMF_MSG 0xb0000000 + #define DRV_MSG_CODE_DCBX_PMF_DRV_OK 0xb2000000 + + #define DRV_MSG_CODE_VF_DISABLED_DONE 0xc0000000 + + #define DRV_MSG_CODE_SET_MF_BW 0xe0000000 + #define REQ_BC_VER_4_SET_MF_BW 0x00060202 + #define DRV_MSG_CODE_SET_MF_BW_ACK 0xe1000000 + + #define DRV_MSG_CODE_LINK_STATUS_CHANGED 0x01000000 + + #define BIOS_MSG_CODE_LIC_CHALLENGE 0xff010000 + #define BIOS_MSG_CODE_LIC_RESPONSE 0xff020000 + #define BIOS_MSG_CODE_VIRT_MAC_PRIM 0xff030000 + #define BIOS_MSG_CODE_VIRT_MAC_ISCSI 0xff040000 + + #define DRV_MSG_SEQ_NUMBER_MASK 0x0000ffff + + u32 drv_mb_param; + #define DRV_MSG_CODE_SET_MF_BW_MIN_MASK 0x00ff0000 + #define DRV_MSG_CODE_SET_MF_BW_MAX_MASK 0xff000000 + + u32 fw_mb_header; + #define FW_MSG_CODE_MASK 0xffff0000 + #define FW_MSG_CODE_DRV_LOAD_COMMON 0x10100000 + #define FW_MSG_CODE_DRV_LOAD_PORT 0x10110000 + #define FW_MSG_CODE_DRV_LOAD_FUNCTION 0x10120000 + /* Load common chip is supported from bc 6.0.0 */ + #define REQ_BC_VER_4_DRV_LOAD_COMMON_CHIP 0x00060000 + #define FW_MSG_CODE_DRV_LOAD_COMMON_CHIP 0x10130000 + + #define FW_MSG_CODE_DRV_LOAD_REFUSED 0x10200000 + #define FW_MSG_CODE_DRV_LOAD_DONE 0x11100000 + #define FW_MSG_CODE_DRV_UNLOAD_COMMON 0x20100000 + #define FW_MSG_CODE_DRV_UNLOAD_PORT 0x20110000 + #define FW_MSG_CODE_DRV_UNLOAD_FUNCTION 0x20120000 + #define FW_MSG_CODE_DRV_UNLOAD_DONE 0x21100000 + #define FW_MSG_CODE_DCC_DONE 0x30100000 + #define FW_MSG_CODE_LLDP_DONE 0x40100000 + #define FW_MSG_CODE_DIAG_ENTER_DONE 0x50100000 + #define FW_MSG_CODE_DIAG_REFUSE 0x50200000 + #define FW_MSG_CODE_DIAG_EXIT_DONE 0x60100000 + #define FW_MSG_CODE_VALIDATE_KEY_SUCCESS 0x70100000 + #define FW_MSG_CODE_VALIDATE_KEY_FAILURE 0x70200000 + #define FW_MSG_CODE_GET_KEY_DONE 0x80100000 + #define FW_MSG_CODE_NO_KEY 0x80f00000 + #define FW_MSG_CODE_LIC_INFO_NOT_READY 0x80f80000 + #define FW_MSG_CODE_L2B_PRAM_LOADED 0x90100000 + #define FW_MSG_CODE_L2B_PRAM_T_LOAD_FAILURE 0x90210000 + #define FW_MSG_CODE_L2B_PRAM_C_LOAD_FAILURE 0x90220000 + #define FW_MSG_CODE_L2B_PRAM_X_LOAD_FAILURE 0x90230000 + #define FW_MSG_CODE_L2B_PRAM_U_LOAD_FAILURE 0x90240000 + #define FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS 0xa0100000 + #define FW_MSG_CODE_VRFY_OPT_MDL_INVLD_IMG 0xa0200000 + #define FW_MSG_CODE_VRFY_OPT_MDL_UNAPPROVED 0xa0300000 + #define FW_MSG_CODE_VF_DISABLED_DONE 0xb0000000 + + #define FW_MSG_CODE_SET_MF_BW_SENT 0xe0000000 + #define FW_MSG_CODE_SET_MF_BW_DONE 0xe1000000 + + #define FW_MSG_CODE_LINK_CHANGED_ACK 0x01100000 + + #define FW_MSG_CODE_LIC_CHALLENGE 0xff010000 + #define FW_MSG_CODE_LIC_RESPONSE 0xff020000 + #define FW_MSG_CODE_VIRT_MAC_PRIM 0xff030000 + #define FW_MSG_CODE_VIRT_MAC_ISCSI 0xff040000 + + #define FW_MSG_SEQ_NUMBER_MASK 0x0000ffff + + u32 fw_mb_param; + + u32 drv_pulse_mb; + #define DRV_PULSE_SEQ_MASK 0x00007fff + #define DRV_PULSE_SYSTEM_TIME_MASK 0xffff0000 + /* + * The system time is in the format of + * (year-2001)*12*32 + month*32 + day. + */ + #define DRV_PULSE_ALWAYS_ALIVE 0x00008000 + /* + * Indicate to the firmware not to go into the + * OS-absent when it is not getting driver pulse. + * This is used for debugging as well for PXE(MBA). + */ + + u32 mcp_pulse_mb; + #define MCP_PULSE_SEQ_MASK 0x00007fff + #define MCP_PULSE_ALWAYS_ALIVE 0x00008000 + /* Indicates to the driver not to assert due to lack + * of MCP response */ + #define MCP_EVENT_MASK 0xffff0000 + #define MCP_EVENT_OTHER_DRIVER_RESET_REQ 0x00010000 + + u32 iscsi_boot_signature; + u32 iscsi_boot_block_offset; + + u32 drv_status; + #define DRV_STATUS_PMF 0x00000001 + #define DRV_STATUS_VF_DISABLED 0x00000002 + #define DRV_STATUS_SET_MF_BW 0x00000004 + #define DRV_STATUS_LINK_EVENT 0x00000008 + + #define DRV_STATUS_DCC_EVENT_MASK 0x0000ff00 + #define DRV_STATUS_DCC_DISABLE_ENABLE_PF 0x00000100 + #define DRV_STATUS_DCC_BANDWIDTH_ALLOCATION 0x00000200 + #define DRV_STATUS_DCC_CHANGE_MAC_ADDRESS 0x00000400 + #define DRV_STATUS_DCC_RESERVED1 0x00000800 + #define DRV_STATUS_DCC_SET_PROTOCOL 0x00001000 + #define DRV_STATUS_DCC_SET_PRIORITY 0x00002000 + + #define DRV_STATUS_DCBX_EVENT_MASK 0x000f0000 + #define DRV_STATUS_DCBX_NEGOTIATION_RESULTS 0x00010000 + + u32 virt_mac_upper; + #define VIRT_MAC_SIGN_MASK 0xffff0000 + #define VIRT_MAC_SIGNATURE 0x564d0000 + u32 virt_mac_lower; + +}; + + +/**************************************************************************** + * Management firmware state * + ****************************************************************************/ +/* Allocate 440 bytes for management firmware */ +#define MGMTFW_STATE_WORD_SIZE 110 + +struct mgmtfw_state { + u32 opaque[MGMTFW_STATE_WORD_SIZE]; +}; + + +/**************************************************************************** + * Multi-Function configuration * + ****************************************************************************/ +struct shared_mf_cfg { + + u32 clp_mb; + #define SHARED_MF_CLP_SET_DEFAULT 0x00000000 + /* set by CLP */ + #define SHARED_MF_CLP_EXIT 0x00000001 + /* set by MCP */ + #define SHARED_MF_CLP_EXIT_DONE 0x00010000 + +}; + +struct port_mf_cfg { + + u32 dynamic_cfg; /* device control channel */ + #define PORT_MF_CFG_E1HOV_TAG_MASK 0x0000ffff + #define PORT_MF_CFG_E1HOV_TAG_SHIFT 0 + #define PORT_MF_CFG_E1HOV_TAG_DEFAULT PORT_MF_CFG_E1HOV_TAG_MASK + + u32 reserved[3]; + +}; + +struct func_mf_cfg { + + u32 config; + /* E/R/I/D */ + /* function 0 of each port cannot be hidden */ + #define FUNC_MF_CFG_FUNC_HIDE 0x00000001 + + #define FUNC_MF_CFG_PROTOCOL_MASK 0x00000006 + #define FUNC_MF_CFG_PROTOCOL_FCOE 0x00000000 + #define FUNC_MF_CFG_PROTOCOL_ETHERNET 0x00000002 + #define FUNC_MF_CFG_PROTOCOL_ETHERNET_WITH_RDMA 0x00000004 + #define FUNC_MF_CFG_PROTOCOL_ISCSI 0x00000006 + #define FUNC_MF_CFG_PROTOCOL_DEFAULT \ + FUNC_MF_CFG_PROTOCOL_ETHERNET_WITH_RDMA + + #define FUNC_MF_CFG_FUNC_DISABLED 0x00000008 + #define FUNC_MF_CFG_FUNC_DELETED 0x00000010 + + /* PRI */ + /* 0 - low priority, 3 - high priority */ + #define FUNC_MF_CFG_TRANSMIT_PRIORITY_MASK 0x00000300 + #define FUNC_MF_CFG_TRANSMIT_PRIORITY_SHIFT 8 + #define FUNC_MF_CFG_TRANSMIT_PRIORITY_DEFAULT 0x00000000 + + /* MINBW, MAXBW */ + /* value range - 0..100, increments in 100Mbps */ + #define FUNC_MF_CFG_MIN_BW_MASK 0x00ff0000 + #define FUNC_MF_CFG_MIN_BW_SHIFT 16 + #define FUNC_MF_CFG_MIN_BW_DEFAULT 0x00000000 + #define FUNC_MF_CFG_MAX_BW_MASK 0xff000000 + #define FUNC_MF_CFG_MAX_BW_SHIFT 24 + #define FUNC_MF_CFG_MAX_BW_DEFAULT 0x64000000 + + u32 mac_upper; /* MAC */ + #define FUNC_MF_CFG_UPPERMAC_MASK 0x0000ffff + #define FUNC_MF_CFG_UPPERMAC_SHIFT 0 + #define FUNC_MF_CFG_UPPERMAC_DEFAULT FUNC_MF_CFG_UPPERMAC_MASK + u32 mac_lower; + #define FUNC_MF_CFG_LOWERMAC_DEFAULT 0xffffffff + + u32 e1hov_tag; /* VNI */ + #define FUNC_MF_CFG_E1HOV_TAG_MASK 0x0000ffff + #define FUNC_MF_CFG_E1HOV_TAG_SHIFT 0 + #define FUNC_MF_CFG_E1HOV_TAG_DEFAULT FUNC_MF_CFG_E1HOV_TAG_MASK + + u32 reserved[2]; +}; + +/* This structure is not applicable and should not be accessed on 57711 */ +struct func_ext_cfg { + u32 func_cfg; + #define MACP_FUNC_CFG_FLAGS_MASK 0x000000FF + #define MACP_FUNC_CFG_FLAGS_SHIFT 0 + #define MACP_FUNC_CFG_FLAGS_ENABLED 0x00000001 + #define MACP_FUNC_CFG_FLAGS_ETHERNET 0x00000002 + #define MACP_FUNC_CFG_FLAGS_ISCSI_OFFLOAD 0x00000004 + #define MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD 0x00000008 + + u32 iscsi_mac_addr_upper; + u32 iscsi_mac_addr_lower; + + u32 fcoe_mac_addr_upper; + u32 fcoe_mac_addr_lower; + + u32 fcoe_wwn_port_name_upper; + u32 fcoe_wwn_port_name_lower; + + u32 fcoe_wwn_node_name_upper; + u32 fcoe_wwn_node_name_lower; + + u32 preserve_data; + #define MF_FUNC_CFG_PRESERVE_L2_MAC (1<<0) + #define MF_FUNC_CFG_PRESERVE_ISCSI_MAC (1<<1) + #define MF_FUNC_CFG_PRESERVE_FCOE_MAC (1<<2) + #define MF_FUNC_CFG_PRESERVE_FCOE_WWN_P (1<<3) + #define MF_FUNC_CFG_PRESERVE_FCOE_WWN_N (1<<4) + #define MF_FUNC_CFG_PRESERVE_TX_BW (1<<5) +}; + +struct mf_cfg { + + struct shared_mf_cfg shared_mf_config; /* 0x4 */ + struct port_mf_cfg port_mf_config[PORT_MAX]; /* 0x10 * 2 = 0x20 */ + /* for all chips, there are 8 mf functions */ + struct func_mf_cfg func_mf_config[E1H_FUNC_MAX]; /* 0x18 * 8 = 0xc0 */ + /* + * Extended configuration per function - this array does not exist and + * should not be accessed on 57711 + */ + struct func_ext_cfg func_ext_config[E1H_FUNC_MAX]; /* 0x28 * 8 = 0x140*/ +}; /* 0x224 */ + +/**************************************************************************** + * Shared Memory Region * + ****************************************************************************/ +struct shmem_region { /* SharedMem Offset (size) */ + + u32 validity_map[PORT_MAX]; /* 0x0 (4*2 = 0x8) */ + #define SHR_MEM_FORMAT_REV_MASK 0xff000000 + #define SHR_MEM_FORMAT_REV_ID ('A'<<24) + /* validity bits */ + #define SHR_MEM_VALIDITY_PCI_CFG 0x00100000 + #define SHR_MEM_VALIDITY_MB 0x00200000 + #define SHR_MEM_VALIDITY_DEV_INFO 0x00400000 + #define SHR_MEM_VALIDITY_RESERVED 0x00000007 + /* One licensing bit should be set */ + #define SHR_MEM_VALIDITY_LIC_KEY_IN_EFFECT_MASK 0x00000038 + #define SHR_MEM_VALIDITY_LIC_MANUF_KEY_IN_EFFECT 0x00000008 + #define SHR_MEM_VALIDITY_LIC_UPGRADE_KEY_IN_EFFECT 0x00000010 + #define SHR_MEM_VALIDITY_LIC_NO_KEY_IN_EFFECT 0x00000020 + /* Active MFW */ + #define SHR_MEM_VALIDITY_ACTIVE_MFW_UNKNOWN 0x00000000 + #define SHR_MEM_VALIDITY_ACTIVE_MFW_MASK 0x000001c0 + #define SHR_MEM_VALIDITY_ACTIVE_MFW_IPMI 0x00000040 + #define SHR_MEM_VALIDITY_ACTIVE_MFW_UMP 0x00000080 + #define SHR_MEM_VALIDITY_ACTIVE_MFW_NCSI 0x000000c0 + #define SHR_MEM_VALIDITY_ACTIVE_MFW_NONE 0x000001c0 + + struct shm_dev_info dev_info; /* 0x8 (0x438) */ + + struct license_key drv_lic_key[PORT_MAX]; /* 0x440 (52*2=0x68) */ + + /* FW information (for internal FW use) */ + u32 fw_info_fio_offset; /* 0x4a8 (0x4) */ + struct mgmtfw_state mgmtfw_state; /* 0x4ac (0x1b8) */ + + struct drv_port_mb port_mb[PORT_MAX]; /* 0x664 (16*2=0x20) */ + +#ifdef BMAPI + /* This is a variable length array */ + /* the number of function depends on the chip type */ + struct drv_func_mb func_mb[1]; /* 0x684 (44*2/4/8=0x58/0xb0/0x160) */ +#else + /* the number of function depends on the chip type */ + struct drv_func_mb func_mb[]; /* 0x684 (44*2/4/8=0x58/0xb0/0x160) */ +#endif /* BMAPI */ + +}; /* 57710 = 0x6dc | 57711 = 0x7E4 | 57712 = 0x734 */ + +/**************************************************************************** + * Shared Memory 2 Region * + ****************************************************************************/ +/* The fw_flr_ack is actually built in the following way: */ +/* 8 bit: PF ack */ +/* 64 bit: VF ack */ +/* 8 bit: ios_dis_ack */ +/* In order to maintain endianity in the mailbox hsi, we want to keep using */ +/* u32. The fw must have the VF right after the PF since this is how it */ +/* access arrays(it expects always the VF to reside after the PF, and that */ +/* makes the calculation much easier for it. ) */ +/* In order to answer both limitations, and keep the struct small, the code */ +/* will abuse the structure defined here to achieve the actual partition */ +/* above */ +/****************************************************************************/ +struct fw_flr_ack { + u32 pf_ack; + u32 vf_ack[1]; + u32 iov_dis_ack; +}; + +struct fw_flr_mb { + u32 aggint; + u32 opgen_addr; + struct fw_flr_ack ack; +}; + +/**** SUPPORT FOR SHMEM ARRRAYS *** + * The SHMEM HSI is aligned on 32 bit boundaries which makes it difficult to + * define arrays with storage types smaller then unsigned dwords. + * The macros below add generic support for SHMEM arrays with numeric elements + * that can span 2,4,8 or 16 bits. The array underlying type is a 32 bit dword + * array with individual bit-filed elements accessed using shifts and masks. + * + */ + +/* eb is the bitwidth of a single element */ +#define SHMEM_ARRAY_MASK(eb) ((1<<(eb))-1) +#define SHMEM_ARRAY_ENTRY(i, eb) ((i)/(32/(eb))) + +/* the bit-position macro allows the used to flip the order of the arrays + * elements on a per byte or word boundary. + * + * example: an array with 8 entries each 4 bit wide. This array will fit into + * a single dword. The diagrmas below show the array order of the nibbles. + * + * SHMEM_ARRAY_BITPOS(i, 4, 4) defines the stadard ordering: + * + * | | | | + * 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + * | | | | + * + * SHMEM_ARRAY_BITPOS(i, 4, 8) defines a flip ordering per byte: + * + * | | | | + * 1 | 0 | 3 | 2 | 5 | 4 | 7 | 6 | + * | | | | + * + * SHMEM_ARRAY_BITPOS(i, 4, 16) defines a flip ordering per word: + * + * | | | | + * 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | + * | | | | + */ +#define SHMEM_ARRAY_BITPOS(i, eb, fb) \ + ((((32/(fb)) - 1 - ((i)/((fb)/(eb))) % (32/(fb))) * (fb)) + \ + (((i)%((fb)/(eb))) * (eb))) + +#define SHMEM_ARRAY_GET(a, i, eb, fb) \ + ((a[SHMEM_ARRAY_ENTRY(i, eb)] >> SHMEM_ARRAY_BITPOS(i, eb, fb)) & \ + SHMEM_ARRAY_MASK(eb)) + +#define SHMEM_ARRAY_SET(a, i, eb, fb, val) \ +do { \ + a[SHMEM_ARRAY_ENTRY(i, eb)] &= ~(SHMEM_ARRAY_MASK(eb) << \ + SHMEM_ARRAY_BITPOS(i, eb, fb)); \ + a[SHMEM_ARRAY_ENTRY(i, eb)] |= (((val) & SHMEM_ARRAY_MASK(eb)) << \ + SHMEM_ARRAY_BITPOS(i, eb, fb)); \ +} while (0) + + +/****START OF DCBX STRUCTURES DECLARATIONS****/ +#define DCBX_MAX_NUM_PRI_PG_ENTRIES 8 +#define DCBX_PRI_PG_BITWIDTH 4 +#define DCBX_PRI_PG_FBITS 8 +#define DCBX_PRI_PG_GET(a, i) \ + SHMEM_ARRAY_GET(a, i, DCBX_PRI_PG_BITWIDTH, DCBX_PRI_PG_FBITS) +#define DCBX_PRI_PG_SET(a, i, val) \ + SHMEM_ARRAY_SET(a, i, DCBX_PRI_PG_BITWIDTH, DCBX_PRI_PG_FBITS, val) +#define DCBX_MAX_NUM_PG_BW_ENTRIES 8 +#define DCBX_BW_PG_BITWIDTH 8 +#define DCBX_PG_BW_GET(a, i) \ + SHMEM_ARRAY_GET(a, i, DCBX_BW_PG_BITWIDTH, DCBX_BW_PG_BITWIDTH) +#define DCBX_PG_BW_SET(a, i, val) \ + SHMEM_ARRAY_SET(a, i, DCBX_BW_PG_BITWIDTH, DCBX_BW_PG_BITWIDTH, val) +#define DCBX_STRICT_PRI_PG 15 +#define DCBX_MAX_APP_PROTOCOL 16 +#define FCOE_APP_IDX 0 +#define ISCSI_APP_IDX 1 +#define PREDEFINED_APP_IDX_MAX 2 + + +/* Big/Little endian have the same representation. */ +struct dcbx_ets_feature { + /* + * For Admin MIB - is this feature supported by the + * driver | For Local MIB - should this feature be enabled. + */ + u32 enabled; + u32 pg_bw_tbl[2]; + u32 pri_pg_tbl[1]; +}; + +/* Driver structure in LE */ +struct dcbx_pfc_feature { +#ifdef __BIG_ENDIAN + u8 pri_en_bitmap; + #define DCBX_PFC_PRI_0 0x01 + #define DCBX_PFC_PRI_1 0x02 + #define DCBX_PFC_PRI_2 0x04 + #define DCBX_PFC_PRI_3 0x08 + #define DCBX_PFC_PRI_4 0x10 + #define DCBX_PFC_PRI_5 0x20 + #define DCBX_PFC_PRI_6 0x40 + #define DCBX_PFC_PRI_7 0x80 + u8 pfc_caps; + u8 reserved; + u8 enabled; +#elif defined(__LITTLE_ENDIAN) + u8 enabled; + u8 reserved; + u8 pfc_caps; + u8 pri_en_bitmap; + #define DCBX_PFC_PRI_0 0x01 + #define DCBX_PFC_PRI_1 0x02 + #define DCBX_PFC_PRI_2 0x04 + #define DCBX_PFC_PRI_3 0x08 + #define DCBX_PFC_PRI_4 0x10 + #define DCBX_PFC_PRI_5 0x20 + #define DCBX_PFC_PRI_6 0x40 + #define DCBX_PFC_PRI_7 0x80 +#endif +}; + +struct dcbx_app_priority_entry { +#ifdef __BIG_ENDIAN + u16 app_id; + u8 pri_bitmap; + u8 appBitfield; + #define DCBX_APP_ENTRY_VALID 0x01 + #define DCBX_APP_ENTRY_SF_MASK 0x30 + #define DCBX_APP_ENTRY_SF_SHIFT 4 + #define DCBX_APP_SF_ETH_TYPE 0x10 + #define DCBX_APP_SF_PORT 0x20 +#elif defined(__LITTLE_ENDIAN) + u8 appBitfield; + #define DCBX_APP_ENTRY_VALID 0x01 + #define DCBX_APP_ENTRY_SF_MASK 0x30 + #define DCBX_APP_ENTRY_SF_SHIFT 4 + #define DCBX_APP_SF_ETH_TYPE 0x10 + #define DCBX_APP_SF_PORT 0x20 + u8 pri_bitmap; + u16 app_id; +#endif +}; + + +/* FW structure in BE */ +struct dcbx_app_priority_feature { +#ifdef __BIG_ENDIAN + u8 reserved; + u8 default_pri; + u8 tc_supported; + u8 enabled; +#elif defined(__LITTLE_ENDIAN) + u8 enabled; + u8 tc_supported; + u8 default_pri; + u8 reserved; +#endif + struct dcbx_app_priority_entry app_pri_tbl[DCBX_MAX_APP_PROTOCOL]; +}; + +/* FW structure in BE */ +struct dcbx_features { + /* PG feature */ + struct dcbx_ets_feature ets; + /* PFC feature */ + struct dcbx_pfc_feature pfc; + /* APP feature */ + struct dcbx_app_priority_feature app; +}; + +/* LLDP protocol parameters */ +/* FW structure in BE */ +struct lldp_params { +#ifdef __BIG_ENDIAN + u8 msg_fast_tx_interval; + u8 msg_tx_hold; + u8 msg_tx_interval; + u8 admin_status; + #define LLDP_TX_ONLY 0x01 + #define LLDP_RX_ONLY 0x02 + #define LLDP_TX_RX 0x03 + #define LLDP_DISABLED 0x04 + u8 reserved1; + u8 tx_fast; + u8 tx_crd_max; + u8 tx_crd; +#elif defined(__LITTLE_ENDIAN) + u8 admin_status; + #define LLDP_TX_ONLY 0x01 + #define LLDP_RX_ONLY 0x02 + #define LLDP_TX_RX 0x03 + #define LLDP_DISABLED 0x04 + u8 msg_tx_interval; + u8 msg_tx_hold; + u8 msg_fast_tx_interval; + u8 tx_crd; + u8 tx_crd_max; + u8 tx_fast; + u8 reserved1; +#endif + #define REM_CHASSIS_ID_STAT_LEN 4 + #define REM_PORT_ID_STAT_LEN 4 + /* Holds remote Chassis ID TLV header, subtype and 9B of payload. */ + u32 peer_chassis_id[REM_CHASSIS_ID_STAT_LEN]; + /* Holds remote Port ID TLV header, subtype and 9B of payload. */ + u32 peer_port_id[REM_PORT_ID_STAT_LEN]; +}; + +struct lldp_dcbx_stat { + #define LOCAL_CHASSIS_ID_STAT_LEN 2 + #define LOCAL_PORT_ID_STAT_LEN 2 + /* Holds local Chassis ID 8B payload of constant subtype 4. */ + u32 local_chassis_id[LOCAL_CHASSIS_ID_STAT_LEN]; + /* Holds local Port ID 8B payload of constant subtype 3. */ + u32 local_port_id[LOCAL_PORT_ID_STAT_LEN]; + /* Number of DCBX frames transmitted. */ + u32 num_tx_dcbx_pkts; + /* Number of DCBX frames received. */ + u32 num_rx_dcbx_pkts; +}; + +/* ADMIN MIB - DCBX local machine default configuration. */ +struct lldp_admin_mib { + u32 ver_cfg_flags; + #define DCBX_ETS_CONFIG_TX_ENABLED 0x00000001 + #define DCBX_PFC_CONFIG_TX_ENABLED 0x00000002 + #define DCBX_APP_CONFIG_TX_ENABLED 0x00000004 + #define DCBX_ETS_RECO_TX_ENABLED 0x00000008 + #define DCBX_ETS_RECO_VALID 0x00000010 + #define DCBX_ETS_WILLING 0x00000020 + #define DCBX_PFC_WILLING 0x00000040 + #define DCBX_APP_WILLING 0x00000080 + #define DCBX_VERSION_CEE 0x00000100 + #define DCBX_VERSION_IEEE 0x00000200 + #define DCBX_DCBX_ENABLED 0x00000400 + #define DCBX_CEE_VERSION_MASK 0x0000f000 + #define DCBX_CEE_VERSION_SHIFT 12 + #define DCBX_CEE_MAX_VERSION_MASK 0x000f0000 + #define DCBX_CEE_MAX_VERSION_SHIFT 16 + struct dcbx_features features; +}; + +/* REMOTE MIB - remote machine DCBX configuration. */ +struct lldp_remote_mib { + u32 prefix_seq_num; + u32 flags; + #define DCBX_ETS_TLV_RX 0x00000001 + #define DCBX_PFC_TLV_RX 0x00000002 + #define DCBX_APP_TLV_RX 0x00000004 + #define DCBX_ETS_RX_ERROR 0x00000010 + #define DCBX_PFC_RX_ERROR 0x00000020 + #define DCBX_APP_RX_ERROR 0x00000040 + #define DCBX_ETS_REM_WILLING 0x00000100 + #define DCBX_PFC_REM_WILLING 0x00000200 + #define DCBX_APP_REM_WILLING 0x00000400 + #define DCBX_REMOTE_ETS_RECO_VALID 0x00001000 + #define DCBX_REMOTE_MIB_VALID 0x00002000 + struct dcbx_features features; + u32 suffix_seq_num; +}; + +/* LOCAL MIB - operational DCBX configuration - transmitted on Tx LLDPDU. */ +struct lldp_local_mib { + u32 prefix_seq_num; + /* Indicates if there is mismatch with negotiation results. */ + u32 error; + #define DCBX_LOCAL_ETS_ERROR 0x00000001 + #define DCBX_LOCAL_PFC_ERROR 0x00000002 + #define DCBX_LOCAL_APP_ERROR 0x00000004 + #define DCBX_LOCAL_PFC_MISMATCH 0x00000010 + #define DCBX_LOCAL_APP_MISMATCH 0x00000020 + #define DCBX_REMOTE_MIB_ERROR 0x00000040 + struct dcbx_features features; + u32 suffix_seq_num; +}; +/***END OF DCBX STRUCTURES DECLARATIONS***/ + +struct ncsi_oem_fcoe_features { + u32 fcoe_features1; + #define FCOE_FEATURES1_IOS_PER_CONNECTION_MASK 0x0000FFFF + #define FCOE_FEATURES1_IOS_PER_CONNECTION_OFFSET 0 + + #define FCOE_FEATURES1_LOGINS_PER_PORT_MASK 0xFFFF0000 + #define FCOE_FEATURES1_LOGINS_PER_PORT_OFFSET 16 + + u32 fcoe_features2; + #define FCOE_FEATURES2_EXCHANGES_MASK 0x0000FFFF + #define FCOE_FEATURES2_EXCHANGES_OFFSET 0 + + #define FCOE_FEATURES2_NPIV_WWN_PER_PORT_MASK 0xFFFF0000 + #define FCOE_FEATURES2_NPIV_WWN_PER_PORT_OFFSET 16 + + u32 fcoe_features3; + #define FCOE_FEATURES3_TARGETS_SUPPORTED_MASK 0x0000FFFF + #define FCOE_FEATURES3_TARGETS_SUPPORTED_OFFSET 0 + + #define FCOE_FEATURES3_OUTSTANDING_COMMANDS_MASK 0xFFFF0000 + #define FCOE_FEATURES3_OUTSTANDING_COMMANDS_OFFSET 16 + + u32 fcoe_features4; + #define FCOE_FEATURES4_FEATURE_SETTINGS_MASK 0x0000000F + #define FCOE_FEATURES4_FEATURE_SETTINGS_OFFSET 0 +}; + +struct ncsi_oem_data { + u32 driver_version[4]; + struct ncsi_oem_fcoe_features ncsi_oem_fcoe_features; +}; + +struct shmem2_region { + + u32 size; /* 0x0000 */ + + u32 dcc_support; /* 0x0004 */ + #define SHMEM_DCC_SUPPORT_NONE 0x00000000 + #define SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV 0x00000001 + #define SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV 0x00000004 + #define SHMEM_DCC_SUPPORT_CHANGE_MAC_ADDRESS_TLV 0x00000008 + #define SHMEM_DCC_SUPPORT_SET_PROTOCOL_TLV 0x00000040 + #define SHMEM_DCC_SUPPORT_SET_PRIORITY_TLV 0x00000080 + + u32 ext_phy_fw_version2[PORT_MAX]; /* 0x0008 */ + /* + * For backwards compatibility, if the mf_cfg_addr does not exist + * (the size filed is smaller than 0xc) the mf_cfg resides at the + * end of struct shmem_region + */ + u32 mf_cfg_addr; /* 0x0010 */ + #define SHMEM_MF_CFG_ADDR_NONE 0x00000000 + + struct fw_flr_mb flr_mb; /* 0x0014 */ + u32 dcbx_lldp_params_offset; /* 0x0028 */ + #define SHMEM_LLDP_DCBX_PARAMS_NONE 0x00000000 + u32 dcbx_neg_res_offset; /* 0x002c */ + #define SHMEM_DCBX_NEG_RES_NONE 0x00000000 + u32 dcbx_remote_mib_offset; /* 0x0030 */ + #define SHMEM_DCBX_REMOTE_MIB_NONE 0x00000000 + /* + * The other shmemX_base_addr holds the other path's shmem address + * required for example in case of common phy init, or for path1 to know + * the address of mcp debug trace which is located in offset from shmem + * of path0 + */ + u32 other_shmem_base_addr; /* 0x0034 */ + u32 other_shmem2_base_addr; /* 0x0038 */ + /* + * mcp_vf_disabled is set by the MCP to indicate the driver about VFs + * which were disabled/flred + */ + u32 mcp_vf_disabled[E2_VF_MAX / 32]; /* 0x003c */ + + /* + * drv_ack_vf_disabled is set by the PF driver to ack handled disabled + * VFs + */ + u32 drv_ack_vf_disabled[E2_FUNC_MAX][E2_VF_MAX / 32]; /* 0x0044 */ + + u32 dcbx_lldp_dcbx_stat_offset; /* 0x0064 */ + #define SHMEM_LLDP_DCBX_STAT_NONE 0x00000000 + + /* + * edebug_driver_if field is used to transfer messages between edebug + * app to the driver through shmem2. + * + * message format: + * bits 0-2 - function number / instance of driver to perform request + * bits 3-5 - op code / is_ack? + * bits 6-63 - data + */ + u32 edebug_driver_if[2]; /* 0x0068 */ + #define EDEBUG_DRIVER_IF_OP_CODE_GET_PHYS_ADDR 1 + #define EDEBUG_DRIVER_IF_OP_CODE_GET_BUS_ADDR 2 + #define EDEBUG_DRIVER_IF_OP_CODE_DISABLE_STAT 3 + + u32 nvm_retain_bitmap_addr; /* 0x0070 */ + + u32 reserved1; /* 0x0074 */ + + u32 reserved2[E2_FUNC_MAX]; + + u32 reserved3[E2_FUNC_MAX];/* 0x0088 */ + u32 reserved4[E2_FUNC_MAX];/* 0x0098 */ + + u32 swim_base_addr; /* 0x0108 */ + u32 swim_funcs; + u32 swim_main_cb; + + u32 reserved5[2]; + + /* generic flags controlled by the driver */ + u32 drv_flags; + #define DRV_FLAGS_DCB_CONFIGURED 0x1 + + /* pointer to extended dev_info shared data copied from nvm image */ + u32 extended_dev_info_shared_addr; + u32 ncsi_oem_data_addr; + + u32 ocsd_host_addr; + u32 ocbb_host_addr; + u32 ocsd_req_update_interval; +}; + + +struct emac_stats { + u32 rx_stat_ifhcinoctets; + u32 rx_stat_ifhcinbadoctets; + u32 rx_stat_etherstatsfragments; + u32 rx_stat_ifhcinucastpkts; + u32 rx_stat_ifhcinmulticastpkts; + u32 rx_stat_ifhcinbroadcastpkts; + u32 rx_stat_dot3statsfcserrors; + u32 rx_stat_dot3statsalignmenterrors; + u32 rx_stat_dot3statscarriersenseerrors; + u32 rx_stat_xonpauseframesreceived; + u32 rx_stat_xoffpauseframesreceived; + u32 rx_stat_maccontrolframesreceived; + u32 rx_stat_xoffstateentered; + u32 rx_stat_dot3statsframestoolong; + u32 rx_stat_etherstatsjabbers; + u32 rx_stat_etherstatsundersizepkts; + u32 rx_stat_etherstatspkts64octets; + u32 rx_stat_etherstatspkts65octetsto127octets; + u32 rx_stat_etherstatspkts128octetsto255octets; + u32 rx_stat_etherstatspkts256octetsto511octets; + u32 rx_stat_etherstatspkts512octetsto1023octets; + u32 rx_stat_etherstatspkts1024octetsto1522octets; + u32 rx_stat_etherstatspktsover1522octets; + + u32 rx_stat_falsecarriererrors; + + u32 tx_stat_ifhcoutoctets; + u32 tx_stat_ifhcoutbadoctets; + u32 tx_stat_etherstatscollisions; + u32 tx_stat_outxonsent; + u32 tx_stat_outxoffsent; + u32 tx_stat_flowcontroldone; + u32 tx_stat_dot3statssinglecollisionframes; + u32 tx_stat_dot3statsmultiplecollisionframes; + u32 tx_stat_dot3statsdeferredtransmissions; + u32 tx_stat_dot3statsexcessivecollisions; + u32 tx_stat_dot3statslatecollisions; + u32 tx_stat_ifhcoutucastpkts; + u32 tx_stat_ifhcoutmulticastpkts; + u32 tx_stat_ifhcoutbroadcastpkts; + u32 tx_stat_etherstatspkts64octets; + u32 tx_stat_etherstatspkts65octetsto127octets; + u32 tx_stat_etherstatspkts128octetsto255octets; + u32 tx_stat_etherstatspkts256octetsto511octets; + u32 tx_stat_etherstatspkts512octetsto1023octets; + u32 tx_stat_etherstatspkts1024octetsto1522octets; + u32 tx_stat_etherstatspktsover1522octets; + u32 tx_stat_dot3statsinternalmactransmiterrors; +}; + + +struct bmac1_stats { + u32 tx_stat_gtpkt_lo; + u32 tx_stat_gtpkt_hi; + u32 tx_stat_gtxpf_lo; + u32 tx_stat_gtxpf_hi; + u32 tx_stat_gtfcs_lo; + u32 tx_stat_gtfcs_hi; + u32 tx_stat_gtmca_lo; + u32 tx_stat_gtmca_hi; + u32 tx_stat_gtbca_lo; + u32 tx_stat_gtbca_hi; + u32 tx_stat_gtfrg_lo; + u32 tx_stat_gtfrg_hi; + u32 tx_stat_gtovr_lo; + u32 tx_stat_gtovr_hi; + u32 tx_stat_gt64_lo; + u32 tx_stat_gt64_hi; + u32 tx_stat_gt127_lo; + u32 tx_stat_gt127_hi; + u32 tx_stat_gt255_lo; + u32 tx_stat_gt255_hi; + u32 tx_stat_gt511_lo; + u32 tx_stat_gt511_hi; + u32 tx_stat_gt1023_lo; + u32 tx_stat_gt1023_hi; + u32 tx_stat_gt1518_lo; + u32 tx_stat_gt1518_hi; + u32 tx_stat_gt2047_lo; + u32 tx_stat_gt2047_hi; + u32 tx_stat_gt4095_lo; + u32 tx_stat_gt4095_hi; + u32 tx_stat_gt9216_lo; + u32 tx_stat_gt9216_hi; + u32 tx_stat_gt16383_lo; + u32 tx_stat_gt16383_hi; + u32 tx_stat_gtmax_lo; + u32 tx_stat_gtmax_hi; + u32 tx_stat_gtufl_lo; + u32 tx_stat_gtufl_hi; + u32 tx_stat_gterr_lo; + u32 tx_stat_gterr_hi; + u32 tx_stat_gtbyt_lo; + u32 tx_stat_gtbyt_hi; + + u32 rx_stat_gr64_lo; + u32 rx_stat_gr64_hi; + u32 rx_stat_gr127_lo; + u32 rx_stat_gr127_hi; + u32 rx_stat_gr255_lo; + u32 rx_stat_gr255_hi; + u32 rx_stat_gr511_lo; + u32 rx_stat_gr511_hi; + u32 rx_stat_gr1023_lo; + u32 rx_stat_gr1023_hi; + u32 rx_stat_gr1518_lo; + u32 rx_stat_gr1518_hi; + u32 rx_stat_gr2047_lo; + u32 rx_stat_gr2047_hi; + u32 rx_stat_gr4095_lo; + u32 rx_stat_gr4095_hi; + u32 rx_stat_gr9216_lo; + u32 rx_stat_gr9216_hi; + u32 rx_stat_gr16383_lo; + u32 rx_stat_gr16383_hi; + u32 rx_stat_grmax_lo; + u32 rx_stat_grmax_hi; + u32 rx_stat_grpkt_lo; + u32 rx_stat_grpkt_hi; + u32 rx_stat_grfcs_lo; + u32 rx_stat_grfcs_hi; + u32 rx_stat_grmca_lo; + u32 rx_stat_grmca_hi; + u32 rx_stat_grbca_lo; + u32 rx_stat_grbca_hi; + u32 rx_stat_grxcf_lo; + u32 rx_stat_grxcf_hi; + u32 rx_stat_grxpf_lo; + u32 rx_stat_grxpf_hi; + u32 rx_stat_grxuo_lo; + u32 rx_stat_grxuo_hi; + u32 rx_stat_grjbr_lo; + u32 rx_stat_grjbr_hi; + u32 rx_stat_grovr_lo; + u32 rx_stat_grovr_hi; + u32 rx_stat_grflr_lo; + u32 rx_stat_grflr_hi; + u32 rx_stat_grmeg_lo; + u32 rx_stat_grmeg_hi; + u32 rx_stat_grmeb_lo; + u32 rx_stat_grmeb_hi; + u32 rx_stat_grbyt_lo; + u32 rx_stat_grbyt_hi; + u32 rx_stat_grund_lo; + u32 rx_stat_grund_hi; + u32 rx_stat_grfrg_lo; + u32 rx_stat_grfrg_hi; + u32 rx_stat_grerb_lo; + u32 rx_stat_grerb_hi; + u32 rx_stat_grfre_lo; + u32 rx_stat_grfre_hi; + u32 rx_stat_gripj_lo; + u32 rx_stat_gripj_hi; +}; + +struct bmac2_stats { + u32 tx_stat_gtpk_lo; /* gtpok */ + u32 tx_stat_gtpk_hi; /* gtpok */ + u32 tx_stat_gtxpf_lo; /* gtpf */ + u32 tx_stat_gtxpf_hi; /* gtpf */ + u32 tx_stat_gtpp_lo; /* NEW BMAC2 */ + u32 tx_stat_gtpp_hi; /* NEW BMAC2 */ + u32 tx_stat_gtfcs_lo; + u32 tx_stat_gtfcs_hi; + u32 tx_stat_gtuca_lo; /* NEW BMAC2 */ + u32 tx_stat_gtuca_hi; /* NEW BMAC2 */ + u32 tx_stat_gtmca_lo; + u32 tx_stat_gtmca_hi; + u32 tx_stat_gtbca_lo; + u32 tx_stat_gtbca_hi; + u32 tx_stat_gtovr_lo; + u32 tx_stat_gtovr_hi; + u32 tx_stat_gtfrg_lo; + u32 tx_stat_gtfrg_hi; + u32 tx_stat_gtpkt1_lo; /* gtpkt */ + u32 tx_stat_gtpkt1_hi; /* gtpkt */ + u32 tx_stat_gt64_lo; + u32 tx_stat_gt64_hi; + u32 tx_stat_gt127_lo; + u32 tx_stat_gt127_hi; + u32 tx_stat_gt255_lo; + u32 tx_stat_gt255_hi; + u32 tx_stat_gt511_lo; + u32 tx_stat_gt511_hi; + u32 tx_stat_gt1023_lo; + u32 tx_stat_gt1023_hi; + u32 tx_stat_gt1518_lo; + u32 tx_stat_gt1518_hi; + u32 tx_stat_gt2047_lo; + u32 tx_stat_gt2047_hi; + u32 tx_stat_gt4095_lo; + u32 tx_stat_gt4095_hi; + u32 tx_stat_gt9216_lo; + u32 tx_stat_gt9216_hi; + u32 tx_stat_gt16383_lo; + u32 tx_stat_gt16383_hi; + u32 tx_stat_gtmax_lo; + u32 tx_stat_gtmax_hi; + u32 tx_stat_gtufl_lo; + u32 tx_stat_gtufl_hi; + u32 tx_stat_gterr_lo; + u32 tx_stat_gterr_hi; + u32 tx_stat_gtbyt_lo; + u32 tx_stat_gtbyt_hi; + + u32 rx_stat_gr64_lo; + u32 rx_stat_gr64_hi; + u32 rx_stat_gr127_lo; + u32 rx_stat_gr127_hi; + u32 rx_stat_gr255_lo; + u32 rx_stat_gr255_hi; + u32 rx_stat_gr511_lo; + u32 rx_stat_gr511_hi; + u32 rx_stat_gr1023_lo; + u32 rx_stat_gr1023_hi; + u32 rx_stat_gr1518_lo; + u32 rx_stat_gr1518_hi; + u32 rx_stat_gr2047_lo; + u32 rx_stat_gr2047_hi; + u32 rx_stat_gr4095_lo; + u32 rx_stat_gr4095_hi; + u32 rx_stat_gr9216_lo; + u32 rx_stat_gr9216_hi; + u32 rx_stat_gr16383_lo; + u32 rx_stat_gr16383_hi; + u32 rx_stat_grmax_lo; + u32 rx_stat_grmax_hi; + u32 rx_stat_grpkt_lo; + u32 rx_stat_grpkt_hi; + u32 rx_stat_grfcs_lo; + u32 rx_stat_grfcs_hi; + u32 rx_stat_gruca_lo; + u32 rx_stat_gruca_hi; + u32 rx_stat_grmca_lo; + u32 rx_stat_grmca_hi; + u32 rx_stat_grbca_lo; + u32 rx_stat_grbca_hi; + u32 rx_stat_grxpf_lo; /* grpf */ + u32 rx_stat_grxpf_hi; /* grpf */ + u32 rx_stat_grpp_lo; + u32 rx_stat_grpp_hi; + u32 rx_stat_grxuo_lo; /* gruo */ + u32 rx_stat_grxuo_hi; /* gruo */ + u32 rx_stat_grjbr_lo; + u32 rx_stat_grjbr_hi; + u32 rx_stat_grovr_lo; + u32 rx_stat_grovr_hi; + u32 rx_stat_grxcf_lo; /* grcf */ + u32 rx_stat_grxcf_hi; /* grcf */ + u32 rx_stat_grflr_lo; + u32 rx_stat_grflr_hi; + u32 rx_stat_grpok_lo; + u32 rx_stat_grpok_hi; + u32 rx_stat_grmeg_lo; + u32 rx_stat_grmeg_hi; + u32 rx_stat_grmeb_lo; + u32 rx_stat_grmeb_hi; + u32 rx_stat_grbyt_lo; + u32 rx_stat_grbyt_hi; + u32 rx_stat_grund_lo; + u32 rx_stat_grund_hi; + u32 rx_stat_grfrg_lo; + u32 rx_stat_grfrg_hi; + u32 rx_stat_grerb_lo; /* grerrbyt */ + u32 rx_stat_grerb_hi; /* grerrbyt */ + u32 rx_stat_grfre_lo; /* grfrerr */ + u32 rx_stat_grfre_hi; /* grfrerr */ + u32 rx_stat_gripj_lo; + u32 rx_stat_gripj_hi; +}; + +struct mstat_stats { + struct { + /* OTE MSTAT on E3 has a bug where this register's contents are + * actually tx_gtxpok + tx_gtxpf + (possibly)tx_gtxpp + */ + u32 tx_gtxpok_lo; + u32 tx_gtxpok_hi; + u32 tx_gtxpf_lo; + u32 tx_gtxpf_hi; + u32 tx_gtxpp_lo; + u32 tx_gtxpp_hi; + u32 tx_gtfcs_lo; + u32 tx_gtfcs_hi; + u32 tx_gtuca_lo; + u32 tx_gtuca_hi; + u32 tx_gtmca_lo; + u32 tx_gtmca_hi; + u32 tx_gtgca_lo; + u32 tx_gtgca_hi; + u32 tx_gtpkt_lo; + u32 tx_gtpkt_hi; + u32 tx_gt64_lo; + u32 tx_gt64_hi; + u32 tx_gt127_lo; + u32 tx_gt127_hi; + u32 tx_gt255_lo; + u32 tx_gt255_hi; + u32 tx_gt511_lo; + u32 tx_gt511_hi; + u32 tx_gt1023_lo; + u32 tx_gt1023_hi; + u32 tx_gt1518_lo; + u32 tx_gt1518_hi; + u32 tx_gt2047_lo; + u32 tx_gt2047_hi; + u32 tx_gt4095_lo; + u32 tx_gt4095_hi; + u32 tx_gt9216_lo; + u32 tx_gt9216_hi; + u32 tx_gt16383_lo; + u32 tx_gt16383_hi; + u32 tx_gtufl_lo; + u32 tx_gtufl_hi; + u32 tx_gterr_lo; + u32 tx_gterr_hi; + u32 tx_gtbyt_lo; + u32 tx_gtbyt_hi; + u32 tx_collisions_lo; + u32 tx_collisions_hi; + u32 tx_singlecollision_lo; + u32 tx_singlecollision_hi; + u32 tx_multiplecollisions_lo; + u32 tx_multiplecollisions_hi; + u32 tx_deferred_lo; + u32 tx_deferred_hi; + u32 tx_excessivecollisions_lo; + u32 tx_excessivecollisions_hi; + u32 tx_latecollisions_lo; + u32 tx_latecollisions_hi; + } stats_tx; + + struct { + u32 rx_gr64_lo; + u32 rx_gr64_hi; + u32 rx_gr127_lo; + u32 rx_gr127_hi; + u32 rx_gr255_lo; + u32 rx_gr255_hi; + u32 rx_gr511_lo; + u32 rx_gr511_hi; + u32 rx_gr1023_lo; + u32 rx_gr1023_hi; + u32 rx_gr1518_lo; + u32 rx_gr1518_hi; + u32 rx_gr2047_lo; + u32 rx_gr2047_hi; + u32 rx_gr4095_lo; + u32 rx_gr4095_hi; + u32 rx_gr9216_lo; + u32 rx_gr9216_hi; + u32 rx_gr16383_lo; + u32 rx_gr16383_hi; + u32 rx_grpkt_lo; + u32 rx_grpkt_hi; + u32 rx_grfcs_lo; + u32 rx_grfcs_hi; + u32 rx_gruca_lo; + u32 rx_gruca_hi; + u32 rx_grmca_lo; + u32 rx_grmca_hi; + u32 rx_grbca_lo; + u32 rx_grbca_hi; + u32 rx_grxpf_lo; + u32 rx_grxpf_hi; + u32 rx_grxpp_lo; + u32 rx_grxpp_hi; + u32 rx_grxuo_lo; + u32 rx_grxuo_hi; + u32 rx_grovr_lo; + u32 rx_grovr_hi; + u32 rx_grxcf_lo; + u32 rx_grxcf_hi; + u32 rx_grflr_lo; + u32 rx_grflr_hi; + u32 rx_grpok_lo; + u32 rx_grpok_hi; + u32 rx_grbyt_lo; + u32 rx_grbyt_hi; + u32 rx_grund_lo; + u32 rx_grund_hi; + u32 rx_grfrg_lo; + u32 rx_grfrg_hi; + u32 rx_grerb_lo; + u32 rx_grerb_hi; + u32 rx_grfre_lo; + u32 rx_grfre_hi; + + u32 rx_alignmenterrors_lo; + u32 rx_alignmenterrors_hi; + u32 rx_falsecarrier_lo; + u32 rx_falsecarrier_hi; + u32 rx_llfcmsgcnt_lo; + u32 rx_llfcmsgcnt_hi; + } stats_rx; +}; + +union mac_stats { + struct emac_stats emac_stats; + struct bmac1_stats bmac1_stats; + struct bmac2_stats bmac2_stats; + struct mstat_stats mstat_stats; +}; + + +struct mac_stx { + /* in_bad_octets */ + u32 rx_stat_ifhcinbadoctets_hi; + u32 rx_stat_ifhcinbadoctets_lo; + + /* out_bad_octets */ + u32 tx_stat_ifhcoutbadoctets_hi; + u32 tx_stat_ifhcoutbadoctets_lo; + + /* crc_receive_errors */ + u32 rx_stat_dot3statsfcserrors_hi; + u32 rx_stat_dot3statsfcserrors_lo; + /* alignment_errors */ + u32 rx_stat_dot3statsalignmenterrors_hi; + u32 rx_stat_dot3statsalignmenterrors_lo; + /* carrier_sense_errors */ + u32 rx_stat_dot3statscarriersenseerrors_hi; + u32 rx_stat_dot3statscarriersenseerrors_lo; + /* false_carrier_detections */ + u32 rx_stat_falsecarriererrors_hi; + u32 rx_stat_falsecarriererrors_lo; + + /* runt_packets_received */ + u32 rx_stat_etherstatsundersizepkts_hi; + u32 rx_stat_etherstatsundersizepkts_lo; + /* jabber_packets_received */ + u32 rx_stat_dot3statsframestoolong_hi; + u32 rx_stat_dot3statsframestoolong_lo; + + /* error_runt_packets_received */ + u32 rx_stat_etherstatsfragments_hi; + u32 rx_stat_etherstatsfragments_lo; + /* error_jabber_packets_received */ + u32 rx_stat_etherstatsjabbers_hi; + u32 rx_stat_etherstatsjabbers_lo; + + /* control_frames_received */ + u32 rx_stat_maccontrolframesreceived_hi; + u32 rx_stat_maccontrolframesreceived_lo; + u32 rx_stat_mac_xpf_hi; + u32 rx_stat_mac_xpf_lo; + u32 rx_stat_mac_xcf_hi; + u32 rx_stat_mac_xcf_lo; + + /* xoff_state_entered */ + u32 rx_stat_xoffstateentered_hi; + u32 rx_stat_xoffstateentered_lo; + /* pause_xon_frames_received */ + u32 rx_stat_xonpauseframesreceived_hi; + u32 rx_stat_xonpauseframesreceived_lo; + /* pause_xoff_frames_received */ + u32 rx_stat_xoffpauseframesreceived_hi; + u32 rx_stat_xoffpauseframesreceived_lo; + /* pause_xon_frames_transmitted */ + u32 tx_stat_outxonsent_hi; + u32 tx_stat_outxonsent_lo; + /* pause_xoff_frames_transmitted */ + u32 tx_stat_outxoffsent_hi; + u32 tx_stat_outxoffsent_lo; + /* flow_control_done */ + u32 tx_stat_flowcontroldone_hi; + u32 tx_stat_flowcontroldone_lo; + + /* ether_stats_collisions */ + u32 tx_stat_etherstatscollisions_hi; + u32 tx_stat_etherstatscollisions_lo; + /* single_collision_transmit_frames */ + u32 tx_stat_dot3statssinglecollisionframes_hi; + u32 tx_stat_dot3statssinglecollisionframes_lo; + /* multiple_collision_transmit_frames */ + u32 tx_stat_dot3statsmultiplecollisionframes_hi; + u32 tx_stat_dot3statsmultiplecollisionframes_lo; + /* deferred_transmissions */ + u32 tx_stat_dot3statsdeferredtransmissions_hi; + u32 tx_stat_dot3statsdeferredtransmissions_lo; + /* excessive_collision_frames */ + u32 tx_stat_dot3statsexcessivecollisions_hi; + u32 tx_stat_dot3statsexcessivecollisions_lo; + /* late_collision_frames */ + u32 tx_stat_dot3statslatecollisions_hi; + u32 tx_stat_dot3statslatecollisions_lo; + + /* frames_transmitted_64_bytes */ + u32 tx_stat_etherstatspkts64octets_hi; + u32 tx_stat_etherstatspkts64octets_lo; + /* frames_transmitted_65_127_bytes */ + u32 tx_stat_etherstatspkts65octetsto127octets_hi; + u32 tx_stat_etherstatspkts65octetsto127octets_lo; + /* frames_transmitted_128_255_bytes */ + u32 tx_stat_etherstatspkts128octetsto255octets_hi; + u32 tx_stat_etherstatspkts128octetsto255octets_lo; + /* frames_transmitted_256_511_bytes */ + u32 tx_stat_etherstatspkts256octetsto511octets_hi; + u32 tx_stat_etherstatspkts256octetsto511octets_lo; + /* frames_transmitted_512_1023_bytes */ + u32 tx_stat_etherstatspkts512octetsto1023octets_hi; + u32 tx_stat_etherstatspkts512octetsto1023octets_lo; + /* frames_transmitted_1024_1522_bytes */ + u32 tx_stat_etherstatspkts1024octetsto1522octets_hi; + u32 tx_stat_etherstatspkts1024octetsto1522octets_lo; + /* frames_transmitted_1523_9022_bytes */ + u32 tx_stat_etherstatspktsover1522octets_hi; + u32 tx_stat_etherstatspktsover1522octets_lo; + u32 tx_stat_mac_2047_hi; + u32 tx_stat_mac_2047_lo; + u32 tx_stat_mac_4095_hi; + u32 tx_stat_mac_4095_lo; + u32 tx_stat_mac_9216_hi; + u32 tx_stat_mac_9216_lo; + u32 tx_stat_mac_16383_hi; + u32 tx_stat_mac_16383_lo; + + /* internal_mac_transmit_errors */ + u32 tx_stat_dot3statsinternalmactransmiterrors_hi; + u32 tx_stat_dot3statsinternalmactransmiterrors_lo; + + /* if_out_discards */ + u32 tx_stat_mac_ufl_hi; + u32 tx_stat_mac_ufl_lo; +}; + + +#define MAC_STX_IDX_MAX 2 + +struct host_port_stats { + u32 host_port_stats_start; + + struct mac_stx mac_stx[MAC_STX_IDX_MAX]; + + u32 brb_drop_hi; + u32 brb_drop_lo; + + u32 host_port_stats_end; +}; + + +struct host_func_stats { + u32 host_func_stats_start; + + u32 total_bytes_received_hi; + u32 total_bytes_received_lo; + + u32 total_bytes_transmitted_hi; + u32 total_bytes_transmitted_lo; + + u32 total_unicast_packets_received_hi; + u32 total_unicast_packets_received_lo; + + u32 total_multicast_packets_received_hi; + u32 total_multicast_packets_received_lo; + + u32 total_broadcast_packets_received_hi; + u32 total_broadcast_packets_received_lo; + + u32 total_unicast_packets_transmitted_hi; + u32 total_unicast_packets_transmitted_lo; + + u32 total_multicast_packets_transmitted_hi; + u32 total_multicast_packets_transmitted_lo; + + u32 total_broadcast_packets_transmitted_hi; + u32 total_broadcast_packets_transmitted_lo; + + u32 valid_bytes_received_hi; + u32 valid_bytes_received_lo; + + u32 host_func_stats_end; +}; + +/* VIC definitions */ +#define VICSTATST_UIF_INDEX 2 + +#define BCM_5710_FW_MAJOR_VERSION 7 +#define BCM_5710_FW_MINOR_VERSION 0 +#define BCM_5710_FW_REVISION_VERSION 23 +#define BCM_5710_FW_ENGINEERING_VERSION 0 +#define BCM_5710_FW_COMPILE_FLAGS 1 + + +/* + * attention bits + */ +struct atten_sp_status_block { + __le32 attn_bits; + __le32 attn_bits_ack; + u8 status_block_id; + u8 reserved0; + __le16 attn_bits_index; + __le32 reserved1; +}; + + +/* + * The eth aggregative context of Cstorm + */ +struct cstorm_eth_ag_context { + u32 __reserved0[10]; +}; + + +/* + * dmae command structure + */ +struct dmae_command { + u32 opcode; +#define DMAE_COMMAND_SRC (0x1<<0) +#define DMAE_COMMAND_SRC_SHIFT 0 +#define DMAE_COMMAND_DST (0x3<<1) +#define DMAE_COMMAND_DST_SHIFT 1 +#define DMAE_COMMAND_C_DST (0x1<<3) +#define DMAE_COMMAND_C_DST_SHIFT 3 +#define DMAE_COMMAND_C_TYPE_ENABLE (0x1<<4) +#define DMAE_COMMAND_C_TYPE_ENABLE_SHIFT 4 +#define DMAE_COMMAND_C_TYPE_CRC_ENABLE (0x1<<5) +#define DMAE_COMMAND_C_TYPE_CRC_ENABLE_SHIFT 5 +#define DMAE_COMMAND_C_TYPE_CRC_OFFSET (0x7<<6) +#define DMAE_COMMAND_C_TYPE_CRC_OFFSET_SHIFT 6 +#define DMAE_COMMAND_ENDIANITY (0x3<<9) +#define DMAE_COMMAND_ENDIANITY_SHIFT 9 +#define DMAE_COMMAND_PORT (0x1<<11) +#define DMAE_COMMAND_PORT_SHIFT 11 +#define DMAE_COMMAND_CRC_RESET (0x1<<12) +#define DMAE_COMMAND_CRC_RESET_SHIFT 12 +#define DMAE_COMMAND_SRC_RESET (0x1<<13) +#define DMAE_COMMAND_SRC_RESET_SHIFT 13 +#define DMAE_COMMAND_DST_RESET (0x1<<14) +#define DMAE_COMMAND_DST_RESET_SHIFT 14 +#define DMAE_COMMAND_E1HVN (0x3<<15) +#define DMAE_COMMAND_E1HVN_SHIFT 15 +#define DMAE_COMMAND_DST_VN (0x3<<17) +#define DMAE_COMMAND_DST_VN_SHIFT 17 +#define DMAE_COMMAND_C_FUNC (0x1<<19) +#define DMAE_COMMAND_C_FUNC_SHIFT 19 +#define DMAE_COMMAND_ERR_POLICY (0x3<<20) +#define DMAE_COMMAND_ERR_POLICY_SHIFT 20 +#define DMAE_COMMAND_RESERVED0 (0x3FF<<22) +#define DMAE_COMMAND_RESERVED0_SHIFT 22 + u32 src_addr_lo; + u32 src_addr_hi; + u32 dst_addr_lo; + u32 dst_addr_hi; +#if defined(__BIG_ENDIAN) + u16 opcode_iov; +#define DMAE_COMMAND_SRC_VFID (0x3F<<0) +#define DMAE_COMMAND_SRC_VFID_SHIFT 0 +#define DMAE_COMMAND_SRC_VFPF (0x1<<6) +#define DMAE_COMMAND_SRC_VFPF_SHIFT 6 +#define DMAE_COMMAND_RESERVED1 (0x1<<7) +#define DMAE_COMMAND_RESERVED1_SHIFT 7 +#define DMAE_COMMAND_DST_VFID (0x3F<<8) +#define DMAE_COMMAND_DST_VFID_SHIFT 8 +#define DMAE_COMMAND_DST_VFPF (0x1<<14) +#define DMAE_COMMAND_DST_VFPF_SHIFT 14 +#define DMAE_COMMAND_RESERVED2 (0x1<<15) +#define DMAE_COMMAND_RESERVED2_SHIFT 15 + u16 len; +#elif defined(__LITTLE_ENDIAN) + u16 len; + u16 opcode_iov; +#define DMAE_COMMAND_SRC_VFID (0x3F<<0) +#define DMAE_COMMAND_SRC_VFID_SHIFT 0 +#define DMAE_COMMAND_SRC_VFPF (0x1<<6) +#define DMAE_COMMAND_SRC_VFPF_SHIFT 6 +#define DMAE_COMMAND_RESERVED1 (0x1<<7) +#define DMAE_COMMAND_RESERVED1_SHIFT 7 +#define DMAE_COMMAND_DST_VFID (0x3F<<8) +#define DMAE_COMMAND_DST_VFID_SHIFT 8 +#define DMAE_COMMAND_DST_VFPF (0x1<<14) +#define DMAE_COMMAND_DST_VFPF_SHIFT 14 +#define DMAE_COMMAND_RESERVED2 (0x1<<15) +#define DMAE_COMMAND_RESERVED2_SHIFT 15 +#endif + u32 comp_addr_lo; + u32 comp_addr_hi; + u32 comp_val; + u32 crc32; + u32 crc32_c; +#if defined(__BIG_ENDIAN) + u16 crc16_c; + u16 crc16; +#elif defined(__LITTLE_ENDIAN) + u16 crc16; + u16 crc16_c; +#endif +#if defined(__BIG_ENDIAN) + u16 reserved3; + u16 crc_t10; +#elif defined(__LITTLE_ENDIAN) + u16 crc_t10; + u16 reserved3; +#endif +#if defined(__BIG_ENDIAN) + u16 xsum8; + u16 xsum16; +#elif defined(__LITTLE_ENDIAN) + u16 xsum16; + u16 xsum8; +#endif +}; + + +/* + * common data for all protocols + */ +struct doorbell_hdr { + u8 header; +#define DOORBELL_HDR_RX (0x1<<0) +#define DOORBELL_HDR_RX_SHIFT 0 +#define DOORBELL_HDR_DB_TYPE (0x1<<1) +#define DOORBELL_HDR_DB_TYPE_SHIFT 1 +#define DOORBELL_HDR_DPM_SIZE (0x3<<2) +#define DOORBELL_HDR_DPM_SIZE_SHIFT 2 +#define DOORBELL_HDR_CONN_TYPE (0xF<<4) +#define DOORBELL_HDR_CONN_TYPE_SHIFT 4 +}; + +/* + * Ethernet doorbell + */ +struct eth_tx_doorbell { +#if defined(__BIG_ENDIAN) + u16 npackets; + u8 params; +#define ETH_TX_DOORBELL_NUM_BDS (0x3F<<0) +#define ETH_TX_DOORBELL_NUM_BDS_SHIFT 0 +#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG (0x1<<6) +#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG_SHIFT 6 +#define ETH_TX_DOORBELL_SPARE (0x1<<7) +#define ETH_TX_DOORBELL_SPARE_SHIFT 7 + struct doorbell_hdr hdr; +#elif defined(__LITTLE_ENDIAN) + struct doorbell_hdr hdr; + u8 params; +#define ETH_TX_DOORBELL_NUM_BDS (0x3F<<0) +#define ETH_TX_DOORBELL_NUM_BDS_SHIFT 0 +#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG (0x1<<6) +#define ETH_TX_DOORBELL_RESERVED_TX_FIN_FLAG_SHIFT 6 +#define ETH_TX_DOORBELL_SPARE (0x1<<7) +#define ETH_TX_DOORBELL_SPARE_SHIFT 7 + u16 npackets; +#endif +}; + + +/* + * 3 lines. status block + */ +struct hc_status_block_e1x { + __le16 index_values[HC_SB_MAX_INDICES_E1X]; + __le16 running_index[HC_SB_MAX_SM]; + __le32 rsrv[11]; +}; + +/* + * host status block + */ +struct host_hc_status_block_e1x { + struct hc_status_block_e1x sb; +}; + + +/* + * 3 lines. status block + */ +struct hc_status_block_e2 { + __le16 index_values[HC_SB_MAX_INDICES_E2]; + __le16 running_index[HC_SB_MAX_SM]; + __le32 reserved[11]; +}; + +/* + * host status block + */ +struct host_hc_status_block_e2 { + struct hc_status_block_e2 sb; +}; + + +/* + * 5 lines. slow-path status block + */ +struct hc_sp_status_block { + __le16 index_values[HC_SP_SB_MAX_INDICES]; + __le16 running_index; + __le16 rsrv; + u32 rsrv1; +}; + +/* + * host status block + */ +struct host_sp_status_block { + struct atten_sp_status_block atten_status_block; + struct hc_sp_status_block sp_sb; +}; + + +/* + * IGU driver acknowledgment register + */ +struct igu_ack_register { +#if defined(__BIG_ENDIAN) + u16 sb_id_and_flags; +#define IGU_ACK_REGISTER_STATUS_BLOCK_ID (0x1F<<0) +#define IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT 0 +#define IGU_ACK_REGISTER_STORM_ID (0x7<<5) +#define IGU_ACK_REGISTER_STORM_ID_SHIFT 5 +#define IGU_ACK_REGISTER_UPDATE_INDEX (0x1<<8) +#define IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT 8 +#define IGU_ACK_REGISTER_INTERRUPT_MODE (0x3<<9) +#define IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT 9 +#define IGU_ACK_REGISTER_RESERVED (0x1F<<11) +#define IGU_ACK_REGISTER_RESERVED_SHIFT 11 + u16 status_block_index; +#elif defined(__LITTLE_ENDIAN) + u16 status_block_index; + u16 sb_id_and_flags; +#define IGU_ACK_REGISTER_STATUS_BLOCK_ID (0x1F<<0) +#define IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT 0 +#define IGU_ACK_REGISTER_STORM_ID (0x7<<5) +#define IGU_ACK_REGISTER_STORM_ID_SHIFT 5 +#define IGU_ACK_REGISTER_UPDATE_INDEX (0x1<<8) +#define IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT 8 +#define IGU_ACK_REGISTER_INTERRUPT_MODE (0x3<<9) +#define IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT 9 +#define IGU_ACK_REGISTER_RESERVED (0x1F<<11) +#define IGU_ACK_REGISTER_RESERVED_SHIFT 11 +#endif +}; + + +/* + * IGU driver acknowledgement register + */ +struct igu_backward_compatible { + u32 sb_id_and_flags; +#define IGU_BACKWARD_COMPATIBLE_SB_INDEX (0xFFFF<<0) +#define IGU_BACKWARD_COMPATIBLE_SB_INDEX_SHIFT 0 +#define IGU_BACKWARD_COMPATIBLE_SB_SELECT (0x1F<<16) +#define IGU_BACKWARD_COMPATIBLE_SB_SELECT_SHIFT 16 +#define IGU_BACKWARD_COMPATIBLE_SEGMENT_ACCESS (0x7<<21) +#define IGU_BACKWARD_COMPATIBLE_SEGMENT_ACCESS_SHIFT 21 +#define IGU_BACKWARD_COMPATIBLE_BUPDATE (0x1<<24) +#define IGU_BACKWARD_COMPATIBLE_BUPDATE_SHIFT 24 +#define IGU_BACKWARD_COMPATIBLE_ENABLE_INT (0x3<<25) +#define IGU_BACKWARD_COMPATIBLE_ENABLE_INT_SHIFT 25 +#define IGU_BACKWARD_COMPATIBLE_RESERVED_0 (0x1F<<27) +#define IGU_BACKWARD_COMPATIBLE_RESERVED_0_SHIFT 27 + u32 reserved_2; +}; + + +/* + * IGU driver acknowledgement register + */ +struct igu_regular { + u32 sb_id_and_flags; +#define IGU_REGULAR_SB_INDEX (0xFFFFF<<0) +#define IGU_REGULAR_SB_INDEX_SHIFT 0 +#define IGU_REGULAR_RESERVED0 (0x1<<20) +#define IGU_REGULAR_RESERVED0_SHIFT 20 +#define IGU_REGULAR_SEGMENT_ACCESS (0x7<<21) +#define IGU_REGULAR_SEGMENT_ACCESS_SHIFT 21 +#define IGU_REGULAR_BUPDATE (0x1<<24) +#define IGU_REGULAR_BUPDATE_SHIFT 24 +#define IGU_REGULAR_ENABLE_INT (0x3<<25) +#define IGU_REGULAR_ENABLE_INT_SHIFT 25 +#define IGU_REGULAR_RESERVED_1 (0x1<<27) +#define IGU_REGULAR_RESERVED_1_SHIFT 27 +#define IGU_REGULAR_CLEANUP_TYPE (0x3<<28) +#define IGU_REGULAR_CLEANUP_TYPE_SHIFT 28 +#define IGU_REGULAR_CLEANUP_SET (0x1<<30) +#define IGU_REGULAR_CLEANUP_SET_SHIFT 30 +#define IGU_REGULAR_BCLEANUP (0x1<<31) +#define IGU_REGULAR_BCLEANUP_SHIFT 31 + u32 reserved_2; +}; + +/* + * IGU driver acknowledgement register + */ +union igu_consprod_reg { + struct igu_regular regular; + struct igu_backward_compatible backward_compatible; +}; + + +/* + * Igu control commands + */ +enum igu_ctrl_cmd { + IGU_CTRL_CMD_TYPE_RD, + IGU_CTRL_CMD_TYPE_WR, + MAX_IGU_CTRL_CMD +}; + + +/* + * Control register for the IGU command register + */ +struct igu_ctrl_reg { + u32 ctrl_data; +#define IGU_CTRL_REG_ADDRESS (0xFFF<<0) +#define IGU_CTRL_REG_ADDRESS_SHIFT 0 +#define IGU_CTRL_REG_FID (0x7F<<12) +#define IGU_CTRL_REG_FID_SHIFT 12 +#define IGU_CTRL_REG_RESERVED (0x1<<19) +#define IGU_CTRL_REG_RESERVED_SHIFT 19 +#define IGU_CTRL_REG_TYPE (0x1<<20) +#define IGU_CTRL_REG_TYPE_SHIFT 20 +#define IGU_CTRL_REG_UNUSED (0x7FF<<21) +#define IGU_CTRL_REG_UNUSED_SHIFT 21 +}; + + +/* + * Igu interrupt command + */ +enum igu_int_cmd { + IGU_INT_ENABLE, + IGU_INT_DISABLE, + IGU_INT_NOP, + IGU_INT_NOP2, + MAX_IGU_INT_CMD +}; + + +/* + * Igu segments + */ +enum igu_seg_access { + IGU_SEG_ACCESS_NORM, + IGU_SEG_ACCESS_DEF, + IGU_SEG_ACCESS_ATTN, + MAX_IGU_SEG_ACCESS +}; + + +/* + * Parser parsing flags field + */ +struct parsing_flags { + __le16 flags; +#define PARSING_FLAGS_ETHERNET_ADDRESS_TYPE (0x1<<0) +#define PARSING_FLAGS_ETHERNET_ADDRESS_TYPE_SHIFT 0 +#define PARSING_FLAGS_VLAN (0x1<<1) +#define PARSING_FLAGS_VLAN_SHIFT 1 +#define PARSING_FLAGS_EXTRA_VLAN (0x1<<2) +#define PARSING_FLAGS_EXTRA_VLAN_SHIFT 2 +#define PARSING_FLAGS_OVER_ETHERNET_PROTOCOL (0x3<<3) +#define PARSING_FLAGS_OVER_ETHERNET_PROTOCOL_SHIFT 3 +#define PARSING_FLAGS_IP_OPTIONS (0x1<<5) +#define PARSING_FLAGS_IP_OPTIONS_SHIFT 5 +#define PARSING_FLAGS_FRAGMENTATION_STATUS (0x1<<6) +#define PARSING_FLAGS_FRAGMENTATION_STATUS_SHIFT 6 +#define PARSING_FLAGS_OVER_IP_PROTOCOL (0x3<<7) +#define PARSING_FLAGS_OVER_IP_PROTOCOL_SHIFT 7 +#define PARSING_FLAGS_PURE_ACK_INDICATION (0x1<<9) +#define PARSING_FLAGS_PURE_ACK_INDICATION_SHIFT 9 +#define PARSING_FLAGS_TCP_OPTIONS_EXIST (0x1<<10) +#define PARSING_FLAGS_TCP_OPTIONS_EXIST_SHIFT 10 +#define PARSING_FLAGS_TIME_STAMP_EXIST_FLAG (0x1<<11) +#define PARSING_FLAGS_TIME_STAMP_EXIST_FLAG_SHIFT 11 +#define PARSING_FLAGS_CONNECTION_MATCH (0x1<<12) +#define PARSING_FLAGS_CONNECTION_MATCH_SHIFT 12 +#define PARSING_FLAGS_LLC_SNAP (0x1<<13) +#define PARSING_FLAGS_LLC_SNAP_SHIFT 13 +#define PARSING_FLAGS_RESERVED0 (0x3<<14) +#define PARSING_FLAGS_RESERVED0_SHIFT 14 +}; + + +/* + * Parsing flags for TCP ACK type + */ +enum prs_flags_ack_type { + PRS_FLAG_PUREACK_PIGGY, + PRS_FLAG_PUREACK_PURE, + MAX_PRS_FLAGS_ACK_TYPE +}; + + +/* + * Parsing flags for Ethernet address type + */ +enum prs_flags_eth_addr_type { + PRS_FLAG_ETHTYPE_NON_UNICAST, + PRS_FLAG_ETHTYPE_UNICAST, + MAX_PRS_FLAGS_ETH_ADDR_TYPE +}; + + +/* + * Parsing flags for over-ethernet protocol + */ +enum prs_flags_over_eth { + PRS_FLAG_OVERETH_UNKNOWN, + PRS_FLAG_OVERETH_IPV4, + PRS_FLAG_OVERETH_IPV6, + PRS_FLAG_OVERETH_LLCSNAP_UNKNOWN, + MAX_PRS_FLAGS_OVER_ETH +}; + + +/* + * Parsing flags for over-IP protocol + */ +enum prs_flags_over_ip { + PRS_FLAG_OVERIP_UNKNOWN, + PRS_FLAG_OVERIP_TCP, + PRS_FLAG_OVERIP_UDP, + MAX_PRS_FLAGS_OVER_IP +}; + + +/* + * SDM operation gen command (generate aggregative interrupt) + */ +struct sdm_op_gen { + __le32 command; +#define SDM_OP_GEN_COMP_PARAM (0x1F<<0) +#define SDM_OP_GEN_COMP_PARAM_SHIFT 0 +#define SDM_OP_GEN_COMP_TYPE (0x7<<5) +#define SDM_OP_GEN_COMP_TYPE_SHIFT 5 +#define SDM_OP_GEN_AGG_VECT_IDX (0xFF<<8) +#define SDM_OP_GEN_AGG_VECT_IDX_SHIFT 8 +#define SDM_OP_GEN_AGG_VECT_IDX_VALID (0x1<<16) +#define SDM_OP_GEN_AGG_VECT_IDX_VALID_SHIFT 16 +#define SDM_OP_GEN_RESERVED (0x7FFF<<17) +#define SDM_OP_GEN_RESERVED_SHIFT 17 +}; + + +/* + * Timers connection context + */ +struct timers_block_context { + u32 __reserved_0; + u32 __reserved_1; + u32 __reserved_2; + u32 flags; +#define __TIMERS_BLOCK_CONTEXT_NUM_OF_ACTIVE_TIMERS (0x3<<0) +#define __TIMERS_BLOCK_CONTEXT_NUM_OF_ACTIVE_TIMERS_SHIFT 0 +#define TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG (0x1<<2) +#define TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG_SHIFT 2 +#define __TIMERS_BLOCK_CONTEXT_RESERVED0 (0x1FFFFFFF<<3) +#define __TIMERS_BLOCK_CONTEXT_RESERVED0_SHIFT 3 +}; + + +/* + * The eth aggregative context of Tstorm + */ +struct tstorm_eth_ag_context { + u32 __reserved0[14]; +}; + + +/* + * The eth aggregative context of Ustorm + */ +struct ustorm_eth_ag_context { + u32 __reserved0; +#if defined(__BIG_ENDIAN) + u8 cdu_usage; + u8 __reserved2; + u16 __reserved1; +#elif defined(__LITTLE_ENDIAN) + u16 __reserved1; + u8 __reserved2; + u8 cdu_usage; +#endif + u32 __reserved3[6]; +}; + + +/* + * The eth aggregative context of Xstorm + */ +struct xstorm_eth_ag_context { + u32 reserved0; +#if defined(__BIG_ENDIAN) + u8 cdu_reserved; + u8 reserved2; + u16 reserved1; +#elif defined(__LITTLE_ENDIAN) + u16 reserved1; + u8 reserved2; + u8 cdu_reserved; +#endif + u32 reserved3[30]; +}; + + +/* + * doorbell message sent to the chip + */ +struct doorbell { +#if defined(__BIG_ENDIAN) + u16 zero_fill2; + u8 zero_fill1; + struct doorbell_hdr header; +#elif defined(__LITTLE_ENDIAN) + struct doorbell_hdr header; + u8 zero_fill1; + u16 zero_fill2; +#endif +}; + + +/* + * doorbell message sent to the chip + */ +struct doorbell_set_prod { +#if defined(__BIG_ENDIAN) + u16 prod; + u8 zero_fill1; + struct doorbell_hdr header; +#elif defined(__LITTLE_ENDIAN) + struct doorbell_hdr header; + u8 zero_fill1; + u16 prod; +#endif +}; + + +struct regpair { + __le32 lo; + __le32 hi; +}; + + +/* + * Classify rule opcodes in E2/E3 + */ +enum classify_rule { + CLASSIFY_RULE_OPCODE_MAC, + CLASSIFY_RULE_OPCODE_VLAN, + CLASSIFY_RULE_OPCODE_PAIR, + MAX_CLASSIFY_RULE +}; + + +/* + * Classify rule types in E2/E3 + */ +enum classify_rule_action_type { + CLASSIFY_RULE_REMOVE, + CLASSIFY_RULE_ADD, + MAX_CLASSIFY_RULE_ACTION_TYPE +}; + + +/* + * client init ramrod data + */ +struct client_init_general_data { + u8 client_id; + u8 statistics_counter_id; + u8 statistics_en_flg; + u8 is_fcoe_flg; + u8 activate_flg; + u8 sp_client_id; + __le16 mtu; + u8 statistics_zero_flg; + u8 func_id; + u8 cos; + u8 traffic_type; + u32 reserved0; +}; + + +/* + * client init rx data + */ +struct client_init_rx_data { + u8 tpa_en; +#define CLIENT_INIT_RX_DATA_TPA_EN_IPV4 (0x1<<0) +#define CLIENT_INIT_RX_DATA_TPA_EN_IPV4_SHIFT 0 +#define CLIENT_INIT_RX_DATA_TPA_EN_IPV6 (0x1<<1) +#define CLIENT_INIT_RX_DATA_TPA_EN_IPV6_SHIFT 1 +#define CLIENT_INIT_RX_DATA_RESERVED5 (0x3F<<2) +#define CLIENT_INIT_RX_DATA_RESERVED5_SHIFT 2 + u8 vmqueue_mode_en_flg; + u8 extra_data_over_sgl_en_flg; + u8 cache_line_alignment_log_size; + u8 enable_dynamic_hc; + u8 max_sges_for_packet; + u8 client_qzone_id; + u8 drop_ip_cs_err_flg; + u8 drop_tcp_cs_err_flg; + u8 drop_ttl0_flg; + u8 drop_udp_cs_err_flg; + u8 inner_vlan_removal_enable_flg; + u8 outer_vlan_removal_enable_flg; + u8 status_block_id; + u8 rx_sb_index_number; + u8 reserved0; + u8 max_tpa_queues; + u8 silent_vlan_removal_flg; + __le16 max_bytes_on_bd; + __le16 sge_buff_size; + u8 approx_mcast_engine_id; + u8 rss_engine_id; + struct regpair bd_page_base; + struct regpair sge_page_base; + struct regpair cqe_page_base; + u8 is_leading_rss; + u8 is_approx_mcast; + __le16 max_agg_size; + __le16 state; +#define CLIENT_INIT_RX_DATA_UCAST_DROP_ALL (0x1<<0) +#define CLIENT_INIT_RX_DATA_UCAST_DROP_ALL_SHIFT 0 +#define CLIENT_INIT_RX_DATA_UCAST_ACCEPT_ALL (0x1<<1) +#define CLIENT_INIT_RX_DATA_UCAST_ACCEPT_ALL_SHIFT 1 +#define CLIENT_INIT_RX_DATA_UCAST_ACCEPT_UNMATCHED (0x1<<2) +#define CLIENT_INIT_RX_DATA_UCAST_ACCEPT_UNMATCHED_SHIFT 2 +#define CLIENT_INIT_RX_DATA_MCAST_DROP_ALL (0x1<<3) +#define CLIENT_INIT_RX_DATA_MCAST_DROP_ALL_SHIFT 3 +#define CLIENT_INIT_RX_DATA_MCAST_ACCEPT_ALL (0x1<<4) +#define CLIENT_INIT_RX_DATA_MCAST_ACCEPT_ALL_SHIFT 4 +#define CLIENT_INIT_RX_DATA_BCAST_ACCEPT_ALL (0x1<<5) +#define CLIENT_INIT_RX_DATA_BCAST_ACCEPT_ALL_SHIFT 5 +#define CLIENT_INIT_RX_DATA_ACCEPT_ANY_VLAN (0x1<<6) +#define CLIENT_INIT_RX_DATA_ACCEPT_ANY_VLAN_SHIFT 6 +#define CLIENT_INIT_RX_DATA_RESERVED2 (0x1FF<<7) +#define CLIENT_INIT_RX_DATA_RESERVED2_SHIFT 7 + __le16 cqe_pause_thr_low; + __le16 cqe_pause_thr_high; + __le16 bd_pause_thr_low; + __le16 bd_pause_thr_high; + __le16 sge_pause_thr_low; + __le16 sge_pause_thr_high; + __le16 rx_cos_mask; + __le16 silent_vlan_value; + __le16 silent_vlan_mask; + __le32 reserved6[2]; +}; + +/* + * client init tx data + */ +struct client_init_tx_data { + u8 enforce_security_flg; + u8 tx_status_block_id; + u8 tx_sb_index_number; + u8 tss_leading_client_id; + u8 tx_switching_flg; + u8 anti_spoofing_flg; + __le16 default_vlan; + struct regpair tx_bd_page_base; + __le16 state; +#define CLIENT_INIT_TX_DATA_UCAST_ACCEPT_ALL (0x1<<0) +#define CLIENT_INIT_TX_DATA_UCAST_ACCEPT_ALL_SHIFT 0 +#define CLIENT_INIT_TX_DATA_MCAST_ACCEPT_ALL (0x1<<1) +#define CLIENT_INIT_TX_DATA_MCAST_ACCEPT_ALL_SHIFT 1 +#define CLIENT_INIT_TX_DATA_BCAST_ACCEPT_ALL (0x1<<2) +#define CLIENT_INIT_TX_DATA_BCAST_ACCEPT_ALL_SHIFT 2 +#define CLIENT_INIT_TX_DATA_ACCEPT_ANY_VLAN (0x1<<3) +#define CLIENT_INIT_TX_DATA_ACCEPT_ANY_VLAN_SHIFT 3 +#define CLIENT_INIT_TX_DATA_RESERVED1 (0xFFF<<4) +#define CLIENT_INIT_TX_DATA_RESERVED1_SHIFT 4 + u8 default_vlan_flg; + u8 reserved2; + __le32 reserved3; +}; + +/* + * client init ramrod data + */ +struct client_init_ramrod_data { + struct client_init_general_data general; + struct client_init_rx_data rx; + struct client_init_tx_data tx; +}; + + +/* + * client update ramrod data + */ +struct client_update_ramrod_data { + u8 client_id; + u8 func_id; + u8 inner_vlan_removal_enable_flg; + u8 inner_vlan_removal_change_flg; + u8 outer_vlan_removal_enable_flg; + u8 outer_vlan_removal_change_flg; + u8 anti_spoofing_enable_flg; + u8 anti_spoofing_change_flg; + u8 activate_flg; + u8 activate_change_flg; + __le16 default_vlan; + u8 default_vlan_enable_flg; + u8 default_vlan_change_flg; + __le16 silent_vlan_value; + __le16 silent_vlan_mask; + u8 silent_vlan_removal_flg; + u8 silent_vlan_change_flg; + __le32 echo; +}; + + +/* + * The eth storm context of Cstorm + */ +struct cstorm_eth_st_context { + u32 __reserved0[4]; +}; + + +struct double_regpair { + u32 regpair0_lo; + u32 regpair0_hi; + u32 regpair1_lo; + u32 regpair1_hi; +}; + + +/* + * Ethernet address typesm used in ethernet tx BDs + */ +enum eth_addr_type { + UNKNOWN_ADDRESS, + UNICAST_ADDRESS, + MULTICAST_ADDRESS, + BROADCAST_ADDRESS, + MAX_ETH_ADDR_TYPE +}; + + +/* + * + */ +struct eth_classify_cmd_header { + u8 cmd_general_data; +#define ETH_CLASSIFY_CMD_HEADER_RX_CMD (0x1<<0) +#define ETH_CLASSIFY_CMD_HEADER_RX_CMD_SHIFT 0 +#define ETH_CLASSIFY_CMD_HEADER_TX_CMD (0x1<<1) +#define ETH_CLASSIFY_CMD_HEADER_TX_CMD_SHIFT 1 +#define ETH_CLASSIFY_CMD_HEADER_OPCODE (0x3<<2) +#define ETH_CLASSIFY_CMD_HEADER_OPCODE_SHIFT 2 +#define ETH_CLASSIFY_CMD_HEADER_IS_ADD (0x1<<4) +#define ETH_CLASSIFY_CMD_HEADER_IS_ADD_SHIFT 4 +#define ETH_CLASSIFY_CMD_HEADER_RESERVED0 (0x7<<5) +#define ETH_CLASSIFY_CMD_HEADER_RESERVED0_SHIFT 5 + u8 func_id; + u8 client_id; + u8 reserved1; +}; + + +/* + * header for eth classification config ramrod + */ +struct eth_classify_header { + u8 rule_cnt; + u8 reserved0; + __le16 reserved1; + __le32 echo; +}; + + +/* + * Command for adding/removing a MAC classification rule + */ +struct eth_classify_mac_cmd { + struct eth_classify_cmd_header header; + __le32 reserved0; + __le16 mac_lsb; + __le16 mac_mid; + __le16 mac_msb; + __le16 reserved1; +}; + + +/* + * Command for adding/removing a MAC-VLAN pair classification rule + */ +struct eth_classify_pair_cmd { + struct eth_classify_cmd_header header; + __le32 reserved0; + __le16 mac_lsb; + __le16 mac_mid; + __le16 mac_msb; + __le16 vlan; +}; + + +/* + * Command for adding/removing a VLAN classification rule + */ +struct eth_classify_vlan_cmd { + struct eth_classify_cmd_header header; + __le32 reserved0; + __le32 reserved1; + __le16 reserved2; + __le16 vlan; +}; + +/* + * union for eth classification rule + */ +union eth_classify_rule_cmd { + struct eth_classify_mac_cmd mac; + struct eth_classify_vlan_cmd vlan; + struct eth_classify_pair_cmd pair; +}; + +/* + * parameters for eth classification configuration ramrod + */ +struct eth_classify_rules_ramrod_data { + struct eth_classify_header header; + union eth_classify_rule_cmd rules[CLASSIFY_RULES_COUNT]; +}; + + +/* + * The data contain client ID need to the ramrod + */ +struct eth_common_ramrod_data { + __le32 client_id; + __le32 reserved1; +}; + + +/* + * The eth storm context of Ustorm + */ +struct ustorm_eth_st_context { + u32 reserved0[52]; +}; + +/* + * The eth storm context of Tstorm + */ +struct tstorm_eth_st_context { + u32 __reserved0[28]; +}; + +/* + * The eth storm context of Xstorm + */ +struct xstorm_eth_st_context { + u32 reserved0[60]; +}; + +/* + * Ethernet connection context + */ +struct eth_context { + struct ustorm_eth_st_context ustorm_st_context; + struct tstorm_eth_st_context tstorm_st_context; + struct xstorm_eth_ag_context xstorm_ag_context; + struct tstorm_eth_ag_context tstorm_ag_context; + struct cstorm_eth_ag_context cstorm_ag_context; + struct ustorm_eth_ag_context ustorm_ag_context; + struct timers_block_context timers_context; + struct xstorm_eth_st_context xstorm_st_context; + struct cstorm_eth_st_context cstorm_st_context; +}; + + +/* + * union for sgl and raw data. + */ +union eth_sgl_or_raw_data { + __le16 sgl[8]; + u32 raw_data[4]; +}; + +/* + * eth FP end aggregation CQE parameters struct + */ +struct eth_end_agg_rx_cqe { + u8 type_error_flags; +#define ETH_END_AGG_RX_CQE_TYPE (0x3<<0) +#define ETH_END_AGG_RX_CQE_TYPE_SHIFT 0 +#define ETH_END_AGG_RX_CQE_SGL_RAW_SEL (0x1<<2) +#define ETH_END_AGG_RX_CQE_SGL_RAW_SEL_SHIFT 2 +#define ETH_END_AGG_RX_CQE_RESERVED0 (0x1F<<3) +#define ETH_END_AGG_RX_CQE_RESERVED0_SHIFT 3 + u8 reserved1; + u8 queue_index; + u8 reserved2; + __le32 timestamp_delta; + __le16 num_of_coalesced_segs; + __le16 pkt_len; + u8 pure_ack_count; + u8 reserved3; + __le16 reserved4; + union eth_sgl_or_raw_data sgl_or_raw_data; + __le32 reserved5[8]; +}; + + +/* + * regular eth FP CQE parameters struct + */ +struct eth_fast_path_rx_cqe { + u8 type_error_flags; +#define ETH_FAST_PATH_RX_CQE_TYPE (0x3<<0) +#define ETH_FAST_PATH_RX_CQE_TYPE_SHIFT 0 +#define ETH_FAST_PATH_RX_CQE_SGL_RAW_SEL (0x1<<2) +#define ETH_FAST_PATH_RX_CQE_SGL_RAW_SEL_SHIFT 2 +#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG (0x1<<3) +#define ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG_SHIFT 3 +#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG (0x1<<4) +#define ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG_SHIFT 4 +#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG (0x1<<5) +#define ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG_SHIFT 5 +#define ETH_FAST_PATH_RX_CQE_RESERVED0 (0x3<<6) +#define ETH_FAST_PATH_RX_CQE_RESERVED0_SHIFT 6 + u8 status_flags; +#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE (0x7<<0) +#define ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE_SHIFT 0 +#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG (0x1<<3) +#define ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG_SHIFT 3 +#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG (0x1<<4) +#define ETH_FAST_PATH_RX_CQE_BROADCAST_FLG_SHIFT 4 +#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG (0x1<<5) +#define ETH_FAST_PATH_RX_CQE_MAC_MATCH_FLG_SHIFT 5 +#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG (0x1<<6) +#define ETH_FAST_PATH_RX_CQE_IP_XSUM_NO_VALIDATION_FLG_SHIFT 6 +#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG (0x1<<7) +#define ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG_SHIFT 7 + u8 queue_index; + u8 placement_offset; + __le32 rss_hash_result; + __le16 vlan_tag; + __le16 pkt_len; + __le16 len_on_bd; + struct parsing_flags pars_flags; + union eth_sgl_or_raw_data sgl_or_raw_data; + __le32 reserved1[8]; +}; + + +/* + * Command for setting classification flags for a client + */ +struct eth_filter_rules_cmd { + u8 cmd_general_data; +#define ETH_FILTER_RULES_CMD_RX_CMD (0x1<<0) +#define ETH_FILTER_RULES_CMD_RX_CMD_SHIFT 0 +#define ETH_FILTER_RULES_CMD_TX_CMD (0x1<<1) +#define ETH_FILTER_RULES_CMD_TX_CMD_SHIFT 1 +#define ETH_FILTER_RULES_CMD_RESERVED0 (0x3F<<2) +#define ETH_FILTER_RULES_CMD_RESERVED0_SHIFT 2 + u8 func_id; + u8 client_id; + u8 reserved1; + __le16 state; +#define ETH_FILTER_RULES_CMD_UCAST_DROP_ALL (0x1<<0) +#define ETH_FILTER_RULES_CMD_UCAST_DROP_ALL_SHIFT 0 +#define ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL (0x1<<1) +#define ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL_SHIFT 1 +#define ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED (0x1<<2) +#define ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED_SHIFT 2 +#define ETH_FILTER_RULES_CMD_MCAST_DROP_ALL (0x1<<3) +#define ETH_FILTER_RULES_CMD_MCAST_DROP_ALL_SHIFT 3 +#define ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL (0x1<<4) +#define ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL_SHIFT 4 +#define ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL (0x1<<5) +#define ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL_SHIFT 5 +#define ETH_FILTER_RULES_CMD_ACCEPT_ANY_VLAN (0x1<<6) +#define ETH_FILTER_RULES_CMD_ACCEPT_ANY_VLAN_SHIFT 6 +#define ETH_FILTER_RULES_CMD_RESERVED2 (0x1FF<<7) +#define ETH_FILTER_RULES_CMD_RESERVED2_SHIFT 7 + __le16 reserved3; + struct regpair reserved4; +}; + + +/* + * parameters for eth classification filters ramrod + */ +struct eth_filter_rules_ramrod_data { + struct eth_classify_header header; + struct eth_filter_rules_cmd rules[FILTER_RULES_COUNT]; +}; + + +/* + * parameters for eth classification configuration ramrod + */ +struct eth_general_rules_ramrod_data { + struct eth_classify_header header; + union eth_classify_rule_cmd rules[CLASSIFY_RULES_COUNT]; +}; + + +/* + * The data for Halt ramrod + */ +struct eth_halt_ramrod_data { + __le32 client_id; + __le32 reserved0; +}; + + +/* + * Command for setting multicast classification for a client + */ +struct eth_multicast_rules_cmd { + u8 cmd_general_data; +#define ETH_MULTICAST_RULES_CMD_RX_CMD (0x1<<0) +#define ETH_MULTICAST_RULES_CMD_RX_CMD_SHIFT 0 +#define ETH_MULTICAST_RULES_CMD_TX_CMD (0x1<<1) +#define ETH_MULTICAST_RULES_CMD_TX_CMD_SHIFT 1 +#define ETH_MULTICAST_RULES_CMD_IS_ADD (0x1<<2) +#define ETH_MULTICAST_RULES_CMD_IS_ADD_SHIFT 2 +#define ETH_MULTICAST_RULES_CMD_RESERVED0 (0x1F<<3) +#define ETH_MULTICAST_RULES_CMD_RESERVED0_SHIFT 3 + u8 func_id; + u8 bin_id; + u8 engine_id; + __le32 reserved2; + struct regpair reserved3; +}; + + +/* + * parameters for multicast classification ramrod + */ +struct eth_multicast_rules_ramrod_data { + struct eth_classify_header header; + struct eth_multicast_rules_cmd rules[MULTICAST_RULES_COUNT]; +}; + + +/* + * Place holder for ramrods protocol specific data + */ +struct ramrod_data { + __le32 data_lo; + __le32 data_hi; +}; + +/* + * union for ramrod data for Ethernet protocol (CQE) (force size of 16 bits) + */ +union eth_ramrod_data { + struct ramrod_data general; +}; + + +/* + * RSS toeplitz hash type, as reported in CQE + */ +enum eth_rss_hash_type { + DEFAULT_HASH_TYPE, + IPV4_HASH_TYPE, + TCP_IPV4_HASH_TYPE, + IPV6_HASH_TYPE, + TCP_IPV6_HASH_TYPE, + VLAN_PRI_HASH_TYPE, + E1HOV_PRI_HASH_TYPE, + DSCP_HASH_TYPE, + MAX_ETH_RSS_HASH_TYPE +}; + + +/* + * Ethernet RSS mode + */ +enum eth_rss_mode { + ETH_RSS_MODE_DISABLED, + ETH_RSS_MODE_REGULAR, + ETH_RSS_MODE_VLAN_PRI, + ETH_RSS_MODE_E1HOV_PRI, + ETH_RSS_MODE_IP_DSCP, + MAX_ETH_RSS_MODE +}; + + +/* + * parameters for RSS update ramrod (E2) + */ +struct eth_rss_update_ramrod_data { + u8 rss_engine_id; + u8 capabilities; +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY (0x1<<0) +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY_SHIFT 0 +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY (0x1<<1) +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY_SHIFT 1 +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY (0x1<<2) +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV4_UDP_CAPABILITY_SHIFT 2 +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY (0x1<<3) +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY_SHIFT 3 +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY (0x1<<4) +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY_SHIFT 4 +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY (0x1<<5) +#define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY_SHIFT 5 +#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY (0x1<<6) +#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY_SHIFT 6 +#define __ETH_RSS_UPDATE_RAMROD_DATA_RESERVED0 (0x1<<7) +#define __ETH_RSS_UPDATE_RAMROD_DATA_RESERVED0_SHIFT 7 + u8 rss_result_mask; + u8 rss_mode; + __le32 __reserved2; + u8 indirection_table[T_ETH_INDIRECTION_TABLE_SIZE]; + __le32 rss_key[T_ETH_RSS_KEY]; + __le32 echo; + __le32 reserved3; +}; + + +/* + * The eth Rx Buffer Descriptor + */ +struct eth_rx_bd { + __le32 addr_lo; + __le32 addr_hi; +}; + + +/* + * Eth Rx Cqe structure- general structure for ramrods + */ +struct common_ramrod_eth_rx_cqe { + u8 ramrod_type; +#define COMMON_RAMROD_ETH_RX_CQE_TYPE (0x3<<0) +#define COMMON_RAMROD_ETH_RX_CQE_TYPE_SHIFT 0 +#define COMMON_RAMROD_ETH_RX_CQE_ERROR (0x1<<2) +#define COMMON_RAMROD_ETH_RX_CQE_ERROR_SHIFT 2 +#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0 (0x1F<<3) +#define COMMON_RAMROD_ETH_RX_CQE_RESERVED0_SHIFT 3 + u8 conn_type; + __le16 reserved1; + __le32 conn_and_cmd_data; +#define COMMON_RAMROD_ETH_RX_CQE_CID (0xFFFFFF<<0) +#define COMMON_RAMROD_ETH_RX_CQE_CID_SHIFT 0 +#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID (0xFF<<24) +#define COMMON_RAMROD_ETH_RX_CQE_CMD_ID_SHIFT 24 + struct ramrod_data protocol_data; + __le32 echo; + __le32 reserved2[11]; +}; + +/* + * Rx Last CQE in page (in ETH) + */ +struct eth_rx_cqe_next_page { + __le32 addr_lo; + __le32 addr_hi; + __le32 reserved[14]; +}; + +/* + * union for all eth rx cqe types (fix their sizes) + */ +union eth_rx_cqe { + struct eth_fast_path_rx_cqe fast_path_cqe; + struct common_ramrod_eth_rx_cqe ramrod_cqe; + struct eth_rx_cqe_next_page next_page_cqe; + struct eth_end_agg_rx_cqe end_agg_cqe; +}; + + +/* + * Values for RX ETH CQE type field + */ +enum eth_rx_cqe_type { + RX_ETH_CQE_TYPE_ETH_FASTPATH, + RX_ETH_CQE_TYPE_ETH_RAMROD, + RX_ETH_CQE_TYPE_ETH_START_AGG, + RX_ETH_CQE_TYPE_ETH_STOP_AGG, + MAX_ETH_RX_CQE_TYPE +}; + + +/* + * Type of SGL/Raw field in ETH RX fast path CQE + */ +enum eth_rx_fp_sel { + ETH_FP_CQE_REGULAR, + ETH_FP_CQE_RAW, + MAX_ETH_RX_FP_SEL +}; + + +/* + * The eth Rx SGE Descriptor + */ +struct eth_rx_sge { + __le32 addr_lo; + __le32 addr_hi; +}; + + +/* + * common data for all protocols + */ +struct spe_hdr { + __le32 conn_and_cmd_data; +#define SPE_HDR_CID (0xFFFFFF<<0) +#define SPE_HDR_CID_SHIFT 0 +#define SPE_HDR_CMD_ID (0xFF<<24) +#define SPE_HDR_CMD_ID_SHIFT 24 + __le16 type; +#define SPE_HDR_CONN_TYPE (0xFF<<0) +#define SPE_HDR_CONN_TYPE_SHIFT 0 +#define SPE_HDR_FUNCTION_ID (0xFF<<8) +#define SPE_HDR_FUNCTION_ID_SHIFT 8 + __le16 reserved1; +}; + +/* + * specific data for ethernet slow path element + */ +union eth_specific_data { + u8 protocol_data[8]; + struct regpair client_update_ramrod_data; + struct regpair client_init_ramrod_init_data; + struct eth_halt_ramrod_data halt_ramrod_data; + struct regpair update_data_addr; + struct eth_common_ramrod_data common_ramrod_data; + struct regpair classify_cfg_addr; + struct regpair filter_cfg_addr; + struct regpair mcast_cfg_addr; +}; + +/* + * Ethernet slow path element + */ +struct eth_spe { + struct spe_hdr hdr; + union eth_specific_data data; +}; + + +/* + * Ethernet command ID for slow path elements + */ +enum eth_spqe_cmd_id { + RAMROD_CMD_ID_ETH_UNUSED, + RAMROD_CMD_ID_ETH_CLIENT_SETUP, + RAMROD_CMD_ID_ETH_HALT, + RAMROD_CMD_ID_ETH_FORWARD_SETUP, + RAMROD_CMD_ID_ETH_TX_QUEUE_SETUP, + RAMROD_CMD_ID_ETH_CLIENT_UPDATE, + RAMROD_CMD_ID_ETH_EMPTY, + RAMROD_CMD_ID_ETH_TERMINATE, + RAMROD_CMD_ID_ETH_TPA_UPDATE, + RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES, + RAMROD_CMD_ID_ETH_FILTER_RULES, + RAMROD_CMD_ID_ETH_MULTICAST_RULES, + RAMROD_CMD_ID_ETH_RSS_UPDATE, + RAMROD_CMD_ID_ETH_SET_MAC, + MAX_ETH_SPQE_CMD_ID +}; + + +/* + * eth tpa update command + */ +enum eth_tpa_update_command { + TPA_UPDATE_NONE_COMMAND, + TPA_UPDATE_ENABLE_COMMAND, + TPA_UPDATE_DISABLE_COMMAND, + MAX_ETH_TPA_UPDATE_COMMAND +}; + + +/* + * Tx regular BD structure + */ +struct eth_tx_bd { + __le32 addr_lo; + __le32 addr_hi; + __le16 total_pkt_bytes; + __le16 nbytes; + u8 reserved[4]; +}; + + +/* + * structure for easy accessibility to assembler + */ +struct eth_tx_bd_flags { + u8 as_bitfield; +#define ETH_TX_BD_FLAGS_IP_CSUM (0x1<<0) +#define ETH_TX_BD_FLAGS_IP_CSUM_SHIFT 0 +#define ETH_TX_BD_FLAGS_L4_CSUM (0x1<<1) +#define ETH_TX_BD_FLAGS_L4_CSUM_SHIFT 1 +#define ETH_TX_BD_FLAGS_VLAN_MODE (0x3<<2) +#define ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT 2 +#define ETH_TX_BD_FLAGS_START_BD (0x1<<4) +#define ETH_TX_BD_FLAGS_START_BD_SHIFT 4 +#define ETH_TX_BD_FLAGS_IS_UDP (0x1<<5) +#define ETH_TX_BD_FLAGS_IS_UDP_SHIFT 5 +#define ETH_TX_BD_FLAGS_SW_LSO (0x1<<6) +#define ETH_TX_BD_FLAGS_SW_LSO_SHIFT 6 +#define ETH_TX_BD_FLAGS_IPV6 (0x1<<7) +#define ETH_TX_BD_FLAGS_IPV6_SHIFT 7 +}; + +/* + * The eth Tx Buffer Descriptor + */ +struct eth_tx_start_bd { + __le32 addr_lo; + __le32 addr_hi; + __le16 nbd; + __le16 nbytes; + __le16 vlan_or_ethertype; + struct eth_tx_bd_flags bd_flags; + u8 general_data; +#define ETH_TX_START_BD_HDR_NBDS (0xF<<0) +#define ETH_TX_START_BD_HDR_NBDS_SHIFT 0 +#define ETH_TX_START_BD_FORCE_VLAN_MODE (0x1<<4) +#define ETH_TX_START_BD_FORCE_VLAN_MODE_SHIFT 4 +#define ETH_TX_START_BD_RESREVED (0x1<<5) +#define ETH_TX_START_BD_RESREVED_SHIFT 5 +#define ETH_TX_START_BD_ETH_ADDR_TYPE (0x3<<6) +#define ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT 6 +}; + +/* + * Tx parsing BD structure for ETH E1/E1h + */ +struct eth_tx_parse_bd_e1x { + u8 global_data; +#define ETH_TX_PARSE_BD_E1X_IP_HDR_START_OFFSET_W (0xF<<0) +#define ETH_TX_PARSE_BD_E1X_IP_HDR_START_OFFSET_W_SHIFT 0 +#define ETH_TX_PARSE_BD_E1X_RESERVED0 (0x1<<4) +#define ETH_TX_PARSE_BD_E1X_RESERVED0_SHIFT 4 +#define ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN (0x1<<5) +#define ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN_SHIFT 5 +#define ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN (0x1<<6) +#define ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT 6 +#define ETH_TX_PARSE_BD_E1X_NS_FLG (0x1<<7) +#define ETH_TX_PARSE_BD_E1X_NS_FLG_SHIFT 7 + u8 tcp_flags; +#define ETH_TX_PARSE_BD_E1X_FIN_FLG (0x1<<0) +#define ETH_TX_PARSE_BD_E1X_FIN_FLG_SHIFT 0 +#define ETH_TX_PARSE_BD_E1X_SYN_FLG (0x1<<1) +#define ETH_TX_PARSE_BD_E1X_SYN_FLG_SHIFT 1 +#define ETH_TX_PARSE_BD_E1X_RST_FLG (0x1<<2) +#define ETH_TX_PARSE_BD_E1X_RST_FLG_SHIFT 2 +#define ETH_TX_PARSE_BD_E1X_PSH_FLG (0x1<<3) +#define ETH_TX_PARSE_BD_E1X_PSH_FLG_SHIFT 3 +#define ETH_TX_PARSE_BD_E1X_ACK_FLG (0x1<<4) +#define ETH_TX_PARSE_BD_E1X_ACK_FLG_SHIFT 4 +#define ETH_TX_PARSE_BD_E1X_URG_FLG (0x1<<5) +#define ETH_TX_PARSE_BD_E1X_URG_FLG_SHIFT 5 +#define ETH_TX_PARSE_BD_E1X_ECE_FLG (0x1<<6) +#define ETH_TX_PARSE_BD_E1X_ECE_FLG_SHIFT 6 +#define ETH_TX_PARSE_BD_E1X_CWR_FLG (0x1<<7) +#define ETH_TX_PARSE_BD_E1X_CWR_FLG_SHIFT 7 + u8 ip_hlen_w; + s8 reserved; + __le16 total_hlen_w; + __le16 tcp_pseudo_csum; + __le16 lso_mss; + __le16 ip_id; + __le32 tcp_send_seq; +}; + +/* + * Tx parsing BD structure for ETH E2 + */ +struct eth_tx_parse_bd_e2 { + __le16 dst_mac_addr_lo; + __le16 dst_mac_addr_mid; + __le16 dst_mac_addr_hi; + __le16 src_mac_addr_lo; + __le16 src_mac_addr_mid; + __le16 src_mac_addr_hi; + __le32 parsing_data; +#define ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W (0x1FFF<<0) +#define ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT 0 +#define ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW (0xF<<13) +#define ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT 13 +#define ETH_TX_PARSE_BD_E2_LSO_MSS (0x3FFF<<17) +#define ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT 17 +#define ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR (0x1<<31) +#define ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR_SHIFT 31 +}; + +/* + * The last BD in the BD memory will hold a pointer to the next BD memory + */ +struct eth_tx_next_bd { + __le32 addr_lo; + __le32 addr_hi; + u8 reserved[8]; +}; + +/* + * union for 4 Bd types + */ +union eth_tx_bd_types { + struct eth_tx_start_bd start_bd; + struct eth_tx_bd reg_bd; + struct eth_tx_parse_bd_e1x parse_bd_e1x; + struct eth_tx_parse_bd_e2 parse_bd_e2; + struct eth_tx_next_bd next_bd; +}; + +/* + * array of 13 bds as appears in the eth xstorm context + */ +struct eth_tx_bds_array { + union eth_tx_bd_types bds[13]; +}; + + +/* + * VLAN mode on TX BDs + */ +enum eth_tx_vlan_type { + X_ETH_NO_VLAN, + X_ETH_OUTBAND_VLAN, + X_ETH_INBAND_VLAN, + X_ETH_FW_ADDED_VLAN, + MAX_ETH_TX_VLAN_TYPE +}; + + +/* + * Ethernet VLAN filtering mode in E1x + */ +enum eth_vlan_filter_mode { + ETH_VLAN_FILTER_ANY_VLAN, + ETH_VLAN_FILTER_SPECIFIC_VLAN, + ETH_VLAN_FILTER_CLASSIFY, + MAX_ETH_VLAN_FILTER_MODE +}; + + +/* + * MAC filtering configuration command header + */ +struct mac_configuration_hdr { + u8 length; + u8 offset; + __le16 client_id; + __le32 echo; +}; + +/* + * MAC address in list for ramrod + */ +struct mac_configuration_entry { + __le16 lsb_mac_addr; + __le16 middle_mac_addr; + __le16 msb_mac_addr; + __le16 vlan_id; + u8 pf_id; + u8 flags; +#define MAC_CONFIGURATION_ENTRY_ACTION_TYPE (0x1<<0) +#define MAC_CONFIGURATION_ENTRY_ACTION_TYPE_SHIFT 0 +#define MAC_CONFIGURATION_ENTRY_RDMA_MAC (0x1<<1) +#define MAC_CONFIGURATION_ENTRY_RDMA_MAC_SHIFT 1 +#define MAC_CONFIGURATION_ENTRY_VLAN_FILTERING_MODE (0x3<<2) +#define MAC_CONFIGURATION_ENTRY_VLAN_FILTERING_MODE_SHIFT 2 +#define MAC_CONFIGURATION_ENTRY_OVERRIDE_VLAN_REMOVAL (0x1<<4) +#define MAC_CONFIGURATION_ENTRY_OVERRIDE_VLAN_REMOVAL_SHIFT 4 +#define MAC_CONFIGURATION_ENTRY_BROADCAST (0x1<<5) +#define MAC_CONFIGURATION_ENTRY_BROADCAST_SHIFT 5 +#define MAC_CONFIGURATION_ENTRY_RESERVED1 (0x3<<6) +#define MAC_CONFIGURATION_ENTRY_RESERVED1_SHIFT 6 + __le16 reserved0; + __le32 clients_bit_vector; +}; + +/* + * MAC filtering configuration command + */ +struct mac_configuration_cmd { + struct mac_configuration_hdr hdr; + struct mac_configuration_entry config_table[64]; +}; + + +/* + * Set-MAC command type (in E1x) + */ +enum set_mac_action_type { + T_ETH_MAC_COMMAND_INVALIDATE, + T_ETH_MAC_COMMAND_SET, + MAX_SET_MAC_ACTION_TYPE +}; + + +/* + * tpa update ramrod data + */ +struct tpa_update_ramrod_data { + u8 update_ipv4; + u8 update_ipv6; + u8 client_id; + u8 max_tpa_queues; + u8 max_sges_for_packet; + u8 complete_on_both_clients; + __le16 reserved1; + __le16 sge_buff_size; + __le16 max_agg_size; + __le32 sge_page_base_lo; + __le32 sge_page_base_hi; + __le16 sge_pause_thr_low; + __le16 sge_pause_thr_high; +}; + + +/* + * approximate-match multicast filtering for E1H per function in Tstorm + */ +struct tstorm_eth_approximate_match_multicast_filtering { + u32 mcast_add_hash_bit_array[8]; +}; + + +/* + * Common configuration parameters per function in Tstorm + */ +struct tstorm_eth_function_common_config { + __le16 config_flags; +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY (0x1<<0) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_CAPABILITY_SHIFT 0 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY (0x1<<1) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV4_TCP_CAPABILITY_SHIFT 1 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY (0x1<<2) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_CAPABILITY_SHIFT 2 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY (0x1<<3) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_IPV6_TCP_CAPABILITY_SHIFT 3 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE (0x7<<4) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_RSS_MODE_SHIFT 4 +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_FILTERING_ENABLE (0x1<<7) +#define TSTORM_ETH_FUNCTION_COMMON_CONFIG_VLAN_FILTERING_ENABLE_SHIFT 7 +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0 (0xFF<<8) +#define __TSTORM_ETH_FUNCTION_COMMON_CONFIG_RESERVED0_SHIFT 8 + u8 rss_result_mask; + u8 reserved1; + __le16 vlan_id[2]; +}; + + +/* + * MAC filtering configuration parameters per port in Tstorm + */ +struct tstorm_eth_mac_filter_config { + __le32 ucast_drop_all; + __le32 ucast_accept_all; + __le32 mcast_drop_all; + __le32 mcast_accept_all; + __le32 bcast_accept_all; + __le32 vlan_filter[2]; + __le32 unmatched_unicast; +}; + + +/* + * tx only queue init ramrod data + */ +struct tx_queue_init_ramrod_data { + struct client_init_general_data general; + struct client_init_tx_data tx; +}; + + +/* + * Three RX producers for ETH + */ +struct ustorm_eth_rx_producers { +#if defined(__BIG_ENDIAN) + u16 bd_prod; + u16 cqe_prod; +#elif defined(__LITTLE_ENDIAN) + u16 cqe_prod; + u16 bd_prod; +#endif +#if defined(__BIG_ENDIAN) + u16 reserved; + u16 sge_prod; +#elif defined(__LITTLE_ENDIAN) + u16 sge_prod; + u16 reserved; +#endif +}; + + +/* + * cfc delete event data + */ +struct cfc_del_event_data { + u32 cid; + u32 reserved0; + u32 reserved1; +}; + + +/* + * per-port SAFC demo variables + */ +struct cmng_flags_per_port { + u32 cmng_enables; +#define CMNG_FLAGS_PER_PORT_FAIRNESS_VN (0x1<<0) +#define CMNG_FLAGS_PER_PORT_FAIRNESS_VN_SHIFT 0 +#define CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN (0x1<<1) +#define CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN_SHIFT 1 +#define CMNG_FLAGS_PER_PORT_FAIRNESS_COS (0x1<<2) +#define CMNG_FLAGS_PER_PORT_FAIRNESS_COS_SHIFT 2 +#define CMNG_FLAGS_PER_PORT_FAIRNESS_COS_MODE (0x1<<3) +#define CMNG_FLAGS_PER_PORT_FAIRNESS_COS_MODE_SHIFT 3 +#define __CMNG_FLAGS_PER_PORT_RESERVED0 (0xFFFFFFF<<4) +#define __CMNG_FLAGS_PER_PORT_RESERVED0_SHIFT 4 + u32 __reserved1; +}; + + +/* + * per-port rate shaping variables + */ +struct rate_shaping_vars_per_port { + u32 rs_periodic_timeout; + u32 rs_threshold; +}; + +/* + * per-port fairness variables + */ +struct fairness_vars_per_port { + u32 upper_bound; + u32 fair_threshold; + u32 fairness_timeout; + u32 reserved0; +}; + +/* + * per-port SAFC variables + */ +struct safc_struct_per_port { +#if defined(__BIG_ENDIAN) + u16 __reserved1; + u8 __reserved0; + u8 safc_timeout_usec; +#elif defined(__LITTLE_ENDIAN) + u8 safc_timeout_usec; + u8 __reserved0; + u16 __reserved1; +#endif + u8 cos_to_traffic_types[MAX_COS_NUMBER]; + u16 cos_to_pause_mask[NUM_OF_SAFC_BITS]; +}; + +/* + * Per-port congestion management variables + */ +struct cmng_struct_per_port { + struct rate_shaping_vars_per_port rs_vars; + struct fairness_vars_per_port fair_vars; + struct safc_struct_per_port safc_vars; + struct cmng_flags_per_port flags; +}; + + +/* + * Protocol-common command ID for slow path elements + */ +enum common_spqe_cmd_id { + RAMROD_CMD_ID_COMMON_UNUSED, + RAMROD_CMD_ID_COMMON_FUNCTION_START, + RAMROD_CMD_ID_COMMON_FUNCTION_STOP, + RAMROD_CMD_ID_COMMON_CFC_DEL, + RAMROD_CMD_ID_COMMON_CFC_DEL_WB, + RAMROD_CMD_ID_COMMON_STAT_QUERY, + RAMROD_CMD_ID_COMMON_STOP_TRAFFIC, + RAMROD_CMD_ID_COMMON_START_TRAFFIC, + RAMROD_CMD_ID_COMMON_RESERVED1, + RAMROD_CMD_ID_COMMON_RESERVED2, + MAX_COMMON_SPQE_CMD_ID +}; + + +/* + * Per-protocol connection types + */ +enum connection_type { + ETH_CONNECTION_TYPE, + TOE_CONNECTION_TYPE, + RDMA_CONNECTION_TYPE, + ISCSI_CONNECTION_TYPE, + FCOE_CONNECTION_TYPE, + RESERVED_CONNECTION_TYPE_0, + RESERVED_CONNECTION_TYPE_1, + RESERVED_CONNECTION_TYPE_2, + NONE_CONNECTION_TYPE, + MAX_CONNECTION_TYPE +}; + + +/* + * Cos modes + */ +enum cos_mode { + OVERRIDE_COS, + STATIC_COS, + FW_WRR, + MAX_COS_MODE +}; + + +/* + * Dynamic HC counters set by the driver + */ +struct hc_dynamic_drv_counter { + u32 val[HC_SB_MAX_DYNAMIC_INDICES]; +}; + +/* + * zone A per-queue data + */ +struct cstorm_queue_zone_data { + struct hc_dynamic_drv_counter hc_dyn_drv_cnt; + struct regpair reserved[2]; +}; + + +/* + * Vf-PF channel data in cstorm ram (non-triggered zone) + */ +struct vf_pf_channel_zone_data { + u32 msg_addr_lo; + u32 msg_addr_hi; +}; + +/* + * zone for VF non-triggered data + */ +struct non_trigger_vf_zone { + struct vf_pf_channel_zone_data vf_pf_channel; +}; + +/* + * Vf-PF channel trigger zone in cstorm ram + */ +struct vf_pf_channel_zone_trigger { + u8 addr_valid; +}; + +/* + * zone that triggers the in-bound interrupt + */ +struct trigger_vf_zone { +#if defined(__BIG_ENDIAN) + u16 reserved1; + u8 reserved0; + struct vf_pf_channel_zone_trigger vf_pf_channel; +#elif defined(__LITTLE_ENDIAN) + struct vf_pf_channel_zone_trigger vf_pf_channel; + u8 reserved0; + u16 reserved1; +#endif + u32 reserved2; +}; + +/* + * zone B per-VF data + */ +struct cstorm_vf_zone_data { + struct non_trigger_vf_zone non_trigger; + struct trigger_vf_zone trigger; +}; + + +/* + * Dynamic host coalescing init parameters, per state machine + */ +struct dynamic_hc_sm_config { + u32 threshold[3]; + u8 shift_per_protocol[HC_SB_MAX_DYNAMIC_INDICES]; + u8 hc_timeout0[HC_SB_MAX_DYNAMIC_INDICES]; + u8 hc_timeout1[HC_SB_MAX_DYNAMIC_INDICES]; + u8 hc_timeout2[HC_SB_MAX_DYNAMIC_INDICES]; + u8 hc_timeout3[HC_SB_MAX_DYNAMIC_INDICES]; +}; + +/* + * Dynamic host coalescing init parameters + */ +struct dynamic_hc_config { + struct dynamic_hc_sm_config sm_config[HC_SB_MAX_SM]; +}; + + +struct e2_integ_data { +#if defined(__BIG_ENDIAN) + u8 flags; +#define E2_INTEG_DATA_TESTING_EN (0x1<<0) +#define E2_INTEG_DATA_TESTING_EN_SHIFT 0 +#define E2_INTEG_DATA_LB_TX (0x1<<1) +#define E2_INTEG_DATA_LB_TX_SHIFT 1 +#define E2_INTEG_DATA_COS_TX (0x1<<2) +#define E2_INTEG_DATA_COS_TX_SHIFT 2 +#define E2_INTEG_DATA_OPPORTUNISTICQM (0x1<<3) +#define E2_INTEG_DATA_OPPORTUNISTICQM_SHIFT 3 +#define E2_INTEG_DATA_DPMTESTRELEASEDQ (0x1<<4) +#define E2_INTEG_DATA_DPMTESTRELEASEDQ_SHIFT 4 +#define E2_INTEG_DATA_RESERVED (0x7<<5) +#define E2_INTEG_DATA_RESERVED_SHIFT 5 + u8 cos; + u8 voq; + u8 pbf_queue; +#elif defined(__LITTLE_ENDIAN) + u8 pbf_queue; + u8 voq; + u8 cos; + u8 flags; +#define E2_INTEG_DATA_TESTING_EN (0x1<<0) +#define E2_INTEG_DATA_TESTING_EN_SHIFT 0 +#define E2_INTEG_DATA_LB_TX (0x1<<1) +#define E2_INTEG_DATA_LB_TX_SHIFT 1 +#define E2_INTEG_DATA_COS_TX (0x1<<2) +#define E2_INTEG_DATA_COS_TX_SHIFT 2 +#define E2_INTEG_DATA_OPPORTUNISTICQM (0x1<<3) +#define E2_INTEG_DATA_OPPORTUNISTICQM_SHIFT 3 +#define E2_INTEG_DATA_DPMTESTRELEASEDQ (0x1<<4) +#define E2_INTEG_DATA_DPMTESTRELEASEDQ_SHIFT 4 +#define E2_INTEG_DATA_RESERVED (0x7<<5) +#define E2_INTEG_DATA_RESERVED_SHIFT 5 +#endif +#if defined(__BIG_ENDIAN) + u16 reserved3; + u8 reserved2; + u8 ramEn; +#elif defined(__LITTLE_ENDIAN) + u8 ramEn; + u8 reserved2; + u16 reserved3; +#endif +}; + + +/* + * set mac event data + */ +struct eth_event_data { + u32 echo; + u32 reserved0; + u32 reserved1; +}; + + +/* + * pf-vf event data + */ +struct vf_pf_event_data { + u8 vf_id; + u8 reserved0; + u16 reserved1; + u32 msg_addr_lo; + u32 msg_addr_hi; +}; + +/* + * VF FLR event data + */ +struct vf_flr_event_data { + u8 vf_id; + u8 reserved0; + u16 reserved1; + u32 reserved2; + u32 reserved3; +}; + +/* + * malicious VF event data + */ +struct malicious_vf_event_data { + u8 vf_id; + u8 reserved0; + u16 reserved1; + u32 reserved2; + u32 reserved3; +}; + +/* + * union for all event ring message types + */ +union event_data { + struct vf_pf_event_data vf_pf_event; + struct eth_event_data eth_event; + struct cfc_del_event_data cfc_del_event; + struct vf_flr_event_data vf_flr_event; + struct malicious_vf_event_data malicious_vf_event; +}; + + +/* + * per PF event ring data + */ +struct event_ring_data { + struct regpair base_addr; +#if defined(__BIG_ENDIAN) + u8 index_id; + u8 sb_id; + u16 producer; +#elif defined(__LITTLE_ENDIAN) + u16 producer; + u8 sb_id; + u8 index_id; +#endif + u32 reserved0; +}; + + +/* + * event ring message element (each element is 128 bits) + */ +struct event_ring_msg { + u8 opcode; + u8 error; + u16 reserved1; + union event_data data; +}; + +/* + * event ring next page element (128 bits) + */ +struct event_ring_next { + struct regpair addr; + u32 reserved[2]; +}; + +/* + * union for event ring element types (each element is 128 bits) + */ +union event_ring_elem { + struct event_ring_msg message; + struct event_ring_next next_page; +}; + + +/* + * Common event ring opcodes + */ +enum event_ring_opcode { + EVENT_RING_OPCODE_VF_PF_CHANNEL, + EVENT_RING_OPCODE_FUNCTION_START, + EVENT_RING_OPCODE_FUNCTION_STOP, + EVENT_RING_OPCODE_CFC_DEL, + EVENT_RING_OPCODE_CFC_DEL_WB, + EVENT_RING_OPCODE_STAT_QUERY, + EVENT_RING_OPCODE_STOP_TRAFFIC, + EVENT_RING_OPCODE_START_TRAFFIC, + EVENT_RING_OPCODE_VF_FLR, + EVENT_RING_OPCODE_MALICIOUS_VF, + EVENT_RING_OPCODE_FORWARD_SETUP, + EVENT_RING_OPCODE_RSS_UPDATE_RULES, + EVENT_RING_OPCODE_RESERVED1, + EVENT_RING_OPCODE_RESERVED2, + EVENT_RING_OPCODE_SET_MAC, + EVENT_RING_OPCODE_CLASSIFICATION_RULES, + EVENT_RING_OPCODE_FILTERS_RULES, + EVENT_RING_OPCODE_MULTICAST_RULES, + MAX_EVENT_RING_OPCODE +}; + + +/* + * Modes for fairness algorithm + */ +enum fairness_mode { + FAIRNESS_COS_WRR_MODE, + FAIRNESS_COS_ETS_MODE, + MAX_FAIRNESS_MODE +}; + + +/* + * per-vnic fairness variables + */ +struct fairness_vars_per_vn { + u32 cos_credit_delta[MAX_COS_NUMBER]; + u32 vn_credit_delta; + u32 __reserved0; +}; + + +/* + * Priority and cos + */ +struct priority_cos { + u8 priority; + u8 cos; + __le16 reserved1; +}; + +/* + * The data for flow control configuration + */ +struct flow_control_configuration { + struct priority_cos traffic_type_to_priority_cos[MAX_TRAFFIC_TYPES]; + u8 dcb_enabled; + u8 dcb_version; + u8 dont_add_pri_0_en; + u8 reserved1; + __le32 reserved2; +}; + + +/* + * + */ +struct function_start_data { + __le16 function_mode; + __le16 sd_vlan_tag; + u16 reserved; + u8 path_id; + u8 network_cos_mode; +}; + + +/* + * FW version stored in the Xstorm RAM + */ +struct fw_version { +#if defined(__BIG_ENDIAN) + u8 engineering; + u8 revision; + u8 minor; + u8 major; +#elif defined(__LITTLE_ENDIAN) + u8 major; + u8 minor; + u8 revision; + u8 engineering; +#endif + u32 flags; +#define FW_VERSION_OPTIMIZED (0x1<<0) +#define FW_VERSION_OPTIMIZED_SHIFT 0 +#define FW_VERSION_BIG_ENDIEN (0x1<<1) +#define FW_VERSION_BIG_ENDIEN_SHIFT 1 +#define FW_VERSION_CHIP_VERSION (0x3<<2) +#define FW_VERSION_CHIP_VERSION_SHIFT 2 +#define __FW_VERSION_RESERVED (0xFFFFFFF<<4) +#define __FW_VERSION_RESERVED_SHIFT 4 +}; + + +/* + * Dynamic Host-Coalescing - Driver(host) counters + */ +struct hc_dynamic_sb_drv_counters { + u32 dynamic_hc_drv_counter[HC_SB_MAX_DYNAMIC_INDICES]; +}; + + +/* + * 2 bytes. configuration/state parameters for a single protocol index + */ +struct hc_index_data { +#if defined(__BIG_ENDIAN) + u8 flags; +#define HC_INDEX_DATA_SM_ID (0x1<<0) +#define HC_INDEX_DATA_SM_ID_SHIFT 0 +#define HC_INDEX_DATA_HC_ENABLED (0x1<<1) +#define HC_INDEX_DATA_HC_ENABLED_SHIFT 1 +#define HC_INDEX_DATA_DYNAMIC_HC_ENABLED (0x1<<2) +#define HC_INDEX_DATA_DYNAMIC_HC_ENABLED_SHIFT 2 +#define HC_INDEX_DATA_RESERVE (0x1F<<3) +#define HC_INDEX_DATA_RESERVE_SHIFT 3 + u8 timeout; +#elif defined(__LITTLE_ENDIAN) + u8 timeout; + u8 flags; +#define HC_INDEX_DATA_SM_ID (0x1<<0) +#define HC_INDEX_DATA_SM_ID_SHIFT 0 +#define HC_INDEX_DATA_HC_ENABLED (0x1<<1) +#define HC_INDEX_DATA_HC_ENABLED_SHIFT 1 +#define HC_INDEX_DATA_DYNAMIC_HC_ENABLED (0x1<<2) +#define HC_INDEX_DATA_DYNAMIC_HC_ENABLED_SHIFT 2 +#define HC_INDEX_DATA_RESERVE (0x1F<<3) +#define HC_INDEX_DATA_RESERVE_SHIFT 3 +#endif +}; + + +/* + * HC state-machine + */ +struct hc_status_block_sm { +#if defined(__BIG_ENDIAN) + u8 igu_seg_id; + u8 igu_sb_id; + u8 timer_value; + u8 __flags; +#elif defined(__LITTLE_ENDIAN) + u8 __flags; + u8 timer_value; + u8 igu_sb_id; + u8 igu_seg_id; +#endif + u32 time_to_expire; +}; + +/* + * hold PCI identification variables- used in various places in firmware + */ +struct pci_entity { +#if defined(__BIG_ENDIAN) + u8 vf_valid; + u8 vf_id; + u8 vnic_id; + u8 pf_id; +#elif defined(__LITTLE_ENDIAN) + u8 pf_id; + u8 vnic_id; + u8 vf_id; + u8 vf_valid; +#endif +}; + +/* + * The fast-path status block meta-data, common to all chips + */ +struct hc_sb_data { + struct regpair host_sb_addr; + struct hc_status_block_sm state_machine[HC_SB_MAX_SM]; + struct pci_entity p_func; +#if defined(__BIG_ENDIAN) + u8 rsrv0; + u8 state; + u8 dhc_qzone_id; + u8 same_igu_sb_1b; +#elif defined(__LITTLE_ENDIAN) + u8 same_igu_sb_1b; + u8 dhc_qzone_id; + u8 state; + u8 rsrv0; +#endif + struct regpair rsrv1[2]; +}; + + +/* + * Segment types for host coaslescing + */ +enum hc_segment { + HC_REGULAR_SEGMENT, + HC_DEFAULT_SEGMENT, + MAX_HC_SEGMENT +}; + + +/* + * The fast-path status block meta-data + */ +struct hc_sp_status_block_data { + struct regpair host_sb_addr; +#if defined(__BIG_ENDIAN) + u8 rsrv1; + u8 state; + u8 igu_seg_id; + u8 igu_sb_id; +#elif defined(__LITTLE_ENDIAN) + u8 igu_sb_id; + u8 igu_seg_id; + u8 state; + u8 rsrv1; +#endif + struct pci_entity p_func; +}; + + +/* + * The fast-path status block meta-data + */ +struct hc_status_block_data_e1x { + struct hc_index_data index_data[HC_SB_MAX_INDICES_E1X]; + struct hc_sb_data common; +}; + + +/* + * The fast-path status block meta-data + */ +struct hc_status_block_data_e2 { + struct hc_index_data index_data[HC_SB_MAX_INDICES_E2]; + struct hc_sb_data common; +}; + + +/* + * IGU block operartion modes (in Everest2) + */ +enum igu_mode { + HC_IGU_BC_MODE, + HC_IGU_NBC_MODE, + MAX_IGU_MODE +}; + + +/* + * IP versions + */ +enum ip_ver { + IP_V4, + IP_V6, + MAX_IP_VER +}; + + +/* + * Multi-function modes + */ +enum mf_mode { + SINGLE_FUNCTION, + MULTI_FUNCTION_SD, + MULTI_FUNCTION_SI, + MULTI_FUNCTION_RESERVED, + MAX_MF_MODE +}; + +/* + * Protocol-common statistics collected by the Tstorm (per pf) + */ +struct tstorm_per_pf_stats { + struct regpair rcv_error_bytes; +}; + +/* + * + */ +struct per_pf_stats { + struct tstorm_per_pf_stats tstorm_pf_statistics; +}; + + +/* + * Protocol-common statistics collected by the Tstorm (per port) + */ +struct tstorm_per_port_stats { + __le32 mac_discard; + __le32 mac_filter_discard; + __le32 brb_truncate_discard; + __le32 mf_tag_discard; + __le32 packet_drop; + __le32 reserved; +}; + +/* + * + */ +struct per_port_stats { + struct tstorm_per_port_stats tstorm_port_statistics; +}; + + +/* + * Protocol-common statistics collected by the Tstorm (per client) + */ +struct tstorm_per_queue_stats { + struct regpair rcv_ucast_bytes; + __le32 rcv_ucast_pkts; + __le32 checksum_discard; + struct regpair rcv_bcast_bytes; + __le32 rcv_bcast_pkts; + __le32 pkts_too_big_discard; + struct regpair rcv_mcast_bytes; + __le32 rcv_mcast_pkts; + __le32 ttl0_discard; + __le16 no_buff_discard; + __le16 reserved0; + __le32 reserved1; +}; + +/* + * Protocol-common statistics collected by the Ustorm (per client) + */ +struct ustorm_per_queue_stats { + struct regpair ucast_no_buff_bytes; + struct regpair mcast_no_buff_bytes; + struct regpair bcast_no_buff_bytes; + __le32 ucast_no_buff_pkts; + __le32 mcast_no_buff_pkts; + __le32 bcast_no_buff_pkts; + __le32 coalesced_pkts; + struct regpair coalesced_bytes; + __le32 coalesced_events; + __le32 coalesced_aborts; +}; + +/* + * Protocol-common statistics collected by the Xstorm (per client) + */ +struct xstorm_per_queue_stats { + struct regpair ucast_bytes_sent; + struct regpair mcast_bytes_sent; + struct regpair bcast_bytes_sent; + __le32 ucast_pkts_sent; + __le32 mcast_pkts_sent; + __le32 bcast_pkts_sent; + __le32 error_drop_pkts; +}; + +/* + * + */ +struct per_queue_stats { + struct tstorm_per_queue_stats tstorm_queue_statistics; + struct ustorm_per_queue_stats ustorm_queue_statistics; + struct xstorm_per_queue_stats xstorm_queue_statistics; +}; + + +/* + * FW version stored in first line of pram + */ +struct pram_fw_version { + u8 major; + u8 minor; + u8 revision; + u8 engineering; + u8 flags; +#define PRAM_FW_VERSION_OPTIMIZED (0x1<<0) +#define PRAM_FW_VERSION_OPTIMIZED_SHIFT 0 +#define PRAM_FW_VERSION_STORM_ID (0x3<<1) +#define PRAM_FW_VERSION_STORM_ID_SHIFT 1 +#define PRAM_FW_VERSION_BIG_ENDIEN (0x1<<3) +#define PRAM_FW_VERSION_BIG_ENDIEN_SHIFT 3 +#define PRAM_FW_VERSION_CHIP_VERSION (0x3<<4) +#define PRAM_FW_VERSION_CHIP_VERSION_SHIFT 4 +#define __PRAM_FW_VERSION_RESERVED0 (0x3<<6) +#define __PRAM_FW_VERSION_RESERVED0_SHIFT 6 +}; + + +/* + * Ethernet slow path element + */ +union protocol_common_specific_data { + u8 protocol_data[8]; + struct regpair phy_address; + struct regpair mac_config_addr; +}; + +/* + * The send queue element + */ +struct protocol_common_spe { + struct spe_hdr hdr; + union protocol_common_specific_data data; +}; + + +/* + * a single rate shaping counter. can be used as protocol or vnic counter + */ +struct rate_shaping_counter { + u32 quota; +#if defined(__BIG_ENDIAN) + u16 __reserved0; + u16 rate; +#elif defined(__LITTLE_ENDIAN) + u16 rate; + u16 __reserved0; +#endif +}; + + +/* + * per-vnic rate shaping variables + */ +struct rate_shaping_vars_per_vn { + struct rate_shaping_counter vn_counter; +}; + + +/* + * The send queue element + */ +struct slow_path_element { + struct spe_hdr hdr; + struct regpair protocol_data; +}; + + +/* + * Protocol-common statistics counter + */ +struct stats_counter { + __le16 xstats_counter; + __le16 reserved0; + __le32 reserved1; + __le16 tstats_counter; + __le16 reserved2; + __le32 reserved3; + __le16 ustats_counter; + __le16 reserved4; + __le32 reserved5; + __le16 cstats_counter; + __le16 reserved6; + __le32 reserved7; +}; + + +/* + * + */ +struct stats_query_entry { + u8 kind; + u8 index; + __le16 funcID; + __le32 reserved; + struct regpair address; +}; + +/* + * statistic command + */ +struct stats_query_cmd_group { + struct stats_query_entry query[STATS_QUERY_CMD_COUNT]; +}; + + +/* + * statistic command header + */ +struct stats_query_header { + u8 cmd_num; + u8 reserved0; + __le16 drv_stats_counter; + __le32 reserved1; + struct regpair stats_counters_addrs; +}; + + +/* + * Types of statistcis query entry + */ +enum stats_query_type { + STATS_TYPE_QUEUE, + STATS_TYPE_PORT, + STATS_TYPE_PF, + STATS_TYPE_TOE, + STATS_TYPE_FCOE, + MAX_STATS_QUERY_TYPE +}; + + +/* + * Indicate of the function status block state + */ +enum status_block_state { + SB_DISABLED, + SB_ENABLED, + SB_CLEANED, + MAX_STATUS_BLOCK_STATE +}; + + +/* + * Storm IDs (including attentions for IGU related enums) + */ +enum storm_id { + USTORM_ID, + CSTORM_ID, + XSTORM_ID, + TSTORM_ID, + ATTENTION_ID, + MAX_STORM_ID +}; + + +/* + * Taffic types used in ETS and flow control algorithms + */ +enum traffic_type { + LLFC_TRAFFIC_TYPE_NW, + LLFC_TRAFFIC_TYPE_FCOE, + LLFC_TRAFFIC_TYPE_ISCSI, + MAX_TRAFFIC_TYPE +}; + + +/* + * zone A per-queue data + */ +struct tstorm_queue_zone_data { + struct regpair reserved[4]; +}; + + +/* + * zone B per-VF data + */ +struct tstorm_vf_zone_data { + struct regpair reserved; +}; + + +/* + * zone A per-queue data + */ +struct ustorm_queue_zone_data { + struct ustorm_eth_rx_producers eth_rx_producers; + struct regpair reserved[3]; +}; + + +/* + * zone B per-VF data + */ +struct ustorm_vf_zone_data { + struct regpair reserved; +}; + + +/* + * data per VF-PF channel + */ +struct vf_pf_channel_data { +#if defined(__BIG_ENDIAN) + u16 reserved0; + u8 valid; + u8 state; +#elif defined(__LITTLE_ENDIAN) + u8 state; + u8 valid; + u16 reserved0; +#endif + u32 reserved1; +}; + + +/* + * State of VF-PF channel + */ +enum vf_pf_channel_state { + VF_PF_CHANNEL_STATE_READY, + VF_PF_CHANNEL_STATE_WAITING_FOR_ACK, + MAX_VF_PF_CHANNEL_STATE +}; + + +/* + * zone A per-queue data + */ +struct xstorm_queue_zone_data { + struct regpair reserved[4]; +}; + + +/* + * zone B per-VF data + */ +struct xstorm_vf_zone_data { + struct regpair reserved; +}; + +#endif /* BNX2X_HSI_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h new file mode 100644 index 000000000000..4d748e77d1ac --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h @@ -0,0 +1,567 @@ +/* bnx2x_init.h: Broadcom Everest network driver. + * Structures and macroes needed during the initialization. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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: Eilon Greenstein + * Written by: Eliezer Tamir + * Modified by: Vladislav Zolotarov + */ + +#ifndef BNX2X_INIT_H +#define BNX2X_INIT_H + +/* Init operation types and structures */ +enum { + OP_RD = 0x1, /* read a single register */ + OP_WR, /* write a single register */ + OP_SW, /* copy a string to the device */ + OP_ZR, /* clear memory */ + OP_ZP, /* unzip then copy with DMAE */ + OP_WR_64, /* write 64 bit pattern */ + OP_WB, /* copy a string using DMAE */ + OP_WB_ZR, /* Clear a string using DMAE or indirect-wr */ + /* Skip the following ops if all of the init modes don't match */ + OP_IF_MODE_OR, + /* Skip the following ops if any of the init modes don't match */ + OP_IF_MODE_AND, + OP_MAX +}; + +enum { + STAGE_START, + STAGE_END, +}; + +/* Returns the index of start or end of a specific block stage in ops array*/ +#define BLOCK_OPS_IDX(block, stage, end) \ + (2*(((block)*NUM_OF_INIT_PHASES) + (stage)) + (end)) + + +/* structs for the various opcodes */ +struct raw_op { + u32 op:8; + u32 offset:24; + u32 raw_data; +}; + +struct op_read { + u32 op:8; + u32 offset:24; + u32 val; +}; + +struct op_write { + u32 op:8; + u32 offset:24; + u32 val; +}; + +struct op_arr_write { + u32 op:8; + u32 offset:24; +#ifdef __BIG_ENDIAN + u16 data_len; + u16 data_off; +#else /* __LITTLE_ENDIAN */ + u16 data_off; + u16 data_len; +#endif +}; + +struct op_zero { + u32 op:8; + u32 offset:24; + u32 len; +}; + +struct op_if_mode { + u32 op:8; + u32 cmd_offset:24; + u32 mode_bit_map; +}; + + +union init_op { + struct op_read read; + struct op_write write; + struct op_arr_write arr_wr; + struct op_zero zero; + struct raw_op raw; + struct op_if_mode if_mode; +}; + + +/* Init Phases */ +enum { + PHASE_COMMON, + PHASE_PORT0, + PHASE_PORT1, + PHASE_PF0, + PHASE_PF1, + PHASE_PF2, + PHASE_PF3, + PHASE_PF4, + PHASE_PF5, + PHASE_PF6, + PHASE_PF7, + NUM_OF_INIT_PHASES +}; + +/* Init Modes */ +enum { + MODE_ASIC = 0x00000001, + MODE_FPGA = 0x00000002, + MODE_EMUL = 0x00000004, + MODE_E2 = 0x00000008, + MODE_E3 = 0x00000010, + MODE_PORT2 = 0x00000020, + MODE_PORT4 = 0x00000040, + MODE_SF = 0x00000080, + MODE_MF = 0x00000100, + MODE_MF_SD = 0x00000200, + MODE_MF_SI = 0x00000400, + MODE_MF_NIV = 0x00000800, + MODE_E3_A0 = 0x00001000, + MODE_E3_B0 = 0x00002000, + MODE_COS3 = 0x00004000, + MODE_COS6 = 0x00008000, + MODE_LITTLE_ENDIAN = 0x00010000, + MODE_BIG_ENDIAN = 0x00020000, +}; + +/* Init Blocks */ +enum { + BLOCK_ATC, + BLOCK_BRB1, + BLOCK_CCM, + BLOCK_CDU, + BLOCK_CFC, + BLOCK_CSDM, + BLOCK_CSEM, + BLOCK_DBG, + BLOCK_DMAE, + BLOCK_DORQ, + BLOCK_HC, + BLOCK_IGU, + BLOCK_MISC, + BLOCK_NIG, + BLOCK_PBF, + BLOCK_PGLUE_B, + BLOCK_PRS, + BLOCK_PXP2, + BLOCK_PXP, + BLOCK_QM, + BLOCK_SRC, + BLOCK_TCM, + BLOCK_TM, + BLOCK_TSDM, + BLOCK_TSEM, + BLOCK_UCM, + BLOCK_UPB, + BLOCK_USDM, + BLOCK_USEM, + BLOCK_XCM, + BLOCK_XPB, + BLOCK_XSDM, + BLOCK_XSEM, + BLOCK_MISC_AEU, + NUM_OF_INIT_BLOCKS +}; + +/* QM queue numbers */ +#define BNX2X_ETH_Q 0 +#define BNX2X_TOE_Q 3 +#define BNX2X_TOE_ACK_Q 6 +#define BNX2X_ISCSI_Q 9 +#define BNX2X_ISCSI_ACK_Q 11 +#define BNX2X_FCOE_Q 10 + +/* Vnics per mode */ +#define BNX2X_PORT2_MODE_NUM_VNICS 4 +#define BNX2X_PORT4_MODE_NUM_VNICS 2 + +/* COS offset for port1 in E3 B0 4port mode */ +#define BNX2X_E3B0_PORT1_COS_OFFSET 3 + +/* QM Register addresses */ +#define BNX2X_Q_VOQ_REG_ADDR(pf_q_num)\ + (QM_REG_QVOQIDX_0 + 4 * (pf_q_num)) +#define BNX2X_VOQ_Q_REG_ADDR(cos, pf_q_num)\ + (QM_REG_VOQQMASK_0_LSB + 4 * ((cos) * 2 + ((pf_q_num) >> 5))) +#define BNX2X_Q_CMDQ_REG_ADDR(pf_q_num)\ + (QM_REG_BYTECRDCMDQ_0 + 4 * ((pf_q_num) >> 4)) + +/* extracts the QM queue number for the specified port and vnic */ +#define BNX2X_PF_Q_NUM(q_num, port, vnic)\ + ((((port) << 1) | (vnic)) * 16 + (q_num)) + + +/* Maps the specified queue to the specified COS */ +static inline void bnx2x_map_q_cos(struct bnx2x *bp, u32 q_num, u32 new_cos) +{ + /* find current COS mapping */ + u32 curr_cos = REG_RD(bp, QM_REG_QVOQIDX_0 + q_num * 4); + + /* check if queue->COS mapping has changed */ + if (curr_cos != new_cos) { + u32 num_vnics = BNX2X_PORT2_MODE_NUM_VNICS; + u32 reg_addr, reg_bit_map, vnic; + + /* update parameters for 4port mode */ + if (INIT_MODE_FLAGS(bp) & MODE_PORT4) { + num_vnics = BNX2X_PORT4_MODE_NUM_VNICS; + if (BP_PORT(bp)) { + curr_cos += BNX2X_E3B0_PORT1_COS_OFFSET; + new_cos += BNX2X_E3B0_PORT1_COS_OFFSET; + } + } + + /* change queue mapping for each VNIC */ + for (vnic = 0; vnic < num_vnics; vnic++) { + u32 pf_q_num = + BNX2X_PF_Q_NUM(q_num, BP_PORT(bp), vnic); + u32 q_bit_map = 1 << (pf_q_num & 0x1f); + + /* overwrite queue->VOQ mapping */ + REG_WR(bp, BNX2X_Q_VOQ_REG_ADDR(pf_q_num), new_cos); + + /* clear queue bit from current COS bit map */ + reg_addr = BNX2X_VOQ_Q_REG_ADDR(curr_cos, pf_q_num); + reg_bit_map = REG_RD(bp, reg_addr); + REG_WR(bp, reg_addr, reg_bit_map & (~q_bit_map)); + + /* set queue bit in new COS bit map */ + reg_addr = BNX2X_VOQ_Q_REG_ADDR(new_cos, pf_q_num); + reg_bit_map = REG_RD(bp, reg_addr); + REG_WR(bp, reg_addr, reg_bit_map | q_bit_map); + + /* set/clear queue bit in command-queue bit map + (E2/E3A0 only, valid COS values are 0/1) */ + if (!(INIT_MODE_FLAGS(bp) & MODE_E3_B0)) { + reg_addr = BNX2X_Q_CMDQ_REG_ADDR(pf_q_num); + reg_bit_map = REG_RD(bp, reg_addr); + q_bit_map = 1 << (2 * (pf_q_num & 0xf)); + reg_bit_map = new_cos ? + (reg_bit_map | q_bit_map) : + (reg_bit_map & (~q_bit_map)); + REG_WR(bp, reg_addr, reg_bit_map); + } + } + } +} + +/* Configures the QM according to the specified per-traffic-type COSes */ +static inline void bnx2x_dcb_config_qm(struct bnx2x *bp, enum cos_mode mode, + struct priority_cos *traffic_cos) +{ + bnx2x_map_q_cos(bp, BNX2X_FCOE_Q, + traffic_cos[LLFC_TRAFFIC_TYPE_FCOE].cos); + bnx2x_map_q_cos(bp, BNX2X_ISCSI_Q, + traffic_cos[LLFC_TRAFFIC_TYPE_ISCSI].cos); + bnx2x_map_q_cos(bp, BNX2X_ISCSI_ACK_Q, + traffic_cos[LLFC_TRAFFIC_TYPE_ISCSI].cos); + if (mode != STATIC_COS) { + /* required only in backward compatible COS mode */ + bnx2x_map_q_cos(bp, BNX2X_ETH_Q, + traffic_cos[LLFC_TRAFFIC_TYPE_NW].cos); + bnx2x_map_q_cos(bp, BNX2X_TOE_Q, + traffic_cos[LLFC_TRAFFIC_TYPE_NW].cos); + bnx2x_map_q_cos(bp, BNX2X_TOE_ACK_Q, + traffic_cos[LLFC_TRAFFIC_TYPE_NW].cos); + } +} + + +/* Returns the index of start or end of a specific block stage in ops array*/ +#define BLOCK_OPS_IDX(block, stage, end) \ + (2*(((block)*NUM_OF_INIT_PHASES) + (stage)) + (end)) + + +#define INITOP_SET 0 /* set the HW directly */ +#define INITOP_CLEAR 1 /* clear the HW directly */ +#define INITOP_INIT 2 /* set the init-value array */ + +/**************************************************************************** +* ILT management +****************************************************************************/ +struct ilt_line { + dma_addr_t page_mapping; + void *page; + u32 size; +}; + +struct ilt_client_info { + u32 page_size; + u16 start; + u16 end; + u16 client_num; + u16 flags; +#define ILT_CLIENT_SKIP_INIT 0x1 +#define ILT_CLIENT_SKIP_MEM 0x2 +}; + +struct bnx2x_ilt { + u32 start_line; + struct ilt_line *lines; + struct ilt_client_info clients[4]; +#define ILT_CLIENT_CDU 0 +#define ILT_CLIENT_QM 1 +#define ILT_CLIENT_SRC 2 +#define ILT_CLIENT_TM 3 +}; + +/**************************************************************************** +* SRC configuration +****************************************************************************/ +struct src_ent { + u8 opaque[56]; + u64 next; +}; + +/**************************************************************************** +* Parity configuration +****************************************************************************/ +#define BLOCK_PRTY_INFO(block, en_mask, m1, m1h, m2, m3) \ +{ \ + block##_REG_##block##_PRTY_MASK, \ + block##_REG_##block##_PRTY_STS_CLR, \ + en_mask, {m1, m1h, m2, m3}, #block \ +} + +#define BLOCK_PRTY_INFO_0(block, en_mask, m1, m1h, m2, m3) \ +{ \ + block##_REG_##block##_PRTY_MASK_0, \ + block##_REG_##block##_PRTY_STS_CLR_0, \ + en_mask, {m1, m1h, m2, m3}, #block"_0" \ +} + +#define BLOCK_PRTY_INFO_1(block, en_mask, m1, m1h, m2, m3) \ +{ \ + block##_REG_##block##_PRTY_MASK_1, \ + block##_REG_##block##_PRTY_STS_CLR_1, \ + en_mask, {m1, m1h, m2, m3}, #block"_1" \ +} + +static const struct { + u32 mask_addr; + u32 sts_clr_addr; + u32 en_mask; /* Mask to enable parity attentions */ + struct { + u32 e1; /* 57710 */ + u32 e1h; /* 57711 */ + u32 e2; /* 57712 */ + u32 e3; /* 578xx */ + } reg_mask; /* Register mask (all valid bits) */ + char name[7]; /* Block's longest name is 6 characters long + * (name + suffix) + */ +} bnx2x_blocks_parity_data[] = { + /* bit 19 masked */ + /* REG_WR(bp, PXP_REG_PXP_PRTY_MASK, 0x80000); */ + /* bit 5,18,20-31 */ + /* REG_WR(bp, PXP2_REG_PXP2_PRTY_MASK_0, 0xfff40020); */ + /* bit 5 */ + /* REG_WR(bp, PXP2_REG_PXP2_PRTY_MASK_1, 0x20); */ + /* REG_WR(bp, HC_REG_HC_PRTY_MASK, 0x0); */ + /* REG_WR(bp, MISC_REG_MISC_PRTY_MASK, 0x0); */ + + /* Block IGU, MISC, PXP and PXP2 parity errors as long as we don't + * want to handle "system kill" flow at the moment. + */ + BLOCK_PRTY_INFO(PXP, 0x7ffffff, 0x3ffffff, 0x3ffffff, 0x7ffffff, + 0x7ffffff), + BLOCK_PRTY_INFO_0(PXP2, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff), + BLOCK_PRTY_INFO_1(PXP2, 0x1ffffff, 0x7f, 0x7f, 0x7ff, 0x1ffffff), + BLOCK_PRTY_INFO(HC, 0x7, 0x7, 0x7, 0, 0), + BLOCK_PRTY_INFO(NIG, 0xffffffff, 0x3fffffff, 0xffffffff, 0, 0), + BLOCK_PRTY_INFO_0(NIG, 0xffffffff, 0, 0, 0xffffffff, 0xffffffff), + BLOCK_PRTY_INFO_1(NIG, 0xffff, 0, 0, 0xff, 0xffff), + BLOCK_PRTY_INFO(IGU, 0x7ff, 0, 0, 0x7ff, 0x7ff), + BLOCK_PRTY_INFO(MISC, 0x1, 0x1, 0x1, 0x1, 0x1), + BLOCK_PRTY_INFO(QM, 0, 0x1ff, 0xfff, 0xfff, 0xfff), + BLOCK_PRTY_INFO(ATC, 0x1f, 0, 0, 0x1f, 0x1f), + BLOCK_PRTY_INFO(PGLUE_B, 0x3, 0, 0, 0x3, 0x3), + BLOCK_PRTY_INFO(DORQ, 0, 0x3, 0x3, 0x3, 0x3), + {GRCBASE_UPB + PB_REG_PB_PRTY_MASK, + GRCBASE_UPB + PB_REG_PB_PRTY_STS_CLR, 0xf, + {0xf, 0xf, 0xf, 0xf}, "UPB"}, + {GRCBASE_XPB + PB_REG_PB_PRTY_MASK, + GRCBASE_XPB + PB_REG_PB_PRTY_STS_CLR, 0, + {0xf, 0xf, 0xf, 0xf}, "XPB"}, + BLOCK_PRTY_INFO(SRC, 0x4, 0x7, 0x7, 0x7, 0x7), + BLOCK_PRTY_INFO(CDU, 0, 0x1f, 0x1f, 0x1f, 0x1f), + BLOCK_PRTY_INFO(CFC, 0, 0xf, 0xf, 0xf, 0x3f), + BLOCK_PRTY_INFO(DBG, 0, 0x1, 0x1, 0x1, 0x1), + BLOCK_PRTY_INFO(DMAE, 0, 0xf, 0xf, 0xf, 0xf), + BLOCK_PRTY_INFO(BRB1, 0, 0xf, 0xf, 0xf, 0xf), + BLOCK_PRTY_INFO(PRS, (1<<6), 0xff, 0xff, 0xff, 0xff), + BLOCK_PRTY_INFO(PBF, 0, 0, 0x3ffff, 0xfffff, 0xfffffff), + BLOCK_PRTY_INFO(TM, 0, 0, 0x7f, 0x7f, 0x7f), + BLOCK_PRTY_INFO(TSDM, 0x18, 0x7ff, 0x7ff, 0x7ff, 0x7ff), + BLOCK_PRTY_INFO(CSDM, 0x8, 0x7ff, 0x7ff, 0x7ff, 0x7ff), + BLOCK_PRTY_INFO(USDM, 0x38, 0x7ff, 0x7ff, 0x7ff, 0x7ff), + BLOCK_PRTY_INFO(XSDM, 0x8, 0x7ff, 0x7ff, 0x7ff, 0x7ff), + BLOCK_PRTY_INFO(TCM, 0, 0, 0x7ffffff, 0x7ffffff, 0x7ffffff), + BLOCK_PRTY_INFO(CCM, 0, 0, 0x7ffffff, 0x7ffffff, 0x7ffffff), + BLOCK_PRTY_INFO(UCM, 0, 0, 0x7ffffff, 0x7ffffff, 0x7ffffff), + BLOCK_PRTY_INFO(XCM, 0, 0, 0x3fffffff, 0x3fffffff, 0x3fffffff), + BLOCK_PRTY_INFO_0(TSEM, 0, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff), + BLOCK_PRTY_INFO_1(TSEM, 0, 0x3, 0x1f, 0x3f, 0x3f), + BLOCK_PRTY_INFO_0(USEM, 0, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff), + BLOCK_PRTY_INFO_1(USEM, 0, 0x3, 0x1f, 0x1f, 0x1f), + BLOCK_PRTY_INFO_0(CSEM, 0, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff), + BLOCK_PRTY_INFO_1(CSEM, 0, 0x3, 0x1f, 0x1f, 0x1f), + BLOCK_PRTY_INFO_0(XSEM, 0, 0xffffffff, 0xffffffff, 0xffffffff, + 0xffffffff), + BLOCK_PRTY_INFO_1(XSEM, 0, 0x3, 0x1f, 0x3f, 0x3f), +}; + + +/* [28] MCP Latched rom_parity + * [29] MCP Latched ump_rx_parity + * [30] MCP Latched ump_tx_parity + * [31] MCP Latched scpad_parity + */ +#define MISC_AEU_ENABLE_MCP_PRTY_BITS \ + (AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY | \ + AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY | \ + AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY | \ + AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY) + +/* Below registers control the MCP parity attention output. When + * MISC_AEU_ENABLE_MCP_PRTY_BITS are set - attentions are + * enabled, when cleared - disabled. + */ +static const u32 mcp_attn_ctl_regs[] = { + MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0, + MISC_REG_AEU_ENABLE4_NIG_0, + MISC_REG_AEU_ENABLE4_PXP_0, + MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0, + MISC_REG_AEU_ENABLE4_NIG_1, + MISC_REG_AEU_ENABLE4_PXP_1 +}; + +static inline void bnx2x_set_mcp_parity(struct bnx2x *bp, u8 enable) +{ + int i; + u32 reg_val; + + for (i = 0; i < ARRAY_SIZE(mcp_attn_ctl_regs); i++) { + reg_val = REG_RD(bp, mcp_attn_ctl_regs[i]); + + if (enable) + reg_val |= MISC_AEU_ENABLE_MCP_PRTY_BITS; + else + reg_val &= ~MISC_AEU_ENABLE_MCP_PRTY_BITS; + + REG_WR(bp, mcp_attn_ctl_regs[i], reg_val); + } +} + +static inline u32 bnx2x_parity_reg_mask(struct bnx2x *bp, int idx) +{ + if (CHIP_IS_E1(bp)) + return bnx2x_blocks_parity_data[idx].reg_mask.e1; + else if (CHIP_IS_E1H(bp)) + return bnx2x_blocks_parity_data[idx].reg_mask.e1h; + else if (CHIP_IS_E2(bp)) + return bnx2x_blocks_parity_data[idx].reg_mask.e2; + else /* CHIP_IS_E3 */ + return bnx2x_blocks_parity_data[idx].reg_mask.e3; +} + +static inline void bnx2x_disable_blocks_parity(struct bnx2x *bp) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bnx2x_blocks_parity_data); i++) { + u32 dis_mask = bnx2x_parity_reg_mask(bp, i); + + if (dis_mask) { + REG_WR(bp, bnx2x_blocks_parity_data[i].mask_addr, + dis_mask); + DP(NETIF_MSG_HW, "Setting parity mask " + "for %s to\t\t0x%x\n", + bnx2x_blocks_parity_data[i].name, dis_mask); + } + } + + /* Disable MCP parity attentions */ + bnx2x_set_mcp_parity(bp, false); +} + +/** + * Clear the parity error status registers. + */ +static inline void bnx2x_clear_blocks_parity(struct bnx2x *bp) +{ + int i; + u32 reg_val, mcp_aeu_bits = + AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY | + AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY | + AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY | + AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY; + + /* Clear SEM_FAST parities */ + REG_WR(bp, XSEM_REG_FAST_MEMORY + SEM_FAST_REG_PARITY_RST, 0x1); + REG_WR(bp, TSEM_REG_FAST_MEMORY + SEM_FAST_REG_PARITY_RST, 0x1); + REG_WR(bp, USEM_REG_FAST_MEMORY + SEM_FAST_REG_PARITY_RST, 0x1); + REG_WR(bp, CSEM_REG_FAST_MEMORY + SEM_FAST_REG_PARITY_RST, 0x1); + + for (i = 0; i < ARRAY_SIZE(bnx2x_blocks_parity_data); i++) { + u32 reg_mask = bnx2x_parity_reg_mask(bp, i); + + if (reg_mask) { + reg_val = REG_RD(bp, bnx2x_blocks_parity_data[i]. + sts_clr_addr); + if (reg_val & reg_mask) + DP(NETIF_MSG_HW, + "Parity errors in %s: 0x%x\n", + bnx2x_blocks_parity_data[i].name, + reg_val & reg_mask); + } + } + + /* Check if there were parity attentions in MCP */ + reg_val = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_MCP); + if (reg_val & mcp_aeu_bits) + DP(NETIF_MSG_HW, "Parity error in MCP: 0x%x\n", + reg_val & mcp_aeu_bits); + + /* Clear parity attentions in MCP: + * [7] clears Latched rom_parity + * [8] clears Latched ump_rx_parity + * [9] clears Latched ump_tx_parity + * [10] clears Latched scpad_parity (both ports) + */ + REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x780); +} + +static inline void bnx2x_enable_blocks_parity(struct bnx2x *bp) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(bnx2x_blocks_parity_data); i++) { + u32 reg_mask = bnx2x_parity_reg_mask(bp, i); + + if (reg_mask) + REG_WR(bp, bnx2x_blocks_parity_data[i].mask_addr, + bnx2x_blocks_parity_data[i].en_mask & reg_mask); + } + + /* Enable MCP parity attentions */ + bnx2x_set_mcp_parity(bp, true); +} + + +#endif /* BNX2X_INIT_H */ + diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h new file mode 100644 index 000000000000..7ec1724753ad --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h @@ -0,0 +1,912 @@ +/* bnx2x_init_ops.h: Broadcom Everest network driver. + * Static functions needed during the initialization. + * This file is "included" in bnx2x_main.c. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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: Eilon Greenstein + * Written by: Vladislav Zolotarov + */ + +#ifndef BNX2X_INIT_OPS_H +#define BNX2X_INIT_OPS_H + + +#ifndef BP_ILT +#define BP_ILT(bp) NULL +#endif + +#ifndef BP_FUNC +#define BP_FUNC(bp) 0 +#endif + +#ifndef BP_PORT +#define BP_PORT(bp) 0 +#endif + +#ifndef BNX2X_ILT_FREE +#define BNX2X_ILT_FREE(x, y, sz) +#endif + +#ifndef BNX2X_ILT_ZALLOC +#define BNX2X_ILT_ZALLOC(x, y, sz) +#endif + +#ifndef ILOG2 +#define ILOG2(x) x +#endif + +static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len); +static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val); +static void bnx2x_write_dmae_phys_len(struct bnx2x *bp, + dma_addr_t phys_addr, u32 addr, + u32 len); + +static void bnx2x_init_str_wr(struct bnx2x *bp, u32 addr, + const u32 *data, u32 len) +{ + u32 i; + + for (i = 0; i < len; i++) + REG_WR(bp, addr + i*4, data[i]); +} + +static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, + const u32 *data, u32 len) +{ + u32 i; + + for (i = 0; i < len; i++) + bnx2x_reg_wr_ind(bp, addr + i*4, data[i]); +} + +static void bnx2x_write_big_buf(struct bnx2x *bp, u32 addr, u32 len, + u8 wb) +{ + if (bp->dmae_ready) + bnx2x_write_dmae_phys_len(bp, GUNZIP_PHYS(bp), addr, len); + else if (wb) + /* + * Wide bus registers with no dmae need to be written + * using indirect write. + */ + bnx2x_init_ind_wr(bp, addr, GUNZIP_BUF(bp), len); + else + bnx2x_init_str_wr(bp, addr, GUNZIP_BUF(bp), len); +} + +static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, + u32 len, u8 wb) +{ + u32 buf_len = (((len*4) > FW_BUF_SIZE) ? FW_BUF_SIZE : (len*4)); + u32 buf_len32 = buf_len/4; + u32 i; + + memset(GUNZIP_BUF(bp), (u8)fill, buf_len); + + for (i = 0; i < len; i += buf_len32) { + u32 cur_len = min(buf_len32, len - i); + + bnx2x_write_big_buf(bp, addr + i*4, cur_len, wb); + } +} + +static void bnx2x_write_big_buf_wb(struct bnx2x *bp, u32 addr, u32 len) +{ + if (bp->dmae_ready) + bnx2x_write_dmae_phys_len(bp, GUNZIP_PHYS(bp), addr, len); + else + bnx2x_init_ind_wr(bp, addr, GUNZIP_BUF(bp), len); +} + +static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, + const u32 *data, u32 len64) +{ + u32 buf_len32 = FW_BUF_SIZE/4; + u32 len = len64*2; + u64 data64 = 0; + u32 i; + + /* 64 bit value is in a blob: first low DWORD, then high DWORD */ + data64 = HILO_U64((*(data + 1)), (*data)); + + len64 = min((u32)(FW_BUF_SIZE/8), len64); + for (i = 0; i < len64; i++) { + u64 *pdata = ((u64 *)(GUNZIP_BUF(bp))) + i; + + *pdata = data64; + } + + for (i = 0; i < len; i += buf_len32) { + u32 cur_len = min(buf_len32, len - i); + + bnx2x_write_big_buf_wb(bp, addr + i*4, cur_len); + } +} + +/********************************************************* + There are different blobs for each PRAM section. + In addition, each blob write operation is divided into a few operations + in order to decrease the amount of phys. contiguous buffer needed. + Thus, when we select a blob the address may be with some offset + from the beginning of PRAM section. + The same holds for the INT_TABLE sections. +**********************************************************/ +#define IF_IS_INT_TABLE_ADDR(base, addr) \ + if (((base) <= (addr)) && ((base) + 0x400 >= (addr))) + +#define IF_IS_PRAM_ADDR(base, addr) \ + if (((base) <= (addr)) && ((base) + 0x40000 >= (addr))) + +static const u8 *bnx2x_sel_blob(struct bnx2x *bp, u32 addr, + const u8 *data) +{ + IF_IS_INT_TABLE_ADDR(TSEM_REG_INT_TABLE, addr) + data = INIT_TSEM_INT_TABLE_DATA(bp); + else + IF_IS_INT_TABLE_ADDR(CSEM_REG_INT_TABLE, addr) + data = INIT_CSEM_INT_TABLE_DATA(bp); + else + IF_IS_INT_TABLE_ADDR(USEM_REG_INT_TABLE, addr) + data = INIT_USEM_INT_TABLE_DATA(bp); + else + IF_IS_INT_TABLE_ADDR(XSEM_REG_INT_TABLE, addr) + data = INIT_XSEM_INT_TABLE_DATA(bp); + else + IF_IS_PRAM_ADDR(TSEM_REG_PRAM, addr) + data = INIT_TSEM_PRAM_DATA(bp); + else + IF_IS_PRAM_ADDR(CSEM_REG_PRAM, addr) + data = INIT_CSEM_PRAM_DATA(bp); + else + IF_IS_PRAM_ADDR(USEM_REG_PRAM, addr) + data = INIT_USEM_PRAM_DATA(bp); + else + IF_IS_PRAM_ADDR(XSEM_REG_PRAM, addr) + data = INIT_XSEM_PRAM_DATA(bp); + + return data; +} + +static void bnx2x_init_wr_wb(struct bnx2x *bp, u32 addr, + const u32 *data, u32 len) +{ + if (bp->dmae_ready) + VIRT_WR_DMAE_LEN(bp, data, addr, len, 0); + else + bnx2x_init_ind_wr(bp, addr, data, len); +} + +static void bnx2x_wr_64(struct bnx2x *bp, u32 reg, u32 val_lo, + u32 val_hi) +{ + u32 wb_write[2]; + + wb_write[0] = val_lo; + wb_write[1] = val_hi; + REG_WR_DMAE_LEN(bp, reg, wb_write, 2); +} +static void bnx2x_init_wr_zp(struct bnx2x *bp, u32 addr, u32 len, + u32 blob_off) +{ + const u8 *data = NULL; + int rc; + u32 i; + + data = bnx2x_sel_blob(bp, addr, data) + blob_off*4; + + rc = bnx2x_gunzip(bp, data, len); + if (rc) + return; + + /* gunzip_outlen is in dwords */ + len = GUNZIP_OUTLEN(bp); + for (i = 0; i < len; i++) + ((u32 *)GUNZIP_BUF(bp))[i] = + cpu_to_le32(((u32 *)GUNZIP_BUF(bp))[i]); + + bnx2x_write_big_buf_wb(bp, addr, len); +} + +static void bnx2x_init_block(struct bnx2x *bp, u32 block, u32 stage) +{ + u16 op_start = + INIT_OPS_OFFSETS(bp)[BLOCK_OPS_IDX(block, stage, + STAGE_START)]; + u16 op_end = + INIT_OPS_OFFSETS(bp)[BLOCK_OPS_IDX(block, stage, + STAGE_END)]; + union init_op *op; + u32 op_idx, op_type, addr, len; + const u32 *data, *data_base; + + /* If empty block */ + if (op_start == op_end) + return; + + data_base = INIT_DATA(bp); + + for (op_idx = op_start; op_idx < op_end; op_idx++) { + + op = (union init_op *)&(INIT_OPS(bp)[op_idx]); + /* Get generic data */ + op_type = op->raw.op; + addr = op->raw.offset; + /* Get data that's used for OP_SW, OP_WB, OP_FW, OP_ZP and + * OP_WR64 (we assume that op_arr_write and op_write have the + * same structure). + */ + len = op->arr_wr.data_len; + data = data_base + op->arr_wr.data_off; + + switch (op_type) { + case OP_RD: + REG_RD(bp, addr); + break; + case OP_WR: + REG_WR(bp, addr, op->write.val); + break; + case OP_SW: + bnx2x_init_str_wr(bp, addr, data, len); + break; + case OP_WB: + bnx2x_init_wr_wb(bp, addr, data, len); + break; + case OP_ZR: + bnx2x_init_fill(bp, addr, 0, op->zero.len, 0); + break; + case OP_WB_ZR: + bnx2x_init_fill(bp, addr, 0, op->zero.len, 1); + break; + case OP_ZP: + bnx2x_init_wr_zp(bp, addr, len, + op->arr_wr.data_off); + break; + case OP_WR_64: + bnx2x_init_wr_64(bp, addr, data, len); + break; + case OP_IF_MODE_AND: + /* if any of the flags doesn't match, skip the + * conditional block. + */ + if ((INIT_MODE_FLAGS(bp) & + op->if_mode.mode_bit_map) != + op->if_mode.mode_bit_map) + op_idx += op->if_mode.cmd_offset; + break; + case OP_IF_MODE_OR: + /* if all the flags don't match, skip the conditional + * block. + */ + if ((INIT_MODE_FLAGS(bp) & + op->if_mode.mode_bit_map) == 0) + op_idx += op->if_mode.cmd_offset; + break; + default: + /* Should never get here! */ + + break; + } + } +} + + +/**************************************************************************** +* PXP Arbiter +****************************************************************************/ +/* + * This code configures the PCI read/write arbiter + * which implements a weighted round robin + * between the virtual queues in the chip. + * + * The values were derived for each PCI max payload and max request size. + * since max payload and max request size are only known at run time, + * this is done as a separate init stage. + */ + +#define NUM_WR_Q 13 +#define NUM_RD_Q 29 +#define MAX_RD_ORD 3 +#define MAX_WR_ORD 2 + +/* configuration for one arbiter queue */ +struct arb_line { + int l; + int add; + int ubound; +}; + +/* derived configuration for each read queue for each max request size */ +static const struct arb_line read_arb_data[NUM_RD_Q][MAX_RD_ORD + 1] = { +/* 1 */ { {8, 64, 25}, {16, 64, 25}, {32, 64, 25}, {64, 64, 41} }, + { {4, 8, 4}, {4, 8, 4}, {4, 8, 4}, {4, 8, 4} }, + { {4, 3, 3}, {4, 3, 3}, {4, 3, 3}, {4, 3, 3} }, + { {8, 3, 6}, {16, 3, 11}, {16, 3, 11}, {16, 3, 11} }, + { {8, 64, 25}, {16, 64, 25}, {32, 64, 25}, {64, 64, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {64, 3, 41} }, +/* 10 */{ {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 64, 6}, {16, 64, 11}, {32, 64, 21}, {32, 64, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, +/* 20 */{ {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 3, 6}, {16, 3, 11}, {32, 3, 21}, {32, 3, 21} }, + { {8, 64, 25}, {16, 64, 41}, {32, 64, 81}, {64, 64, 120} } +}; + +/* derived configuration for each write queue for each max request size */ +static const struct arb_line write_arb_data[NUM_WR_Q][MAX_WR_ORD + 1] = { +/* 1 */ { {4, 6, 3}, {4, 6, 3}, {4, 6, 3} }, + { {4, 2, 3}, {4, 2, 3}, {4, 2, 3} }, + { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, + { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, + { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, + { {8, 2, 6}, {16, 2, 11}, {32, 2, 21} }, + { {8, 64, 25}, {16, 64, 25}, {32, 64, 25} }, + { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, + { {8, 2, 6}, {16, 2, 11}, {16, 2, 11} }, +/* 10 */{ {8, 9, 6}, {16, 9, 11}, {32, 9, 21} }, + { {8, 47, 19}, {16, 47, 19}, {32, 47, 21} }, + { {8, 9, 6}, {16, 9, 11}, {16, 9, 11} }, + { {8, 64, 25}, {16, 64, 41}, {32, 64, 81} } +}; + +/* register addresses for read queues */ +static const struct arb_line read_arb_addr[NUM_RD_Q-1] = { +/* 1 */ {PXP2_REG_RQ_BW_RD_L0, PXP2_REG_RQ_BW_RD_ADD0, + PXP2_REG_RQ_BW_RD_UBOUND0}, + {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, + PXP2_REG_PSWRQ_BW_UB1}, + {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, + PXP2_REG_PSWRQ_BW_UB2}, + {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, + PXP2_REG_PSWRQ_BW_UB3}, + {PXP2_REG_RQ_BW_RD_L4, PXP2_REG_RQ_BW_RD_ADD4, + PXP2_REG_RQ_BW_RD_UBOUND4}, + {PXP2_REG_RQ_BW_RD_L5, PXP2_REG_RQ_BW_RD_ADD5, + PXP2_REG_RQ_BW_RD_UBOUND5}, + {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, + PXP2_REG_PSWRQ_BW_UB6}, + {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, + PXP2_REG_PSWRQ_BW_UB7}, + {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, + PXP2_REG_PSWRQ_BW_UB8}, +/* 10 */{PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, + PXP2_REG_PSWRQ_BW_UB9}, + {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, + PXP2_REG_PSWRQ_BW_UB10}, + {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, + PXP2_REG_PSWRQ_BW_UB11}, + {PXP2_REG_RQ_BW_RD_L12, PXP2_REG_RQ_BW_RD_ADD12, + PXP2_REG_RQ_BW_RD_UBOUND12}, + {PXP2_REG_RQ_BW_RD_L13, PXP2_REG_RQ_BW_RD_ADD13, + PXP2_REG_RQ_BW_RD_UBOUND13}, + {PXP2_REG_RQ_BW_RD_L14, PXP2_REG_RQ_BW_RD_ADD14, + PXP2_REG_RQ_BW_RD_UBOUND14}, + {PXP2_REG_RQ_BW_RD_L15, PXP2_REG_RQ_BW_RD_ADD15, + PXP2_REG_RQ_BW_RD_UBOUND15}, + {PXP2_REG_RQ_BW_RD_L16, PXP2_REG_RQ_BW_RD_ADD16, + PXP2_REG_RQ_BW_RD_UBOUND16}, + {PXP2_REG_RQ_BW_RD_L17, PXP2_REG_RQ_BW_RD_ADD17, + PXP2_REG_RQ_BW_RD_UBOUND17}, + {PXP2_REG_RQ_BW_RD_L18, PXP2_REG_RQ_BW_RD_ADD18, + PXP2_REG_RQ_BW_RD_UBOUND18}, +/* 20 */{PXP2_REG_RQ_BW_RD_L19, PXP2_REG_RQ_BW_RD_ADD19, + PXP2_REG_RQ_BW_RD_UBOUND19}, + {PXP2_REG_RQ_BW_RD_L20, PXP2_REG_RQ_BW_RD_ADD20, + PXP2_REG_RQ_BW_RD_UBOUND20}, + {PXP2_REG_RQ_BW_RD_L22, PXP2_REG_RQ_BW_RD_ADD22, + PXP2_REG_RQ_BW_RD_UBOUND22}, + {PXP2_REG_RQ_BW_RD_L23, PXP2_REG_RQ_BW_RD_ADD23, + PXP2_REG_RQ_BW_RD_UBOUND23}, + {PXP2_REG_RQ_BW_RD_L24, PXP2_REG_RQ_BW_RD_ADD24, + PXP2_REG_RQ_BW_RD_UBOUND24}, + {PXP2_REG_RQ_BW_RD_L25, PXP2_REG_RQ_BW_RD_ADD25, + PXP2_REG_RQ_BW_RD_UBOUND25}, + {PXP2_REG_RQ_BW_RD_L26, PXP2_REG_RQ_BW_RD_ADD26, + PXP2_REG_RQ_BW_RD_UBOUND26}, + {PXP2_REG_RQ_BW_RD_L27, PXP2_REG_RQ_BW_RD_ADD27, + PXP2_REG_RQ_BW_RD_UBOUND27}, + {PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, + PXP2_REG_PSWRQ_BW_UB28} +}; + +/* register addresses for write queues */ +static const struct arb_line write_arb_addr[NUM_WR_Q-1] = { +/* 1 */ {PXP2_REG_PSWRQ_BW_L1, PXP2_REG_PSWRQ_BW_ADD1, + PXP2_REG_PSWRQ_BW_UB1}, + {PXP2_REG_PSWRQ_BW_L2, PXP2_REG_PSWRQ_BW_ADD2, + PXP2_REG_PSWRQ_BW_UB2}, + {PXP2_REG_PSWRQ_BW_L3, PXP2_REG_PSWRQ_BW_ADD3, + PXP2_REG_PSWRQ_BW_UB3}, + {PXP2_REG_PSWRQ_BW_L6, PXP2_REG_PSWRQ_BW_ADD6, + PXP2_REG_PSWRQ_BW_UB6}, + {PXP2_REG_PSWRQ_BW_L7, PXP2_REG_PSWRQ_BW_ADD7, + PXP2_REG_PSWRQ_BW_UB7}, + {PXP2_REG_PSWRQ_BW_L8, PXP2_REG_PSWRQ_BW_ADD8, + PXP2_REG_PSWRQ_BW_UB8}, + {PXP2_REG_PSWRQ_BW_L9, PXP2_REG_PSWRQ_BW_ADD9, + PXP2_REG_PSWRQ_BW_UB9}, + {PXP2_REG_PSWRQ_BW_L10, PXP2_REG_PSWRQ_BW_ADD10, + PXP2_REG_PSWRQ_BW_UB10}, + {PXP2_REG_PSWRQ_BW_L11, PXP2_REG_PSWRQ_BW_ADD11, + PXP2_REG_PSWRQ_BW_UB11}, +/* 10 */{PXP2_REG_PSWRQ_BW_L28, PXP2_REG_PSWRQ_BW_ADD28, + PXP2_REG_PSWRQ_BW_UB28}, + {PXP2_REG_RQ_BW_WR_L29, PXP2_REG_RQ_BW_WR_ADD29, + PXP2_REG_RQ_BW_WR_UBOUND29}, + {PXP2_REG_RQ_BW_WR_L30, PXP2_REG_RQ_BW_WR_ADD30, + PXP2_REG_RQ_BW_WR_UBOUND30} +}; + +static void bnx2x_init_pxp_arb(struct bnx2x *bp, int r_order, + int w_order) +{ + u32 val, i; + + if (r_order > MAX_RD_ORD) { + DP(NETIF_MSG_HW, "read order of %d order adjusted to %d\n", + r_order, MAX_RD_ORD); + r_order = MAX_RD_ORD; + } + if (w_order > MAX_WR_ORD) { + DP(NETIF_MSG_HW, "write order of %d order adjusted to %d\n", + w_order, MAX_WR_ORD); + w_order = MAX_WR_ORD; + } + if (CHIP_REV_IS_FPGA(bp)) { + DP(NETIF_MSG_HW, "write order adjusted to 1 for FPGA\n"); + w_order = 0; + } + DP(NETIF_MSG_HW, "read order %d write order %d\n", r_order, w_order); + + for (i = 0; i < NUM_RD_Q-1; i++) { + REG_WR(bp, read_arb_addr[i].l, read_arb_data[i][r_order].l); + REG_WR(bp, read_arb_addr[i].add, + read_arb_data[i][r_order].add); + REG_WR(bp, read_arb_addr[i].ubound, + read_arb_data[i][r_order].ubound); + } + + for (i = 0; i < NUM_WR_Q-1; i++) { + if ((write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L29) || + (write_arb_addr[i].l == PXP2_REG_RQ_BW_WR_L30)) { + + REG_WR(bp, write_arb_addr[i].l, + write_arb_data[i][w_order].l); + + REG_WR(bp, write_arb_addr[i].add, + write_arb_data[i][w_order].add); + + REG_WR(bp, write_arb_addr[i].ubound, + write_arb_data[i][w_order].ubound); + } else { + + val = REG_RD(bp, write_arb_addr[i].l); + REG_WR(bp, write_arb_addr[i].l, + val | (write_arb_data[i][w_order].l << 10)); + + val = REG_RD(bp, write_arb_addr[i].add); + REG_WR(bp, write_arb_addr[i].add, + val | (write_arb_data[i][w_order].add << 10)); + + val = REG_RD(bp, write_arb_addr[i].ubound); + REG_WR(bp, write_arb_addr[i].ubound, + val | (write_arb_data[i][w_order].ubound << 7)); + } + } + + val = write_arb_data[NUM_WR_Q-1][w_order].add; + val += write_arb_data[NUM_WR_Q-1][w_order].ubound << 10; + val += write_arb_data[NUM_WR_Q-1][w_order].l << 17; + REG_WR(bp, PXP2_REG_PSWRQ_BW_RD, val); + + val = read_arb_data[NUM_RD_Q-1][r_order].add; + val += read_arb_data[NUM_RD_Q-1][r_order].ubound << 10; + val += read_arb_data[NUM_RD_Q-1][r_order].l << 17; + REG_WR(bp, PXP2_REG_PSWRQ_BW_WR, val); + + REG_WR(bp, PXP2_REG_RQ_WR_MBS0, w_order); + REG_WR(bp, PXP2_REG_RQ_WR_MBS1, w_order); + REG_WR(bp, PXP2_REG_RQ_RD_MBS0, r_order); + REG_WR(bp, PXP2_REG_RQ_RD_MBS1, r_order); + + if ((CHIP_IS_E1(bp) || CHIP_IS_E1H(bp)) && (r_order == MAX_RD_ORD)) + REG_WR(bp, PXP2_REG_RQ_PDR_LIMIT, 0xe00); + + if (CHIP_IS_E3(bp)) + REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x4 << w_order)); + else if (CHIP_IS_E2(bp)) + REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x8 << w_order)); + else + REG_WR(bp, PXP2_REG_WR_USDMDP_TH, (0x18 << w_order)); + + if (!CHIP_IS_E1(bp)) { + /* MPS w_order optimal TH presently TH + * 128 0 0 2 + * 256 1 1 3 + * >=512 2 2 3 + */ + /* DMAE is special */ + if (!CHIP_IS_E1H(bp)) { + /* E2 can use optimal TH */ + val = w_order; + REG_WR(bp, PXP2_REG_WR_DMAE_MPS, val); + } else { + val = ((w_order == 0) ? 2 : 3); + REG_WR(bp, PXP2_REG_WR_DMAE_MPS, 2); + } + + REG_WR(bp, PXP2_REG_WR_HC_MPS, val); + REG_WR(bp, PXP2_REG_WR_USDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_CSDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_TSDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_XSDM_MPS, val); + REG_WR(bp, PXP2_REG_WR_QM_MPS, val); + REG_WR(bp, PXP2_REG_WR_TM_MPS, val); + REG_WR(bp, PXP2_REG_WR_SRC_MPS, val); + REG_WR(bp, PXP2_REG_WR_DBG_MPS, val); + REG_WR(bp, PXP2_REG_WR_CDU_MPS, val); + } + + /* Validate number of tags suppoted by device */ +#define PCIE_REG_PCIER_TL_HDR_FC_ST 0x2980 + val = REG_RD(bp, PCIE_REG_PCIER_TL_HDR_FC_ST); + val &= 0xFF; + if (val <= 0x20) + REG_WR(bp, PXP2_REG_PGL_TAGS_LIMIT, 0x20); +} + +/**************************************************************************** +* ILT management +****************************************************************************/ +/* + * This codes hides the low level HW interaction for ILT management and + * configuration. The API consists of a shadow ILT table which is set by the + * driver and a set of routines to use it to configure the HW. + * + */ + +/* ILT HW init operations */ + +/* ILT memory management operations */ +#define ILT_MEMOP_ALLOC 0 +#define ILT_MEMOP_FREE 1 + +/* the phys address is shifted right 12 bits and has an added + * 1=valid bit added to the 53rd bit + * then since this is a wide register(TM) + * we split it into two 32 bit writes + */ +#define ILT_ADDR1(x) ((u32)(((u64)x >> 12) & 0xFFFFFFFF)) +#define ILT_ADDR2(x) ((u32)((1 << 20) | ((u64)x >> 44))) +#define ILT_RANGE(f, l) (((l) << 10) | f) + +static int bnx2x_ilt_line_mem_op(struct bnx2x *bp, + struct ilt_line *line, u32 size, u8 memop) +{ + if (memop == ILT_MEMOP_FREE) { + BNX2X_ILT_FREE(line->page, line->page_mapping, line->size); + return 0; + } + BNX2X_ILT_ZALLOC(line->page, &line->page_mapping, size); + if (!line->page) + return -1; + line->size = size; + return 0; +} + + +static int bnx2x_ilt_client_mem_op(struct bnx2x *bp, int cli_num, + u8 memop) +{ + int i, rc; + struct bnx2x_ilt *ilt = BP_ILT(bp); + struct ilt_client_info *ilt_cli = &ilt->clients[cli_num]; + + if (!ilt || !ilt->lines) + return -1; + + if (ilt_cli->flags & (ILT_CLIENT_SKIP_INIT | ILT_CLIENT_SKIP_MEM)) + return 0; + + for (rc = 0, i = ilt_cli->start; i <= ilt_cli->end && !rc; i++) { + rc = bnx2x_ilt_line_mem_op(bp, &ilt->lines[i], + ilt_cli->page_size, memop); + } + return rc; +} + +static int bnx2x_ilt_mem_op(struct bnx2x *bp, u8 memop) +{ + int rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_CDU, memop); + if (!rc) + rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_QM, memop); + if (!rc) + rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_SRC, memop); + if (!rc) + rc = bnx2x_ilt_client_mem_op(bp, ILT_CLIENT_TM, memop); + + return rc; +} + +static void bnx2x_ilt_line_wr(struct bnx2x *bp, int abs_idx, + dma_addr_t page_mapping) +{ + u32 reg; + + if (CHIP_IS_E1(bp)) + reg = PXP2_REG_RQ_ONCHIP_AT + abs_idx*8; + else + reg = PXP2_REG_RQ_ONCHIP_AT_B0 + abs_idx*8; + + bnx2x_wr_64(bp, reg, ILT_ADDR1(page_mapping), ILT_ADDR2(page_mapping)); +} + +static void bnx2x_ilt_line_init_op(struct bnx2x *bp, + struct bnx2x_ilt *ilt, int idx, u8 initop) +{ + dma_addr_t null_mapping; + int abs_idx = ilt->start_line + idx; + + + switch (initop) { + case INITOP_INIT: + /* set in the init-value array */ + case INITOP_SET: + bnx2x_ilt_line_wr(bp, abs_idx, ilt->lines[idx].page_mapping); + break; + case INITOP_CLEAR: + null_mapping = 0; + bnx2x_ilt_line_wr(bp, abs_idx, null_mapping); + break; + } +} + +static void bnx2x_ilt_boundry_init_op(struct bnx2x *bp, + struct ilt_client_info *ilt_cli, + u32 ilt_start, u8 initop) +{ + u32 start_reg = 0; + u32 end_reg = 0; + + /* The boundary is either SET or INIT, + CLEAR => SET and for now SET ~~ INIT */ + + /* find the appropriate regs */ + if (CHIP_IS_E1(bp)) { + switch (ilt_cli->client_num) { + case ILT_CLIENT_CDU: + start_reg = PXP2_REG_PSWRQ_CDU0_L2P; + break; + case ILT_CLIENT_QM: + start_reg = PXP2_REG_PSWRQ_QM0_L2P; + break; + case ILT_CLIENT_SRC: + start_reg = PXP2_REG_PSWRQ_SRC0_L2P; + break; + case ILT_CLIENT_TM: + start_reg = PXP2_REG_PSWRQ_TM0_L2P; + break; + } + REG_WR(bp, start_reg + BP_FUNC(bp)*4, + ILT_RANGE((ilt_start + ilt_cli->start), + (ilt_start + ilt_cli->end))); + } else { + switch (ilt_cli->client_num) { + case ILT_CLIENT_CDU: + start_reg = PXP2_REG_RQ_CDU_FIRST_ILT; + end_reg = PXP2_REG_RQ_CDU_LAST_ILT; + break; + case ILT_CLIENT_QM: + start_reg = PXP2_REG_RQ_QM_FIRST_ILT; + end_reg = PXP2_REG_RQ_QM_LAST_ILT; + break; + case ILT_CLIENT_SRC: + start_reg = PXP2_REG_RQ_SRC_FIRST_ILT; + end_reg = PXP2_REG_RQ_SRC_LAST_ILT; + break; + case ILT_CLIENT_TM: + start_reg = PXP2_REG_RQ_TM_FIRST_ILT; + end_reg = PXP2_REG_RQ_TM_LAST_ILT; + break; + } + REG_WR(bp, start_reg, (ilt_start + ilt_cli->start)); + REG_WR(bp, end_reg, (ilt_start + ilt_cli->end)); + } +} + +static void bnx2x_ilt_client_init_op_ilt(struct bnx2x *bp, + struct bnx2x_ilt *ilt, + struct ilt_client_info *ilt_cli, + u8 initop) +{ + int i; + + if (ilt_cli->flags & ILT_CLIENT_SKIP_INIT) + return; + + for (i = ilt_cli->start; i <= ilt_cli->end; i++) + bnx2x_ilt_line_init_op(bp, ilt, i, initop); + + /* init/clear the ILT boundries */ + bnx2x_ilt_boundry_init_op(bp, ilt_cli, ilt->start_line, initop); +} + +static void bnx2x_ilt_client_init_op(struct bnx2x *bp, + struct ilt_client_info *ilt_cli, u8 initop) +{ + struct bnx2x_ilt *ilt = BP_ILT(bp); + + bnx2x_ilt_client_init_op_ilt(bp, ilt, ilt_cli, initop); +} + +static void bnx2x_ilt_client_id_init_op(struct bnx2x *bp, + int cli_num, u8 initop) +{ + struct bnx2x_ilt *ilt = BP_ILT(bp); + struct ilt_client_info *ilt_cli = &ilt->clients[cli_num]; + + bnx2x_ilt_client_init_op(bp, ilt_cli, initop); +} + +static void bnx2x_ilt_init_op(struct bnx2x *bp, u8 initop) +{ + bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_CDU, initop); + bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_QM, initop); + bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_SRC, initop); + bnx2x_ilt_client_id_init_op(bp, ILT_CLIENT_TM, initop); +} + +static void bnx2x_ilt_init_client_psz(struct bnx2x *bp, int cli_num, + u32 psz_reg, u8 initop) +{ + struct bnx2x_ilt *ilt = BP_ILT(bp); + struct ilt_client_info *ilt_cli = &ilt->clients[cli_num]; + + if (ilt_cli->flags & ILT_CLIENT_SKIP_INIT) + return; + + switch (initop) { + case INITOP_INIT: + /* set in the init-value array */ + case INITOP_SET: + REG_WR(bp, psz_reg, ILOG2(ilt_cli->page_size >> 12)); + break; + case INITOP_CLEAR: + break; + } +} + +/* + * called during init common stage, ilt clients should be initialized + * prioir to calling this function + */ +static void bnx2x_ilt_init_page_size(struct bnx2x *bp, u8 initop) +{ + bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_CDU, + PXP2_REG_RQ_CDU_P_SIZE, initop); + bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_QM, + PXP2_REG_RQ_QM_P_SIZE, initop); + bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_SRC, + PXP2_REG_RQ_SRC_P_SIZE, initop); + bnx2x_ilt_init_client_psz(bp, ILT_CLIENT_TM, + PXP2_REG_RQ_TM_P_SIZE, initop); +} + +/**************************************************************************** +* QM initializations +****************************************************************************/ +#define QM_QUEUES_PER_FUNC 16 /* E1 has 32, but only 16 are used */ +#define QM_INIT_MIN_CID_COUNT 31 +#define QM_INIT(cid_cnt) (cid_cnt > QM_INIT_MIN_CID_COUNT) + +/* called during init port stage */ +static void bnx2x_qm_init_cid_count(struct bnx2x *bp, int qm_cid_count, + u8 initop) +{ + int port = BP_PORT(bp); + + if (QM_INIT(qm_cid_count)) { + switch (initop) { + case INITOP_INIT: + /* set in the init-value array */ + case INITOP_SET: + REG_WR(bp, QM_REG_CONNNUM_0 + port*4, + qm_cid_count/16 - 1); + break; + case INITOP_CLEAR: + break; + } + } +} + +static void bnx2x_qm_set_ptr_table(struct bnx2x *bp, int qm_cid_count) +{ + int i; + u32 wb_data[2]; + + wb_data[0] = wb_data[1] = 0; + + for (i = 0; i < 4 * QM_QUEUES_PER_FUNC; i++) { + REG_WR(bp, QM_REG_BASEADDR + i*4, + qm_cid_count * 4 * (i % QM_QUEUES_PER_FUNC)); + bnx2x_init_ind_wr(bp, QM_REG_PTRTBL + i*8, + wb_data, 2); + + if (CHIP_IS_E1H(bp)) { + REG_WR(bp, QM_REG_BASEADDR_EXT_A + i*4, + qm_cid_count * 4 * (i % QM_QUEUES_PER_FUNC)); + bnx2x_init_ind_wr(bp, QM_REG_PTRTBL_EXT_A + i*8, + wb_data, 2); + } + } +} + +/* called during init common stage */ +static void bnx2x_qm_init_ptr_table(struct bnx2x *bp, int qm_cid_count, + u8 initop) +{ + if (!QM_INIT(qm_cid_count)) + return; + + switch (initop) { + case INITOP_INIT: + /* set in the init-value array */ + case INITOP_SET: + bnx2x_qm_set_ptr_table(bp, qm_cid_count); + break; + case INITOP_CLEAR: + break; + } +} + +/**************************************************************************** +* SRC initializations +****************************************************************************/ +#ifdef BCM_CNIC +/* called during init func stage */ +static void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2, + dma_addr_t t2_mapping, int src_cid_count) +{ + int i; + int port = BP_PORT(bp); + + /* Initialize T2 */ + for (i = 0; i < src_cid_count-1; i++) + t2[i].next = (u64)(t2_mapping + + (i+1)*sizeof(struct src_ent)); + + /* tell the searcher where the T2 table is */ + REG_WR(bp, SRC_REG_COUNTFREE0 + port*4, src_cid_count); + + bnx2x_wr_64(bp, SRC_REG_FIRSTFREE0 + port*16, + U64_LO(t2_mapping), U64_HI(t2_mapping)); + + bnx2x_wr_64(bp, SRC_REG_LASTFREE0 + port*16, + U64_LO((u64)t2_mapping + + (src_cid_count-1) * sizeof(struct src_ent)), + U64_HI((u64)t2_mapping + + (src_cid_count-1) * sizeof(struct src_ent))); +} +#endif +#endif /* BNX2X_INIT_OPS_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c new file mode 100644 index 000000000000..d45b1555a602 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -0,0 +1,12472 @@ +/* Copyright 2008-2011 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + * + * Written by Yaniv Rosner + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "bnx2x.h" +#include "bnx2x_cmn.h" + + +/********************************************************/ +#define ETH_HLEN 14 +/* L2 header size + 2*VLANs (8 bytes) + LLC SNAP (8 bytes) */ +#define ETH_OVREHEAD (ETH_HLEN + 8 + 8) +#define ETH_MIN_PACKET_SIZE 60 +#define ETH_MAX_PACKET_SIZE 1500 +#define ETH_MAX_JUMBO_PACKET_SIZE 9600 +#define MDIO_ACCESS_TIMEOUT 1000 +#define BMAC_CONTROL_RX_ENABLE 2 +#define WC_LANE_MAX 4 +#define I2C_SWITCH_WIDTH 2 +#define I2C_BSC0 0 +#define I2C_BSC1 1 +#define I2C_WA_RETRY_CNT 3 +#define MCPR_IMC_COMMAND_READ_OP 1 +#define MCPR_IMC_COMMAND_WRITE_OP 2 + +/***********************************************************/ +/* Shortcut definitions */ +/***********************************************************/ + +#define NIG_LATCH_BC_ENABLE_MI_INT 0 + +#define NIG_STATUS_EMAC0_MI_INT \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT +#define NIG_STATUS_XGXS0_LINK10G \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G +#define NIG_STATUS_XGXS0_LINK_STATUS \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS +#define NIG_STATUS_XGXS0_LINK_STATUS_SIZE \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE +#define NIG_STATUS_SERDES0_LINK_STATUS \ + NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS +#define NIG_MASK_MI_INT \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT +#define NIG_MASK_XGXS0_LINK10G \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G +#define NIG_MASK_XGXS0_LINK_STATUS \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS +#define NIG_MASK_SERDES0_LINK_STATUS \ + NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS + +#define MDIO_AN_CL73_OR_37_COMPLETE \ + (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | \ + MDIO_GP_STATUS_TOP_AN_STATUS1_CL37_AUTONEG_COMPLETE) + +#define XGXS_RESET_BITS \ + (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB) + +#define SERDES_RESET_BITS \ + (MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN | \ + MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD) + +#define AUTONEG_CL37 SHARED_HW_CFG_AN_ENABLE_CL37 +#define AUTONEG_CL73 SHARED_HW_CFG_AN_ENABLE_CL73 +#define AUTONEG_BAM SHARED_HW_CFG_AN_ENABLE_BAM +#define AUTONEG_PARALLEL \ + SHARED_HW_CFG_AN_ENABLE_PARALLEL_DETECTION +#define AUTONEG_SGMII_FIBER_AUTODET \ + SHARED_HW_CFG_AN_EN_SGMII_FIBER_AUTO_DETECT +#define AUTONEG_REMOTE_PHY SHARED_HW_CFG_AN_ENABLE_REMOTE_PHY + +#define GP_STATUS_PAUSE_RSOLUTION_TXSIDE \ + MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_TXSIDE +#define GP_STATUS_PAUSE_RSOLUTION_RXSIDE \ + MDIO_GP_STATUS_TOP_AN_STATUS1_PAUSE_RSOLUTION_RXSIDE +#define GP_STATUS_SPEED_MASK \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_MASK +#define GP_STATUS_10M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10M +#define GP_STATUS_100M MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_100M +#define GP_STATUS_1G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G +#define GP_STATUS_2_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_2_5G +#define GP_STATUS_5G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_5G +#define GP_STATUS_6G MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_6G +#define GP_STATUS_10G_HIG \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_HIG +#define GP_STATUS_10G_CX4 \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_CX4 +#define GP_STATUS_1G_KX MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_1G_KX +#define GP_STATUS_10G_KX4 \ + MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KX4 +#define GP_STATUS_10G_KR MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_KR +#define GP_STATUS_10G_XFI MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_XFI +#define GP_STATUS_20G_DXGXS MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_20G_DXGXS +#define GP_STATUS_10G_SFI MDIO_GP_STATUS_TOP_AN_STATUS1_ACTUAL_SPEED_10G_SFI +#define LINK_10THD LINK_STATUS_SPEED_AND_DUPLEX_10THD +#define LINK_10TFD LINK_STATUS_SPEED_AND_DUPLEX_10TFD +#define LINK_100TXHD LINK_STATUS_SPEED_AND_DUPLEX_100TXHD +#define LINK_100T4 LINK_STATUS_SPEED_AND_DUPLEX_100T4 +#define LINK_100TXFD LINK_STATUS_SPEED_AND_DUPLEX_100TXFD +#define LINK_1000THD LINK_STATUS_SPEED_AND_DUPLEX_1000THD +#define LINK_1000TFD LINK_STATUS_SPEED_AND_DUPLEX_1000TFD +#define LINK_1000XFD LINK_STATUS_SPEED_AND_DUPLEX_1000XFD +#define LINK_2500THD LINK_STATUS_SPEED_AND_DUPLEX_2500THD +#define LINK_2500TFD LINK_STATUS_SPEED_AND_DUPLEX_2500TFD +#define LINK_2500XFD LINK_STATUS_SPEED_AND_DUPLEX_2500XFD +#define LINK_10GTFD LINK_STATUS_SPEED_AND_DUPLEX_10GTFD +#define LINK_10GXFD LINK_STATUS_SPEED_AND_DUPLEX_10GXFD +#define LINK_20GTFD LINK_STATUS_SPEED_AND_DUPLEX_20GTFD +#define LINK_20GXFD LINK_STATUS_SPEED_AND_DUPLEX_20GXFD + + + +/* */ +#define SFP_EEPROM_CON_TYPE_ADDR 0x2 + #define SFP_EEPROM_CON_TYPE_VAL_LC 0x7 + #define SFP_EEPROM_CON_TYPE_VAL_COPPER 0x21 + + +#define SFP_EEPROM_COMP_CODE_ADDR 0x3 + #define SFP_EEPROM_COMP_CODE_SR_MASK (1<<4) + #define SFP_EEPROM_COMP_CODE_LR_MASK (1<<5) + #define SFP_EEPROM_COMP_CODE_LRM_MASK (1<<6) + +#define SFP_EEPROM_FC_TX_TECH_ADDR 0x8 + #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE 0x4 + #define SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE 0x8 + +#define SFP_EEPROM_OPTIONS_ADDR 0x40 + #define SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK 0x1 +#define SFP_EEPROM_OPTIONS_SIZE 2 + +#define EDC_MODE_LINEAR 0x0022 +#define EDC_MODE_LIMITING 0x0044 +#define EDC_MODE_PASSIVE_DAC 0x0055 + + +/* BRB thresholds for E2*/ +#define PFC_E2_BRB_MAC_PAUSE_XOFF_THR_PAUSE 170 +#define PFC_E2_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0 + +#define PFC_E2_BRB_MAC_PAUSE_XON_THR_PAUSE 250 +#define PFC_E2_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0 + +#define PFC_E2_BRB_MAC_FULL_XOFF_THR_PAUSE 10 +#define PFC_E2_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 90 + +#define PFC_E2_BRB_MAC_FULL_XON_THR_PAUSE 50 +#define PFC_E2_BRB_MAC_FULL_XON_THR_NON_PAUSE 250 + +/* BRB thresholds for E3A0 */ +#define PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_PAUSE 290 +#define PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0 + +#define PFC_E3A0_BRB_MAC_PAUSE_XON_THR_PAUSE 410 +#define PFC_E3A0_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0 + +#define PFC_E3A0_BRB_MAC_FULL_XOFF_THR_PAUSE 10 +#define PFC_E3A0_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 170 + +#define PFC_E3A0_BRB_MAC_FULL_XON_THR_PAUSE 50 +#define PFC_E3A0_BRB_MAC_FULL_XON_THR_NON_PAUSE 410 + + +/* BRB thresholds for E3B0 2 port mode*/ +#define PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_PAUSE 1025 +#define PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0 + +#define PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_PAUSE 1025 +#define PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0 + +#define PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_PAUSE 10 +#define PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 1025 + +#define PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_PAUSE 50 +#define PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_NON_PAUSE 1025 + +/* only for E3B0*/ +#define PFC_E3B0_2P_BRB_FULL_LB_XOFF_THR 1025 +#define PFC_E3B0_2P_BRB_FULL_LB_XON_THR 1025 + +/* Lossy +Lossless GUARANTIED == GUART */ +#define PFC_E3B0_2P_MIX_PAUSE_LB_GUART 284 +/* Lossless +Lossless*/ +#define PFC_E3B0_2P_PAUSE_LB_GUART 236 +/* Lossy +Lossy*/ +#define PFC_E3B0_2P_NON_PAUSE_LB_GUART 342 + +/* Lossy +Lossless*/ +#define PFC_E3B0_2P_MIX_PAUSE_MAC_0_CLASS_T_GUART 284 +/* Lossless +Lossless*/ +#define PFC_E3B0_2P_PAUSE_MAC_0_CLASS_T_GUART 236 +/* Lossy +Lossy*/ +#define PFC_E3B0_2P_NON_PAUSE_MAC_0_CLASS_T_GUART 336 +#define PFC_E3B0_2P_BRB_MAC_0_CLASS_T_GUART_HYST 80 + +#define PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART 0 +#define PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART_HYST 0 + +/* BRB thresholds for E3B0 4 port mode */ +#define PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_PAUSE 304 +#define PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE 0 + +#define PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_PAUSE 384 +#define PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE 0 + +#define PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_PAUSE 10 +#define PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE 304 + +#define PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_PAUSE 50 +#define PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_NON_PAUSE 384 + + +/* only for E3B0*/ +#define PFC_E3B0_4P_BRB_FULL_LB_XOFF_THR 304 +#define PFC_E3B0_4P_BRB_FULL_LB_XON_THR 384 +#define PFC_E3B0_4P_LB_GUART 120 + +#define PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART 120 +#define PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART_HYST 80 + +#define PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART 80 +#define PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART_HYST 120 + +#define DCBX_INVALID_COS (0xFF) + +#define ETS_BW_LIMIT_CREDIT_UPPER_BOUND (0x5000) +#define ETS_BW_LIMIT_CREDIT_WEIGHT (0x5000) +#define ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS (1360) +#define ETS_E3B0_NIG_MIN_W_VAL_20GBPS (2720) +#define ETS_E3B0_PBF_MIN_W_VAL (10000) + +#define MAX_PACKET_SIZE (9700) +#define WC_UC_TIMEOUT 100 + +/**********************************************************/ +/* INTERFACE */ +/**********************************************************/ + +#define CL22_WR_OVER_CL45(_bp, _phy, _bank, _addr, _val) \ + bnx2x_cl45_write(_bp, _phy, \ + (_phy)->def_md_devad, \ + (_bank + (_addr & 0xf)), \ + _val) + +#define CL22_RD_OVER_CL45(_bp, _phy, _bank, _addr, _val) \ + bnx2x_cl45_read(_bp, _phy, \ + (_phy)->def_md_devad, \ + (_bank + (_addr & 0xf)), \ + _val) + +static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits) +{ + u32 val = REG_RD(bp, reg); + + val |= bits; + REG_WR(bp, reg, val); + return val; +} + +static u32 bnx2x_bits_dis(struct bnx2x *bp, u32 reg, u32 bits) +{ + u32 val = REG_RD(bp, reg); + + val &= ~bits; + REG_WR(bp, reg, val); + return val; +} + +/******************************************************************/ +/* EPIO/GPIO section */ +/******************************************************************/ +static void bnx2x_get_epio(struct bnx2x *bp, u32 epio_pin, u32 *en) +{ + u32 epio_mask, gp_oenable; + *en = 0; + /* Sanity check */ + if (epio_pin > 31) { + DP(NETIF_MSG_LINK, "Invalid EPIO pin %d to get\n", epio_pin); + return; + } + + epio_mask = 1 << epio_pin; + /* Set this EPIO to output */ + gp_oenable = REG_RD(bp, MCP_REG_MCPR_GP_OENABLE); + REG_WR(bp, MCP_REG_MCPR_GP_OENABLE, gp_oenable & ~epio_mask); + + *en = (REG_RD(bp, MCP_REG_MCPR_GP_INPUTS) & epio_mask) >> epio_pin; +} +static void bnx2x_set_epio(struct bnx2x *bp, u32 epio_pin, u32 en) +{ + u32 epio_mask, gp_output, gp_oenable; + + /* Sanity check */ + if (epio_pin > 31) { + DP(NETIF_MSG_LINK, "Invalid EPIO pin %d to set\n", epio_pin); + return; + } + DP(NETIF_MSG_LINK, "Setting EPIO pin %d to %d\n", epio_pin, en); + epio_mask = 1 << epio_pin; + /* Set this EPIO to output */ + gp_output = REG_RD(bp, MCP_REG_MCPR_GP_OUTPUTS); + if (en) + gp_output |= epio_mask; + else + gp_output &= ~epio_mask; + + REG_WR(bp, MCP_REG_MCPR_GP_OUTPUTS, gp_output); + + /* Set the value for this EPIO */ + gp_oenable = REG_RD(bp, MCP_REG_MCPR_GP_OENABLE); + REG_WR(bp, MCP_REG_MCPR_GP_OENABLE, gp_oenable | epio_mask); +} + +static void bnx2x_set_cfg_pin(struct bnx2x *bp, u32 pin_cfg, u32 val) +{ + if (pin_cfg == PIN_CFG_NA) + return; + if (pin_cfg >= PIN_CFG_EPIO0) { + bnx2x_set_epio(bp, pin_cfg - PIN_CFG_EPIO0, val); + } else { + u8 gpio_num = (pin_cfg - PIN_CFG_GPIO0_P0) & 0x3; + u8 gpio_port = (pin_cfg - PIN_CFG_GPIO0_P0) >> 2; + bnx2x_set_gpio(bp, gpio_num, (u8)val, gpio_port); + } +} + +static u32 bnx2x_get_cfg_pin(struct bnx2x *bp, u32 pin_cfg, u32 *val) +{ + if (pin_cfg == PIN_CFG_NA) + return -EINVAL; + if (pin_cfg >= PIN_CFG_EPIO0) { + bnx2x_get_epio(bp, pin_cfg - PIN_CFG_EPIO0, val); + } else { + u8 gpio_num = (pin_cfg - PIN_CFG_GPIO0_P0) & 0x3; + u8 gpio_port = (pin_cfg - PIN_CFG_GPIO0_P0) >> 2; + *val = bnx2x_get_gpio(bp, gpio_num, gpio_port); + } + return 0; + +} +/******************************************************************/ +/* ETS section */ +/******************************************************************/ +static void bnx2x_ets_e2e3a0_disabled(struct link_params *params) +{ + /* ETS disabled configuration*/ + struct bnx2x *bp = params->bp; + + DP(NETIF_MSG_LINK, "ETS E2E3 disabled configuration\n"); + + /* + * mapping between entry priority to client number (0,1,2 -debug and + * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST) + * 3bits client num. + * PRI4 | PRI3 | PRI2 | PRI1 | PRI0 + * cos1-100 cos0-011 dbg1-010 dbg0-001 MCP-000 + */ + + REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, 0x4688); + /* + * Bitmap of 5bits length. Each bit specifies whether the entry behaves + * as strict. Bits 0,1,2 - debug and management entries, 3 - + * COS0 entry, 4 - COS1 entry. + * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT + * bit4 bit3 bit2 bit1 bit0 + * MCP and debug are strict + */ + + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7); + /* defines which entries (clients) are subjected to WFQ arbitration */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0); + /* + * For strict priority entries defines the number of consecutive + * slots for the highest priority. + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); + /* + * mapping between the CREDIT_WEIGHT registers and actual client + * numbers + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0); + + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, 0); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, 0); + REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, 0); + /* ETS mode disable */ + REG_WR(bp, PBF_REG_ETS_ENABLED, 0); + /* + * If ETS mode is enabled (there is no strict priority) defines a WFQ + * weight for COS0/COS1. + */ + REG_WR(bp, PBF_REG_COS0_WEIGHT, 0x2710); + REG_WR(bp, PBF_REG_COS1_WEIGHT, 0x2710); + /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter */ + REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, 0x989680); + REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, 0x989680); + /* Defines the number of consecutive slots for the strict priority */ + REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0); +} +/****************************************************************************** +* Description: +* Getting min_w_val will be set according to line speed . +*. +******************************************************************************/ +static u32 bnx2x_ets_get_min_w_val_nig(const struct link_vars *vars) +{ + u32 min_w_val = 0; + /* Calculate min_w_val.*/ + if (vars->link_up) { + if (SPEED_20000 == vars->line_speed) + min_w_val = ETS_E3B0_NIG_MIN_W_VAL_20GBPS; + else + min_w_val = ETS_E3B0_NIG_MIN_W_VAL_UP_TO_10GBPS; + } else + min_w_val = ETS_E3B0_NIG_MIN_W_VAL_20GBPS; + /** + * If the link isn't up (static configuration for example ) The + * link will be according to 20GBPS. + */ + return min_w_val; +} +/****************************************************************************** +* Description: +* Getting credit upper bound form min_w_val. +*. +******************************************************************************/ +static u32 bnx2x_ets_get_credit_upper_bound(const u32 min_w_val) +{ + const u32 credit_upper_bound = (u32)MAXVAL((150 * min_w_val), + MAX_PACKET_SIZE); + return credit_upper_bound; +} +/****************************************************************************** +* Description: +* Set credit upper bound for NIG. +*. +******************************************************************************/ +static void bnx2x_ets_e3b0_set_credit_upper_bound_nig( + const struct link_params *params, + const u32 min_w_val) +{ + struct bnx2x *bp = params->bp; + const u8 port = params->port; + const u32 credit_upper_bound = + bnx2x_ets_get_credit_upper_bound(min_w_val); + + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_0 : + NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, credit_upper_bound); + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_1 : + NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, credit_upper_bound); + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_2 : + NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_2, credit_upper_bound); + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_3 : + NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_3, credit_upper_bound); + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_4 : + NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_4, credit_upper_bound); + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_5 : + NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_5, credit_upper_bound); + + if (0 == port) { + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_6, + credit_upper_bound); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_7, + credit_upper_bound); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_8, + credit_upper_bound); + } +} +/****************************************************************************** +* Description: +* Will return the NIG ETS registers to init values.Except +* credit_upper_bound. +* That isn't used in this configuration (No WFQ is enabled) and will be +* configured acording to spec +*. +******************************************************************************/ +static void bnx2x_ets_e3b0_nig_disabled(const struct link_params *params, + const struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + const u8 port = params->port; + const u32 min_w_val = bnx2x_ets_get_min_w_val_nig(vars); + /** + * mapping between entry priority to client number (0,1,2 -debug and + * management clients, 3 - COS0 client, 4 - COS1, ... 8 - + * COS5)(HIGHEST) 4bits client num.TODO_ETS - Should be done by + * reset value or init tool + */ + if (port) { + REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB, 0x543210); + REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_MSB, 0x0); + } else { + REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB, 0x76543210); + REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB, 0x8); + } + /** + * For strict priority entries defines the number of consecutive + * slots for the highest priority. + */ + /* TODO_ETS - Should be done by reset value or init tool */ + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS : + NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); + /** + * mapping between the CREDIT_WEIGHT registers and actual client + * numbers + */ + /* TODO_ETS - Should be done by reset value or init tool */ + if (port) { + /*Port 1 has 6 COS*/ + REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_LSB, 0x210543); + REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_MSB, 0x0); + } else { + /*Port 0 has 9 COS*/ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_LSB, + 0x43210876); + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_MSB, 0x5); + } + + /** + * Bitmap of 5bits length. Each bit specifies whether the entry behaves + * as strict. Bits 0,1,2 - debug and management entries, 3 - + * COS0 entry, 4 - COS1 entry. + * COS1 | COS0 | DEBUG1 | DEBUG0 | MGMT + * bit4 bit3 bit2 bit1 bit0 + * MCP and debug are strict + */ + if (port) + REG_WR(bp, NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT, 0x3f); + else + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1ff); + /* defines which entries (clients) are subjected to WFQ arbitration */ + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ : + NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0); + + /** + * Please notice the register address are note continuous and a + * for here is note appropriate.In 2 port mode port0 only COS0-5 + * can be used. DEBUG1,DEBUG1,MGMT are never used for WFQ* In 4 + * port mode port1 only COS0-2 can be used. DEBUG1,DEBUG1,MGMT + * are never used for WFQ + */ + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, 0x0); + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, 0x0); + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2, 0x0); + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_3 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3, 0x0); + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_4 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4, 0x0); + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_5 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5, 0x0); + if (0 == port) { + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_6, 0x0); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_7, 0x0); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_8, 0x0); + } + + bnx2x_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val); +} +/****************************************************************************** +* Description: +* Set credit upper bound for PBF. +*. +******************************************************************************/ +static void bnx2x_ets_e3b0_set_credit_upper_bound_pbf( + const struct link_params *params, + const u32 min_w_val) +{ + struct bnx2x *bp = params->bp; + const u32 credit_upper_bound = + bnx2x_ets_get_credit_upper_bound(min_w_val); + const u8 port = params->port; + u32 base_upper_bound = 0; + u8 max_cos = 0; + u8 i = 0; + /** + * In 2 port mode port0 has COS0-5 that can be used for WFQ.In 4 + * port mode port1 has COS0-2 that can be used for WFQ. + */ + if (0 == port) { + base_upper_bound = PBF_REG_COS0_UPPER_BOUND_P0; + max_cos = DCBX_E3B0_MAX_NUM_COS_PORT0; + } else { + base_upper_bound = PBF_REG_COS0_UPPER_BOUND_P1; + max_cos = DCBX_E3B0_MAX_NUM_COS_PORT1; + } + + for (i = 0; i < max_cos; i++) + REG_WR(bp, base_upper_bound + (i << 2), credit_upper_bound); +} + +/****************************************************************************** +* Description: +* Will return the PBF ETS registers to init values.Except +* credit_upper_bound. +* That isn't used in this configuration (No WFQ is enabled) and will be +* configured acording to spec +*. +******************************************************************************/ +static void bnx2x_ets_e3b0_pbf_disabled(const struct link_params *params) +{ + struct bnx2x *bp = params->bp; + const u8 port = params->port; + const u32 min_w_val_pbf = ETS_E3B0_PBF_MIN_W_VAL; + u8 i = 0; + u32 base_weight = 0; + u8 max_cos = 0; + + /** + * mapping between entry priority to client number 0 - COS0 + * client, 2 - COS1, ... 5 - COS5)(HIGHEST) 4bits client num. + * TODO_ETS - Should be done by reset value or init tool + */ + if (port) + /* 0x688 (|011|0 10|00 1|000) */ + REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1 , 0x688); + else + /* (10 1|100 |011|0 10|00 1|000) */ + REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0 , 0x2C688); + + /* TODO_ETS - Should be done by reset value or init tool */ + if (port) + /* 0x688 (|011|0 10|00 1|000)*/ + REG_WR(bp, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P1, 0x688); + else + /* 0x2C688 (10 1|100 |011|0 10|00 1|000) */ + REG_WR(bp, PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P0, 0x2C688); + + REG_WR(bp, (port) ? PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P1 : + PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P0 , 0x100); + + + REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 : + PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0 , 0); + + REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 : + PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0 , 0); + /** + * In 2 port mode port0 has COS0-5 that can be used for WFQ. + * In 4 port mode port1 has COS0-2 that can be used for WFQ. + */ + if (0 == port) { + base_weight = PBF_REG_COS0_WEIGHT_P0; + max_cos = DCBX_E3B0_MAX_NUM_COS_PORT0; + } else { + base_weight = PBF_REG_COS0_WEIGHT_P1; + max_cos = DCBX_E3B0_MAX_NUM_COS_PORT1; + } + + for (i = 0; i < max_cos; i++) + REG_WR(bp, base_weight + (0x4 * i), 0); + + bnx2x_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf); +} +/****************************************************************************** +* Description: +* E3B0 disable will return basicly the values to init values. +*. +******************************************************************************/ +static int bnx2x_ets_e3b0_disabled(const struct link_params *params, + const struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + + if (!CHIP_IS_E3B0(bp)) { + DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_disabled the chip isn't E3B0" + "\n"); + return -EINVAL; + } + + bnx2x_ets_e3b0_nig_disabled(params, vars); + + bnx2x_ets_e3b0_pbf_disabled(params); + + return 0; +} + +/****************************************************************************** +* Description: +* Disable will return basicly the values to init values. +*. +******************************************************************************/ +int bnx2x_ets_disabled(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + int bnx2x_status = 0; + + if ((CHIP_IS_E2(bp)) || (CHIP_IS_E3A0(bp))) + bnx2x_ets_e2e3a0_disabled(params); + else if (CHIP_IS_E3B0(bp)) + bnx2x_status = bnx2x_ets_e3b0_disabled(params, vars); + else { + DP(NETIF_MSG_LINK, "bnx2x_ets_disabled - chip not supported\n"); + return -EINVAL; + } + + return bnx2x_status; +} + +/****************************************************************************** +* Description +* Set the COS mappimg to SP and BW until this point all the COS are not +* set as SP or BW. +******************************************************************************/ +static int bnx2x_ets_e3b0_cli_map(const struct link_params *params, + const struct bnx2x_ets_params *ets_params, + const u8 cos_sp_bitmap, + const u8 cos_bw_bitmap) +{ + struct bnx2x *bp = params->bp; + const u8 port = params->port; + const u8 nig_cli_sp_bitmap = 0x7 | (cos_sp_bitmap << 3); + const u8 pbf_cli_sp_bitmap = cos_sp_bitmap; + const u8 nig_cli_subject2wfq_bitmap = cos_bw_bitmap << 3; + const u8 pbf_cli_subject2wfq_bitmap = cos_bw_bitmap; + + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT : + NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, nig_cli_sp_bitmap); + + REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 : + PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0 , pbf_cli_sp_bitmap); + + REG_WR(bp, (port) ? NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ : + NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, + nig_cli_subject2wfq_bitmap); + + REG_WR(bp, (port) ? PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 : + PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0, + pbf_cli_subject2wfq_bitmap); + + return 0; +} + +/****************************************************************************** +* Description: +* This function is needed because NIG ARB_CREDIT_WEIGHT_X are +* not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable. +******************************************************************************/ +static int bnx2x_ets_e3b0_set_cos_bw(struct bnx2x *bp, + const u8 cos_entry, + const u32 min_w_val_nig, + const u32 min_w_val_pbf, + const u16 total_bw, + const u8 bw, + const u8 port) +{ + u32 nig_reg_adress_crd_weight = 0; + u32 pbf_reg_adress_crd_weight = 0; + /* Calculate and set BW for this COS*/ + const u32 cos_bw_nig = (bw * min_w_val_nig) / total_bw; + const u32 cos_bw_pbf = (bw * min_w_val_pbf) / total_bw; + + switch (cos_entry) { + case 0: + nig_reg_adress_crd_weight = + (port) ? NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0; + pbf_reg_adress_crd_weight = (port) ? + PBF_REG_COS0_WEIGHT_P1 : PBF_REG_COS0_WEIGHT_P0; + break; + case 1: + nig_reg_adress_crd_weight = (port) ? + NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1; + pbf_reg_adress_crd_weight = (port) ? + PBF_REG_COS1_WEIGHT_P1 : PBF_REG_COS1_WEIGHT_P0; + break; + case 2: + nig_reg_adress_crd_weight = (port) ? + NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 : + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2; + + pbf_reg_adress_crd_weight = (port) ? + PBF_REG_COS2_WEIGHT_P1 : PBF_REG_COS2_WEIGHT_P0; + break; + case 3: + if (port) + return -EINVAL; + nig_reg_adress_crd_weight = + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3; + pbf_reg_adress_crd_weight = + PBF_REG_COS3_WEIGHT_P0; + break; + case 4: + if (port) + return -EINVAL; + nig_reg_adress_crd_weight = + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4; + pbf_reg_adress_crd_weight = PBF_REG_COS4_WEIGHT_P0; + break; + case 5: + if (port) + return -EINVAL; + nig_reg_adress_crd_weight = + NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5; + pbf_reg_adress_crd_weight = PBF_REG_COS5_WEIGHT_P0; + break; + } + + REG_WR(bp, nig_reg_adress_crd_weight, cos_bw_nig); + + REG_WR(bp, pbf_reg_adress_crd_weight, cos_bw_pbf); + + return 0; +} +/****************************************************************************** +* Description: +* Calculate the total BW.A value of 0 isn't legal. +*. +******************************************************************************/ +static int bnx2x_ets_e3b0_get_total_bw( + const struct link_params *params, + const struct bnx2x_ets_params *ets_params, + u16 *total_bw) +{ + struct bnx2x *bp = params->bp; + u8 cos_idx = 0; + + *total_bw = 0 ; + /* Calculate total BW requested */ + for (cos_idx = 0; cos_idx < ets_params->num_of_cos; cos_idx++) { + if (bnx2x_cos_state_bw == ets_params->cos[cos_idx].state) { + + if (0 == ets_params->cos[cos_idx].params.bw_params.bw) { + DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config BW" + "was set to 0\n"); + return -EINVAL; + } + *total_bw += + ets_params->cos[cos_idx].params.bw_params.bw; + } + } + + /*Check taotl BW is valid */ + if ((100 != *total_bw) || (0 == *total_bw)) { + if (0 == *total_bw) { + DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config toatl BW" + "shouldn't be 0\n"); + return -EINVAL; + } + DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config toatl BW should be" + "100\n"); + /** + * We can handle a case whre the BW isn't 100 this can happen + * if the TC are joined. + */ + } + return 0; +} + +/****************************************************************************** +* Description: +* Invalidate all the sp_pri_to_cos. +*. +******************************************************************************/ +static void bnx2x_ets_e3b0_sp_pri_to_cos_init(u8 *sp_pri_to_cos) +{ + u8 pri = 0; + for (pri = 0; pri < DCBX_MAX_NUM_COS; pri++) + sp_pri_to_cos[pri] = DCBX_INVALID_COS; +} +/****************************************************************************** +* Description: +* Calculate and set the SP (ARB_PRIORITY_CLIENT) NIG and PBF registers +* according to sp_pri_to_cos. +*. +******************************************************************************/ +static int bnx2x_ets_e3b0_sp_pri_to_cos_set(const struct link_params *params, + u8 *sp_pri_to_cos, const u8 pri, + const u8 cos_entry) +{ + struct bnx2x *bp = params->bp; + const u8 port = params->port; + const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 : + DCBX_E3B0_MAX_NUM_COS_PORT0; + + if (DCBX_INVALID_COS != sp_pri_to_cos[pri]) { + DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid " + "parameter There can't be two COS's with" + "the same strict pri\n"); + return -EINVAL; + } + + if (pri > max_num_of_cos) { + DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_pri_to_cos_set invalid" + "parameter Illegal strict priority\n"); + return -EINVAL; + } + + sp_pri_to_cos[pri] = cos_entry; + return 0; + +} + +/****************************************************************************** +* Description: +* Returns the correct value according to COS and priority in +* the sp_pri_cli register. +*. +******************************************************************************/ +static u64 bnx2x_e3b0_sp_get_pri_cli_reg(const u8 cos, const u8 cos_offset, + const u8 pri_set, + const u8 pri_offset, + const u8 entry_size) +{ + u64 pri_cli_nig = 0; + pri_cli_nig = ((u64)(cos + cos_offset)) << (entry_size * + (pri_set + pri_offset)); + + return pri_cli_nig; +} +/****************************************************************************** +* Description: +* Returns the correct value according to COS and priority in the +* sp_pri_cli register for NIG. +*. +******************************************************************************/ +static u64 bnx2x_e3b0_sp_get_pri_cli_reg_nig(const u8 cos, const u8 pri_set) +{ + /* MCP Dbg0 and dbg1 are always with higher strict pri*/ + const u8 nig_cos_offset = 3; + const u8 nig_pri_offset = 3; + + return bnx2x_e3b0_sp_get_pri_cli_reg(cos, nig_cos_offset, pri_set, + nig_pri_offset, 4); + +} +/****************************************************************************** +* Description: +* Returns the correct value according to COS and priority in the +* sp_pri_cli register for PBF. +*. +******************************************************************************/ +static u64 bnx2x_e3b0_sp_get_pri_cli_reg_pbf(const u8 cos, const u8 pri_set) +{ + const u8 pbf_cos_offset = 0; + const u8 pbf_pri_offset = 0; + + return bnx2x_e3b0_sp_get_pri_cli_reg(cos, pbf_cos_offset, pri_set, + pbf_pri_offset, 3); + +} + +/****************************************************************************** +* Description: +* Calculate and set the SP (ARB_PRIORITY_CLIENT) NIG and PBF registers +* according to sp_pri_to_cos.(which COS has higher priority) +*. +******************************************************************************/ +static int bnx2x_ets_e3b0_sp_set_pri_cli_reg(const struct link_params *params, + u8 *sp_pri_to_cos) +{ + struct bnx2x *bp = params->bp; + u8 i = 0; + const u8 port = params->port; + /* MCP Dbg0 and dbg1 are always with higher strict pri*/ + u64 pri_cli_nig = 0x210; + u32 pri_cli_pbf = 0x0; + u8 pri_set = 0; + u8 pri_bitmask = 0; + const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 : + DCBX_E3B0_MAX_NUM_COS_PORT0; + + u8 cos_bit_to_set = (1 << max_num_of_cos) - 1; + + /* Set all the strict priority first */ + for (i = 0; i < max_num_of_cos; i++) { + if (DCBX_INVALID_COS != sp_pri_to_cos[i]) { + if (DCBX_MAX_NUM_COS <= sp_pri_to_cos[i]) { + DP(NETIF_MSG_LINK, + "bnx2x_ets_e3b0_sp_set_pri_cli_reg " + "invalid cos entry\n"); + return -EINVAL; + } + + pri_cli_nig |= bnx2x_e3b0_sp_get_pri_cli_reg_nig( + sp_pri_to_cos[i], pri_set); + + pri_cli_pbf |= bnx2x_e3b0_sp_get_pri_cli_reg_pbf( + sp_pri_to_cos[i], pri_set); + pri_bitmask = 1 << sp_pri_to_cos[i]; + /* COS is used remove it from bitmap.*/ + if (0 == (pri_bitmask & cos_bit_to_set)) { + DP(NETIF_MSG_LINK, + "bnx2x_ets_e3b0_sp_set_pri_cli_reg " + "invalid There can't be two COS's with" + " the same strict pri\n"); + return -EINVAL; + } + cos_bit_to_set &= ~pri_bitmask; + pri_set++; + } + } + + /* Set all the Non strict priority i= COS*/ + for (i = 0; i < max_num_of_cos; i++) { + pri_bitmask = 1 << i; + /* Check if COS was already used for SP */ + if (pri_bitmask & cos_bit_to_set) { + /* COS wasn't used for SP */ + pri_cli_nig |= bnx2x_e3b0_sp_get_pri_cli_reg_nig( + i, pri_set); + + pri_cli_pbf |= bnx2x_e3b0_sp_get_pri_cli_reg_pbf( + i, pri_set); + /* COS is used remove it from bitmap.*/ + cos_bit_to_set &= ~pri_bitmask; + pri_set++; + } + } + + if (pri_set != max_num_of_cos) { + DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_sp_set_pri_cli_reg not all " + "entries were set\n"); + return -EINVAL; + } + + if (port) { + /* Only 6 usable clients*/ + REG_WR(bp, NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB, + (u32)pri_cli_nig); + + REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1 , pri_cli_pbf); + } else { + /* Only 9 usable clients*/ + const u32 pri_cli_nig_lsb = (u32) (pri_cli_nig); + const u32 pri_cli_nig_msb = (u32) ((pri_cli_nig >> 32) & 0xF); + + REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB, + pri_cli_nig_lsb); + REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB, + pri_cli_nig_msb); + + REG_WR(bp, PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0 , pri_cli_pbf); + } + return 0; +} + +/****************************************************************************** +* Description: +* Configure the COS to ETS according to BW and SP settings. +******************************************************************************/ +int bnx2x_ets_e3b0_config(const struct link_params *params, + const struct link_vars *vars, + const struct bnx2x_ets_params *ets_params) +{ + struct bnx2x *bp = params->bp; + int bnx2x_status = 0; + const u8 port = params->port; + u16 total_bw = 0; + const u32 min_w_val_nig = bnx2x_ets_get_min_w_val_nig(vars); + const u32 min_w_val_pbf = ETS_E3B0_PBF_MIN_W_VAL; + u8 cos_bw_bitmap = 0; + u8 cos_sp_bitmap = 0; + u8 sp_pri_to_cos[DCBX_MAX_NUM_COS] = {0}; + const u8 max_num_of_cos = (port) ? DCBX_E3B0_MAX_NUM_COS_PORT1 : + DCBX_E3B0_MAX_NUM_COS_PORT0; + u8 cos_entry = 0; + + if (!CHIP_IS_E3B0(bp)) { + DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_disabled the chip isn't E3B0" + "\n"); + return -EINVAL; + } + + if ((ets_params->num_of_cos > max_num_of_cos)) { + DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config the number of COS " + "isn't supported\n"); + return -EINVAL; + } + + /* Prepare sp strict priority parameters*/ + bnx2x_ets_e3b0_sp_pri_to_cos_init(sp_pri_to_cos); + + /* Prepare BW parameters*/ + bnx2x_status = bnx2x_ets_e3b0_get_total_bw(params, ets_params, + &total_bw); + if (0 != bnx2x_status) { + DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config get_total_bw failed " + "\n"); + return -EINVAL; + } + + /** + * Upper bound is set according to current link speed (min_w_val + * should be the same for upper bound and COS credit val). + */ + bnx2x_ets_e3b0_set_credit_upper_bound_nig(params, min_w_val_nig); + bnx2x_ets_e3b0_set_credit_upper_bound_pbf(params, min_w_val_pbf); + + + for (cos_entry = 0; cos_entry < ets_params->num_of_cos; cos_entry++) { + if (bnx2x_cos_state_bw == ets_params->cos[cos_entry].state) { + cos_bw_bitmap |= (1 << cos_entry); + /** + * The function also sets the BW in HW(not the mappin + * yet) + */ + bnx2x_status = bnx2x_ets_e3b0_set_cos_bw( + bp, cos_entry, min_w_val_nig, min_w_val_pbf, + total_bw, + ets_params->cos[cos_entry].params.bw_params.bw, + port); + } else if (bnx2x_cos_state_strict == + ets_params->cos[cos_entry].state){ + cos_sp_bitmap |= (1 << cos_entry); + + bnx2x_status = bnx2x_ets_e3b0_sp_pri_to_cos_set( + params, + sp_pri_to_cos, + ets_params->cos[cos_entry].params.sp_params.pri, + cos_entry); + + } else { + DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_config cos state not" + " valid\n"); + return -EINVAL; + } + if (0 != bnx2x_status) { + DP(NETIF_MSG_LINK, "bnx2x_ets_e3b0_config set cos bw " + "failed\n"); + return bnx2x_status; + } + } + + /* Set SP register (which COS has higher priority) */ + bnx2x_status = bnx2x_ets_e3b0_sp_set_pri_cli_reg(params, + sp_pri_to_cos); + + if (0 != bnx2x_status) { + DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config set_pri_cli_reg " + "failed\n"); + return bnx2x_status; + } + + /* Set client mapping of BW and strict */ + bnx2x_status = bnx2x_ets_e3b0_cli_map(params, ets_params, + cos_sp_bitmap, + cos_bw_bitmap); + + if (0 != bnx2x_status) { + DP(NETIF_MSG_LINK, "bnx2x_ets_E3B0_config SP failed\n"); + return bnx2x_status; + } + return 0; +} +static void bnx2x_ets_bw_limit_common(const struct link_params *params) +{ + /* ETS disabled configuration */ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n"); + /* + * defines which entries (clients) are subjected to WFQ arbitration + * COS0 0x8 + * COS1 0x10 + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ, 0x18); + /* + * mapping between the ARB_CREDIT_WEIGHT registers and actual + * client numbers (WEIGHT_0 does not actually have to represent + * client 0) + * PRI4 | PRI3 | PRI2 | PRI1 | PRI0 + * cos1-001 cos0-000 dbg1-100 dbg0-011 MCP-010 + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP, 0x111A); + + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0, + ETS_BW_LIMIT_CREDIT_UPPER_BOUND); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1, + ETS_BW_LIMIT_CREDIT_UPPER_BOUND); + + /* ETS mode enabled*/ + REG_WR(bp, PBF_REG_ETS_ENABLED, 1); + + /* Defines the number of consecutive slots for the strict priority */ + REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0); + /* + * Bitmap of 5bits length. Each bit specifies whether the entry behaves + * as strict. Bits 0,1,2 - debug and management entries, 3 - COS0 + * entry, 4 - COS1 entry. + * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT + * bit4 bit3 bit2 bit1 bit0 + * MCP and debug are strict + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x7); + + /* Upper bound that COS0_WEIGHT can reach in the WFQ arbiter.*/ + REG_WR(bp, PBF_REG_COS0_UPPER_BOUND, + ETS_BW_LIMIT_CREDIT_UPPER_BOUND); + REG_WR(bp, PBF_REG_COS1_UPPER_BOUND, + ETS_BW_LIMIT_CREDIT_UPPER_BOUND); +} + +void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw, + const u32 cos1_bw) +{ + /* ETS disabled configuration*/ + struct bnx2x *bp = params->bp; + const u32 total_bw = cos0_bw + cos1_bw; + u32 cos0_credit_weight = 0; + u32 cos1_credit_weight = 0; + + DP(NETIF_MSG_LINK, "ETS enabled BW limit configuration\n"); + + if ((0 == total_bw) || + (0 == cos0_bw) || + (0 == cos1_bw)) { + DP(NETIF_MSG_LINK, "Total BW can't be zero\n"); + return; + } + + cos0_credit_weight = (cos0_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/ + total_bw; + cos1_credit_weight = (cos1_bw * ETS_BW_LIMIT_CREDIT_WEIGHT)/ + total_bw; + + bnx2x_ets_bw_limit_common(params); + + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0, cos0_credit_weight); + REG_WR(bp, NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1, cos1_credit_weight); + + REG_WR(bp, PBF_REG_COS0_WEIGHT, cos0_credit_weight); + REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight); +} + +int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos) +{ + /* ETS disabled configuration*/ + struct bnx2x *bp = params->bp; + u32 val = 0; + + DP(NETIF_MSG_LINK, "ETS enabled strict configuration\n"); + /* + * Bitmap of 5bits length. Each bit specifies whether the entry behaves + * as strict. Bits 0,1,2 - debug and management entries, + * 3 - COS0 entry, 4 - COS1 entry. + * COS1 | COS0 | DEBUG21 | DEBUG0 | MGMT + * bit4 bit3 bit2 bit1 bit0 + * MCP and debug are strict + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT, 0x1F); + /* + * For strict priority entries defines the number of consecutive slots + * for the highest priority. + */ + REG_WR(bp, NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS, 0x100); + /* ETS mode disable */ + REG_WR(bp, PBF_REG_ETS_ENABLED, 0); + /* Defines the number of consecutive slots for the strict priority */ + REG_WR(bp, PBF_REG_NUM_STRICT_ARB_SLOTS, 0x100); + + /* Defines the number of consecutive slots for the strict priority */ + REG_WR(bp, PBF_REG_HIGH_PRIORITY_COS_NUM, strict_cos); + + /* + * mapping between entry priority to client number (0,1,2 -debug and + * management clients, 3 - COS0 client, 4 - COS client)(HIGHEST) + * 3bits client num. + * PRI4 | PRI3 | PRI2 | PRI1 | PRI0 + * dbg0-010 dbg1-001 cos1-100 cos0-011 MCP-000 + * dbg0-010 dbg1-001 cos0-011 cos1-100 MCP-000 + */ + val = (0 == strict_cos) ? 0x2318 : 0x22E0; + REG_WR(bp, NIG_REG_P0_TX_ARB_PRIORITY_CLIENT, val); + + return 0; +} +/******************************************************************/ +/* PFC section */ +/******************************************************************/ + +static void bnx2x_update_pfc_xmac(struct link_params *params, + struct link_vars *vars, + u8 is_lb) +{ + struct bnx2x *bp = params->bp; + u32 xmac_base; + u32 pause_val, pfc0_val, pfc1_val; + + /* XMAC base adrr */ + xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; + + /* Initialize pause and pfc registers */ + pause_val = 0x18000; + pfc0_val = 0xFFFF8000; + pfc1_val = 0x2; + + /* No PFC support */ + if (!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED)) { + + /* + * RX flow control - Process pause frame in receive direction + */ + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) + pause_val |= XMAC_PAUSE_CTRL_REG_RX_PAUSE_EN; + + /* + * TX flow control - Send pause packet when buffer is full + */ + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) + pause_val |= XMAC_PAUSE_CTRL_REG_TX_PAUSE_EN; + } else {/* PFC support */ + pfc1_val |= XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN | + XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN | + XMAC_PFC_CTRL_HI_REG_RX_PFC_EN | + XMAC_PFC_CTRL_HI_REG_TX_PFC_EN; + } + + /* Write pause and PFC registers */ + REG_WR(bp, xmac_base + XMAC_REG_PAUSE_CTRL, pause_val); + REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL, pfc0_val); + REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, pfc1_val); + + + /* Set MAC address for source TX Pause/PFC frames */ + REG_WR(bp, xmac_base + XMAC_REG_CTRL_SA_LO, + ((params->mac_addr[2] << 24) | + (params->mac_addr[3] << 16) | + (params->mac_addr[4] << 8) | + (params->mac_addr[5]))); + REG_WR(bp, xmac_base + XMAC_REG_CTRL_SA_HI, + ((params->mac_addr[0] << 8) | + (params->mac_addr[1]))); + + udelay(30); +} + + +static void bnx2x_emac_get_pfc_stat(struct link_params *params, + u32 pfc_frames_sent[2], + u32 pfc_frames_received[2]) +{ + /* Read pfc statistic */ + struct bnx2x *bp = params->bp; + u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + u32 val_xon = 0; + u32 val_xoff = 0; + + DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n"); + + /* PFC received frames */ + val_xoff = REG_RD(bp, emac_base + + EMAC_REG_RX_PFC_STATS_XOFF_RCVD); + val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT; + val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD); + val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT; + + pfc_frames_received[0] = val_xon + val_xoff; + + /* PFC received sent */ + val_xoff = REG_RD(bp, emac_base + + EMAC_REG_RX_PFC_STATS_XOFF_SENT); + val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT; + val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT); + val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT; + + pfc_frames_sent[0] = val_xon + val_xoff; +} + +/* Read pfc statistic*/ +void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars, + u32 pfc_frames_sent[2], + u32 pfc_frames_received[2]) +{ + /* Read pfc statistic */ + struct bnx2x *bp = params->bp; + + DP(NETIF_MSG_LINK, "pfc statistic\n"); + + if (!vars->link_up) + return; + + if (MAC_TYPE_EMAC == vars->mac_type) { + DP(NETIF_MSG_LINK, "About to read PFC stats from EMAC\n"); + bnx2x_emac_get_pfc_stat(params, pfc_frames_sent, + pfc_frames_received); + } +} +/******************************************************************/ +/* MAC/PBF section */ +/******************************************************************/ +static void bnx2x_set_mdio_clk(struct bnx2x *bp, u32 chip_id, u8 port) +{ + u32 mode, emac_base; + /** + * Set clause 45 mode, slow down the MDIO clock to 2.5MHz + * (a value of 49==0x31) and make sure that the AUTO poll is off + */ + + if (CHIP_IS_E2(bp)) + emac_base = GRCBASE_EMAC0; + else + emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + mode = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE); + mode &= ~(EMAC_MDIO_MODE_AUTO_POLL | + EMAC_MDIO_MODE_CLOCK_CNT); + if (USES_WARPCORE(bp)) + mode |= (74L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT); + else + mode |= (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT); + + mode |= (EMAC_MDIO_MODE_CLAUSE_45); + REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE, mode); + + udelay(40); +} + +static void bnx2x_emac_init(struct link_params *params, + struct link_vars *vars) +{ + /* reset and unreset the emac core */ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + u32 val; + u16 timeout; + + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); + udelay(5); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + (MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE << port)); + + /* init emac - use read-modify-write */ + /* self clear reset */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_RESET)); + + timeout = 200; + do { + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + DP(NETIF_MSG_LINK, "EMAC reset reg is %u\n", val); + if (!timeout) { + DP(NETIF_MSG_LINK, "EMAC timeout!\n"); + return; + } + timeout--; + } while (val & EMAC_MODE_RESET); + bnx2x_set_mdio_clk(bp, params->chip_id, port); + /* Set mac address */ + val = ((params->mac_addr[0] << 8) | + params->mac_addr[1]); + EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH, val); + + val = ((params->mac_addr[2] << 24) | + (params->mac_addr[3] << 16) | + (params->mac_addr[4] << 8) | + params->mac_addr[5]); + EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val); +} + +static void bnx2x_set_xumac_nig(struct link_params *params, + u16 tx_pause_en, + u8 enable) +{ + struct bnx2x *bp = params->bp; + + REG_WR(bp, params->port ? NIG_REG_P1_MAC_IN_EN : NIG_REG_P0_MAC_IN_EN, + enable); + REG_WR(bp, params->port ? NIG_REG_P1_MAC_OUT_EN : NIG_REG_P0_MAC_OUT_EN, + enable); + REG_WR(bp, params->port ? NIG_REG_P1_MAC_PAUSE_OUT_EN : + NIG_REG_P0_MAC_PAUSE_OUT_EN, tx_pause_en); +} + +static void bnx2x_umac_enable(struct link_params *params, + struct link_vars *vars, u8 lb) +{ + u32 val; + u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0; + struct bnx2x *bp = params->bp; + /* Reset UMAC */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port)); + usleep_range(1000, 1000); + + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + (MISC_REGISTERS_RESET_REG_2_UMAC0 << params->port)); + + DP(NETIF_MSG_LINK, "enabling UMAC\n"); + + /** + * This register determines on which events the MAC will assert + * error on the i/f to the NIG along w/ EOP. + */ + + /** + * BD REG_WR(bp, NIG_REG_P0_MAC_RSV_ERR_MASK + + * params->port*0x14, 0xfffff. + */ + /* This register opens the gate for the UMAC despite its name */ + REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 1); + + val = UMAC_COMMAND_CONFIG_REG_PROMIS_EN | + UMAC_COMMAND_CONFIG_REG_PAD_EN | + UMAC_COMMAND_CONFIG_REG_SW_RESET | + UMAC_COMMAND_CONFIG_REG_NO_LGTH_CHECK; + switch (vars->line_speed) { + case SPEED_10: + val |= (0<<2); + break; + case SPEED_100: + val |= (1<<2); + break; + case SPEED_1000: + val |= (2<<2); + break; + case SPEED_2500: + val |= (3<<2); + break; + default: + DP(NETIF_MSG_LINK, "Invalid speed for UMAC %d\n", + vars->line_speed); + break; + } + if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) + val |= UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE; + + if (!(vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)) + val |= UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE; + + REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val); + udelay(50); + + /* Set MAC address for source TX Pause/PFC frames (under SW reset) */ + REG_WR(bp, umac_base + UMAC_REG_MAC_ADDR0, + ((params->mac_addr[2] << 24) | + (params->mac_addr[3] << 16) | + (params->mac_addr[4] << 8) | + (params->mac_addr[5]))); + REG_WR(bp, umac_base + UMAC_REG_MAC_ADDR1, + ((params->mac_addr[0] << 8) | + (params->mac_addr[1]))); + + /* Enable RX and TX */ + val &= ~UMAC_COMMAND_CONFIG_REG_PAD_EN; + val |= UMAC_COMMAND_CONFIG_REG_TX_ENA | + UMAC_COMMAND_CONFIG_REG_RX_ENA; + REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val); + udelay(50); + + /* Remove SW Reset */ + val &= ~UMAC_COMMAND_CONFIG_REG_SW_RESET; + + /* Check loopback mode */ + if (lb) + val |= UMAC_COMMAND_CONFIG_REG_LOOP_ENA; + REG_WR(bp, umac_base + UMAC_REG_COMMAND_CONFIG, val); + + /* + * Maximum Frame Length (RW). Defines a 14-Bit maximum frame + * length used by the MAC receive logic to check frames. + */ + REG_WR(bp, umac_base + UMAC_REG_MAXFR, 0x2710); + bnx2x_set_xumac_nig(params, + ((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1); + vars->mac_type = MAC_TYPE_UMAC; + +} + +static u8 bnx2x_is_4_port_mode(struct bnx2x *bp) +{ + u32 port4mode_ovwr_val; + /* Check 4-port override enabled */ + port4mode_ovwr_val = REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR); + if (port4mode_ovwr_val & (1<<0)) { + /* Return 4-port mode override value */ + return ((port4mode_ovwr_val & (1<<1)) == (1<<1)); + } + /* Return 4-port mode from input pin */ + return (u8)REG_RD(bp, MISC_REG_PORT4MODE_EN); +} + +/* Define the XMAC mode */ +static void bnx2x_xmac_init(struct bnx2x *bp, u32 max_speed) +{ + u32 is_port4mode = bnx2x_is_4_port_mode(bp); + + /** + * In 4-port mode, need to set the mode only once, so if XMAC is + * already out of reset, it means the mode has already been set, + * and it must not* reset the XMAC again, since it controls both + * ports of the path + **/ + + if (is_port4mode && (REG_RD(bp, MISC_REG_RESET_REG_2) & + MISC_REGISTERS_RESET_REG_2_XMAC)) { + DP(NETIF_MSG_LINK, "XMAC already out of reset" + " in 4-port mode\n"); + return; + } + + /* Hard reset */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + MISC_REGISTERS_RESET_REG_2_XMAC); + usleep_range(1000, 1000); + + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + MISC_REGISTERS_RESET_REG_2_XMAC); + if (is_port4mode) { + DP(NETIF_MSG_LINK, "Init XMAC to 2 ports x 10G per path\n"); + + /* Set the number of ports on the system side to up to 2 */ + REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 1); + + /* Set the number of ports on the Warp Core to 10G */ + REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3); + } else { + /* Set the number of ports on the system side to 1 */ + REG_WR(bp, MISC_REG_XMAC_CORE_PORT_MODE, 0); + if (max_speed == SPEED_10000) { + DP(NETIF_MSG_LINK, "Init XMAC to 10G x 1" + " port per path\n"); + /* Set the number of ports on the Warp Core to 10G */ + REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 3); + } else { + DP(NETIF_MSG_LINK, "Init XMAC to 20G x 2 ports" + " per path\n"); + /* Set the number of ports on the Warp Core to 20G */ + REG_WR(bp, MISC_REG_XMAC_PHY_PORT_MODE, 1); + } + } + /* Soft reset */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + MISC_REGISTERS_RESET_REG_2_XMAC_SOFT); + usleep_range(1000, 1000); + + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + MISC_REGISTERS_RESET_REG_2_XMAC_SOFT); + +} + +static void bnx2x_xmac_disable(struct link_params *params) +{ + u8 port = params->port; + struct bnx2x *bp = params->bp; + u32 pfc_ctrl, xmac_base = (port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; + + if (REG_RD(bp, MISC_REG_RESET_REG_2) & + MISC_REGISTERS_RESET_REG_2_XMAC) { + /* + * Send an indication to change the state in the NIG back to XON + * Clearing this bit enables the next set of this bit to get + * rising edge + */ + pfc_ctrl = REG_RD(bp, xmac_base + XMAC_REG_PFC_CTRL_HI); + REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, + (pfc_ctrl & ~(1<<1))); + REG_WR(bp, xmac_base + XMAC_REG_PFC_CTRL_HI, + (pfc_ctrl | (1<<1))); + DP(NETIF_MSG_LINK, "Disable XMAC on port %x\n", port); + REG_WR(bp, xmac_base + XMAC_REG_CTRL, 0); + usleep_range(1000, 1000); + bnx2x_set_xumac_nig(params, 0, 0); + REG_WR(bp, xmac_base + XMAC_REG_CTRL, + XMAC_CTRL_REG_SOFT_RESET); + } +} + +static int bnx2x_xmac_enable(struct link_params *params, + struct link_vars *vars, u8 lb) +{ + u32 val, xmac_base; + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "enabling XMAC\n"); + + xmac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; + + bnx2x_xmac_init(bp, vars->line_speed); + + /* + * This register determines on which events the MAC will assert + * error on the i/f to the NIG along w/ EOP. + */ + + /* + * This register tells the NIG whether to send traffic to UMAC + * or XMAC + */ + REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 0); + + /* Set Max packet size */ + REG_WR(bp, xmac_base + XMAC_REG_RX_MAX_SIZE, 0x2710); + + /* CRC append for Tx packets */ + REG_WR(bp, xmac_base + XMAC_REG_TX_CTRL, 0xC800); + + /* update PFC */ + bnx2x_update_pfc_xmac(params, vars, 0); + + /* Enable TX and RX */ + val = XMAC_CTRL_REG_TX_EN | XMAC_CTRL_REG_RX_EN; + + /* Check loopback mode */ + if (lb) + val |= XMAC_CTRL_REG_CORE_LOCAL_LPBK; + REG_WR(bp, xmac_base + XMAC_REG_CTRL, val); + bnx2x_set_xumac_nig(params, + ((vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) != 0), 1); + + vars->mac_type = MAC_TYPE_XMAC; + + return 0; +} +static int bnx2x_emac_enable(struct link_params *params, + struct link_vars *vars, u8 lb) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + u32 val; + + DP(NETIF_MSG_LINK, "enabling EMAC\n"); + + /* Disable BMAC */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + + /* enable emac and not bmac */ + REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 1); + + /* ASIC */ + if (vars->phy_flags & PHY_XGXS_FLAG) { + u32 ser_lane = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + + DP(NETIF_MSG_LINK, "XGXS\n"); + /* select the master lanes (out of 0-3) */ + REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, ser_lane); + /* select XGXS */ + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); + + } else { /* SerDes */ + DP(NETIF_MSG_LINK, "SerDes\n"); + /* select SerDes */ + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0); + } + + bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE, + EMAC_RX_MODE_RESET); + bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE, + EMAC_TX_MODE_RESET); + + if (CHIP_REV_IS_SLOW(bp)) { + /* config GMII mode */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + EMAC_WR(bp, EMAC_REG_EMAC_MODE, (val | EMAC_MODE_PORT_GMII)); + } else { /* ASIC */ + /* pause enable/disable */ + bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE, + EMAC_RX_MODE_FLOW_EN); + + bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE, + (EMAC_TX_MODE_EXT_PAUSE_EN | + EMAC_TX_MODE_FLOW_EN)); + if (!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED)) { + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) + bnx2x_bits_en(bp, emac_base + + EMAC_REG_EMAC_RX_MODE, + EMAC_RX_MODE_FLOW_EN); + + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) + bnx2x_bits_en(bp, emac_base + + EMAC_REG_EMAC_TX_MODE, + (EMAC_TX_MODE_EXT_PAUSE_EN | + EMAC_TX_MODE_FLOW_EN)); + } else + bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE, + EMAC_TX_MODE_FLOW_EN); + } + + /* KEEP_VLAN_TAG, promiscuous */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_RX_MODE); + val |= EMAC_RX_MODE_KEEP_VLAN_TAG | EMAC_RX_MODE_PROMISCUOUS; + + /* + * Setting this bit causes MAC control frames (except for pause + * frames) to be passed on for processing. This setting has no + * affect on the operation of the pause frames. This bit effects + * all packets regardless of RX Parser packet sorting logic. + * Turn the PFC off to make sure we are in Xon state before + * enabling it. + */ + EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, 0); + if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) { + DP(NETIF_MSG_LINK, "PFC is enabled\n"); + /* Enable PFC again */ + EMAC_WR(bp, EMAC_REG_RX_PFC_MODE, + EMAC_REG_RX_PFC_MODE_RX_EN | + EMAC_REG_RX_PFC_MODE_TX_EN | + EMAC_REG_RX_PFC_MODE_PRIORITIES); + + EMAC_WR(bp, EMAC_REG_RX_PFC_PARAM, + ((0x0101 << + EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT) | + (0x00ff << + EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT))); + val |= EMAC_RX_MODE_KEEP_MAC_CONTROL; + } + EMAC_WR(bp, EMAC_REG_EMAC_RX_MODE, val); + + /* Set Loopback */ + val = REG_RD(bp, emac_base + EMAC_REG_EMAC_MODE); + if (lb) + val |= 0x810; + else + val &= ~0x810; + EMAC_WR(bp, EMAC_REG_EMAC_MODE, val); + + /* enable emac */ + REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 1); + + /* enable emac for jumbo packets */ + EMAC_WR(bp, EMAC_REG_EMAC_RX_MTU_SIZE, + (EMAC_RX_MTU_SIZE_JUMBO_ENA | + (ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD))); + + /* strip CRC */ + REG_WR(bp, NIG_REG_NIG_INGRESS_EMAC0_NO_CRC + port*4, 0x1); + + /* disable the NIG in/out to the bmac */ + REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x0); + REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, 0x0); + REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x0); + + /* enable the NIG in/out to the emac */ + REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1); + val = 0; + if ((params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED) || + (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) + val = 1; + + REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val); + REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x1); + + REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x0); + + vars->mac_type = MAC_TYPE_EMAC; + return 0; +} + +static void bnx2x_update_pfc_bmac1(struct link_params *params, + struct link_vars *vars) +{ + u32 wb_data[2]; + struct bnx2x *bp = params->bp; + u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM; + + u32 val = 0x14; + if ((!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED)) && + (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)) + /* Enable BigMAC to react on received Pause packets */ + val |= (1<<5); + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_CONTROL, wb_data, 2); + + /* tx control */ + val = 0xc0; + if (!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED) && + (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) + val |= 0x800000; + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_CONTROL, wb_data, 2); +} + +static void bnx2x_update_pfc_bmac2(struct link_params *params, + struct link_vars *vars, + u8 is_lb) +{ + /* + * Set rx control: Strip CRC and enable BigMAC to relay + * control packets to the system as well + */ + u32 wb_data[2]; + struct bnx2x *bp = params->bp; + u32 bmac_addr = params->port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM; + u32 val = 0x14; + + if ((!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED)) && + (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX)) + /* Enable BigMAC to react on received Pause packets */ + val |= (1<<5); + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_CONTROL, wb_data, 2); + udelay(30); + + /* Tx control */ + val = 0xc0; + if (!(params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED) && + (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) + val |= 0x800000; + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_CONTROL, wb_data, 2); + + if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) { + DP(NETIF_MSG_LINK, "PFC is enabled\n"); + /* Enable PFC RX & TX & STATS and set 8 COS */ + wb_data[0] = 0x0; + wb_data[0] |= (1<<0); /* RX */ + wb_data[0] |= (1<<1); /* TX */ + wb_data[0] |= (1<<2); /* Force initial Xon */ + wb_data[0] |= (1<<3); /* 8 cos */ + wb_data[0] |= (1<<5); /* STATS */ + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, + wb_data, 2); + /* Clear the force Xon */ + wb_data[0] &= ~(1<<2); + } else { + DP(NETIF_MSG_LINK, "PFC is disabled\n"); + /* disable PFC RX & TX & STATS and set 8 COS */ + wb_data[0] = 0x8; + wb_data[1] = 0; + } + + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_PFC_CONTROL, wb_data, 2); + + /* + * Set Time (based unit is 512 bit time) between automatic + * re-sending of PP packets amd enable automatic re-send of + * Per-Priroity Packet as long as pp_gen is asserted and + * pp_disable is low. + */ + val = 0x8000; + if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) + val |= (1<<16); /* enable automatic re-send */ + + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_PAUSE_CONTROL, + wb_data, 2); + + /* mac control */ + val = 0x3; /* Enable RX and TX */ + if (is_lb) { + val |= 0x4; /* Local loopback */ + DP(NETIF_MSG_LINK, "enable bmac loopback\n"); + } + /* When PFC enabled, Pass pause frames towards the NIG. */ + if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) + val |= ((1<<6)|(1<<5)); + + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2); +} + + +/* PFC BRB internal port configuration params */ +struct bnx2x_pfc_brb_threshold_val { + u32 pause_xoff; + u32 pause_xon; + u32 full_xoff; + u32 full_xon; +}; + +struct bnx2x_pfc_brb_e3b0_val { + u32 full_lb_xoff_th; + u32 full_lb_xon_threshold; + u32 lb_guarantied; + u32 mac_0_class_t_guarantied; + u32 mac_0_class_t_guarantied_hyst; + u32 mac_1_class_t_guarantied; + u32 mac_1_class_t_guarantied_hyst; +}; + +struct bnx2x_pfc_brb_th_val { + struct bnx2x_pfc_brb_threshold_val pauseable_th; + struct bnx2x_pfc_brb_threshold_val non_pauseable_th; +}; +static int bnx2x_pfc_brb_get_config_params( + struct link_params *params, + struct bnx2x_pfc_brb_th_val *config_val) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "Setting PFC BRB configuration\n"); + if (CHIP_IS_E2(bp)) { + config_val->pauseable_th.pause_xoff = + PFC_E2_BRB_MAC_PAUSE_XOFF_THR_PAUSE; + config_val->pauseable_th.pause_xon = + PFC_E2_BRB_MAC_PAUSE_XON_THR_PAUSE; + config_val->pauseable_th.full_xoff = + PFC_E2_BRB_MAC_FULL_XOFF_THR_PAUSE; + config_val->pauseable_th.full_xon = + PFC_E2_BRB_MAC_FULL_XON_THR_PAUSE; + /* non pause able*/ + config_val->non_pauseable_th.pause_xoff = + PFC_E2_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE; + config_val->non_pauseable_th.pause_xon = + PFC_E2_BRB_MAC_PAUSE_XON_THR_NON_PAUSE; + config_val->non_pauseable_th.full_xoff = + PFC_E2_BRB_MAC_FULL_XOFF_THR_NON_PAUSE; + config_val->non_pauseable_th.full_xon = + PFC_E2_BRB_MAC_FULL_XON_THR_NON_PAUSE; + } else if (CHIP_IS_E3A0(bp)) { + config_val->pauseable_th.pause_xoff = + PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_PAUSE; + config_val->pauseable_th.pause_xon = + PFC_E3A0_BRB_MAC_PAUSE_XON_THR_PAUSE; + config_val->pauseable_th.full_xoff = + PFC_E3A0_BRB_MAC_FULL_XOFF_THR_PAUSE; + config_val->pauseable_th.full_xon = + PFC_E3A0_BRB_MAC_FULL_XON_THR_PAUSE; + /* non pause able*/ + config_val->non_pauseable_th.pause_xoff = + PFC_E3A0_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE; + config_val->non_pauseable_th.pause_xon = + PFC_E3A0_BRB_MAC_PAUSE_XON_THR_NON_PAUSE; + config_val->non_pauseable_th.full_xoff = + PFC_E3A0_BRB_MAC_FULL_XOFF_THR_NON_PAUSE; + config_val->non_pauseable_th.full_xon = + PFC_E3A0_BRB_MAC_FULL_XON_THR_NON_PAUSE; + } else if (CHIP_IS_E3B0(bp)) { + if (params->phy[INT_PHY].flags & + FLAGS_4_PORT_MODE) { + config_val->pauseable_th.pause_xoff = + PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_PAUSE; + config_val->pauseable_th.pause_xon = + PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_PAUSE; + config_val->pauseable_th.full_xoff = + PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_PAUSE; + config_val->pauseable_th.full_xon = + PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_PAUSE; + /* non pause able*/ + config_val->non_pauseable_th.pause_xoff = + PFC_E3B0_4P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE; + config_val->non_pauseable_th.pause_xon = + PFC_E3B0_4P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE; + config_val->non_pauseable_th.full_xoff = + PFC_E3B0_4P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE; + config_val->non_pauseable_th.full_xon = + PFC_E3B0_4P_BRB_MAC_FULL_XON_THR_NON_PAUSE; + } else { + config_val->pauseable_th.pause_xoff = + PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_PAUSE; + config_val->pauseable_th.pause_xon = + PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_PAUSE; + config_val->pauseable_th.full_xoff = + PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_PAUSE; + config_val->pauseable_th.full_xon = + PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_PAUSE; + /* non pause able*/ + config_val->non_pauseable_th.pause_xoff = + PFC_E3B0_2P_BRB_MAC_PAUSE_XOFF_THR_NON_PAUSE; + config_val->non_pauseable_th.pause_xon = + PFC_E3B0_2P_BRB_MAC_PAUSE_XON_THR_NON_PAUSE; + config_val->non_pauseable_th.full_xoff = + PFC_E3B0_2P_BRB_MAC_FULL_XOFF_THR_NON_PAUSE; + config_val->non_pauseable_th.full_xon = + PFC_E3B0_2P_BRB_MAC_FULL_XON_THR_NON_PAUSE; + } + } else + return -EINVAL; + + return 0; +} + + +static void bnx2x_pfc_brb_get_e3b0_config_params(struct link_params *params, + struct bnx2x_pfc_brb_e3b0_val + *e3b0_val, + u32 cos0_pauseable, + u32 cos1_pauseable) +{ + if (params->phy[INT_PHY].flags & FLAGS_4_PORT_MODE) { + e3b0_val->full_lb_xoff_th = + PFC_E3B0_4P_BRB_FULL_LB_XOFF_THR; + e3b0_val->full_lb_xon_threshold = + PFC_E3B0_4P_BRB_FULL_LB_XON_THR; + e3b0_val->lb_guarantied = + PFC_E3B0_4P_LB_GUART; + e3b0_val->mac_0_class_t_guarantied = + PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART; + e3b0_val->mac_0_class_t_guarantied_hyst = + PFC_E3B0_4P_BRB_MAC_0_CLASS_T_GUART_HYST; + e3b0_val->mac_1_class_t_guarantied = + PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART; + e3b0_val->mac_1_class_t_guarantied_hyst = + PFC_E3B0_4P_BRB_MAC_1_CLASS_T_GUART_HYST; + } else { + e3b0_val->full_lb_xoff_th = + PFC_E3B0_2P_BRB_FULL_LB_XOFF_THR; + e3b0_val->full_lb_xon_threshold = + PFC_E3B0_2P_BRB_FULL_LB_XON_THR; + e3b0_val->mac_0_class_t_guarantied_hyst = + PFC_E3B0_2P_BRB_MAC_0_CLASS_T_GUART_HYST; + e3b0_val->mac_1_class_t_guarantied = + PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART; + e3b0_val->mac_1_class_t_guarantied_hyst = + PFC_E3B0_2P_BRB_MAC_1_CLASS_T_GUART_HYST; + + if (cos0_pauseable != cos1_pauseable) { + /* nonpauseable= Lossy + pauseable = Lossless*/ + e3b0_val->lb_guarantied = + PFC_E3B0_2P_MIX_PAUSE_LB_GUART; + e3b0_val->mac_0_class_t_guarantied = + PFC_E3B0_2P_MIX_PAUSE_MAC_0_CLASS_T_GUART; + } else if (cos0_pauseable) { + /* Lossless +Lossless*/ + e3b0_val->lb_guarantied = + PFC_E3B0_2P_PAUSE_LB_GUART; + e3b0_val->mac_0_class_t_guarantied = + PFC_E3B0_2P_PAUSE_MAC_0_CLASS_T_GUART; + } else { + /* Lossy +Lossy*/ + e3b0_val->lb_guarantied = + PFC_E3B0_2P_NON_PAUSE_LB_GUART; + e3b0_val->mac_0_class_t_guarantied = + PFC_E3B0_2P_NON_PAUSE_MAC_0_CLASS_T_GUART; + } + } +} +static int bnx2x_update_pfc_brb(struct link_params *params, + struct link_vars *vars, + struct bnx2x_nig_brb_pfc_port_params + *pfc_params) +{ + struct bnx2x *bp = params->bp; + struct bnx2x_pfc_brb_th_val config_val = { {0} }; + struct bnx2x_pfc_brb_threshold_val *reg_th_config = + &config_val.pauseable_th; + struct bnx2x_pfc_brb_e3b0_val e3b0_val = {0}; + int set_pfc = params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED; + int bnx2x_status = 0; + u8 port = params->port; + + /* default - pause configuration */ + reg_th_config = &config_val.pauseable_th; + bnx2x_status = bnx2x_pfc_brb_get_config_params(params, &config_val); + if (0 != bnx2x_status) + return bnx2x_status; + + if (set_pfc && pfc_params) + /* First COS */ + if (!pfc_params->cos0_pauseable) + reg_th_config = &config_val.non_pauseable_th; + /* + * The number of free blocks below which the pause signal to class 0 + * of MAC #n is asserted. n=0,1 + */ + REG_WR(bp, (port) ? BRB1_REG_PAUSE_0_XOFF_THRESHOLD_1 : + BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 , + reg_th_config->pause_xoff); + /* + * The number of free blocks above which the pause signal to class 0 + * of MAC #n is de-asserted. n=0,1 + */ + REG_WR(bp, (port) ? BRB1_REG_PAUSE_0_XON_THRESHOLD_1 : + BRB1_REG_PAUSE_0_XON_THRESHOLD_0 , reg_th_config->pause_xon); + /* + * The number of free blocks below which the full signal to class 0 + * of MAC #n is asserted. n=0,1 + */ + REG_WR(bp, (port) ? BRB1_REG_FULL_0_XOFF_THRESHOLD_1 : + BRB1_REG_FULL_0_XOFF_THRESHOLD_0 , reg_th_config->full_xoff); + /* + * The number of free blocks above which the full signal to class 0 + * of MAC #n is de-asserted. n=0,1 + */ + REG_WR(bp, (port) ? BRB1_REG_FULL_0_XON_THRESHOLD_1 : + BRB1_REG_FULL_0_XON_THRESHOLD_0 , reg_th_config->full_xon); + + if (set_pfc && pfc_params) { + /* Second COS */ + if (pfc_params->cos1_pauseable) + reg_th_config = &config_val.pauseable_th; + else + reg_th_config = &config_val.non_pauseable_th; + /* + * The number of free blocks below which the pause signal to + * class 1 of MAC #n is asserted. n=0,1 + **/ + REG_WR(bp, (port) ? BRB1_REG_PAUSE_1_XOFF_THRESHOLD_1 : + BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0, + reg_th_config->pause_xoff); + /* + * The number of free blocks above which the pause signal to + * class 1 of MAC #n is de-asserted. n=0,1 + */ + REG_WR(bp, (port) ? BRB1_REG_PAUSE_1_XON_THRESHOLD_1 : + BRB1_REG_PAUSE_1_XON_THRESHOLD_0, + reg_th_config->pause_xon); + /* + * The number of free blocks below which the full signal to + * class 1 of MAC #n is asserted. n=0,1 + */ + REG_WR(bp, (port) ? BRB1_REG_FULL_1_XOFF_THRESHOLD_1 : + BRB1_REG_FULL_1_XOFF_THRESHOLD_0, + reg_th_config->full_xoff); + /* + * The number of free blocks above which the full signal to + * class 1 of MAC #n is de-asserted. n=0,1 + */ + REG_WR(bp, (port) ? BRB1_REG_FULL_1_XON_THRESHOLD_1 : + BRB1_REG_FULL_1_XON_THRESHOLD_0, + reg_th_config->full_xon); + + + if (CHIP_IS_E3B0(bp)) { + /*Should be done by init tool */ + /* + * BRB_empty_for_dup = BRB1_REG_BRB_EMPTY_THRESHOLD + * reset value + * 944 + */ + + /** + * The hysteresis on the guarantied buffer space for the Lb port + * before signaling XON. + **/ + REG_WR(bp, BRB1_REG_LB_GUARANTIED_HYST, 80); + + bnx2x_pfc_brb_get_e3b0_config_params( + params, + &e3b0_val, + pfc_params->cos0_pauseable, + pfc_params->cos1_pauseable); + /** + * The number of free blocks below which the full signal to the + * LB port is asserted. + */ + REG_WR(bp, BRB1_REG_FULL_LB_XOFF_THRESHOLD, + e3b0_val.full_lb_xoff_th); + /** + * The number of free blocks above which the full signal to the + * LB port is de-asserted. + */ + REG_WR(bp, BRB1_REG_FULL_LB_XON_THRESHOLD, + e3b0_val.full_lb_xon_threshold); + /** + * The number of blocks guarantied for the MAC #n port. n=0,1 + */ + + /*The number of blocks guarantied for the LB port.*/ + REG_WR(bp, BRB1_REG_LB_GUARANTIED, + e3b0_val.lb_guarantied); + + /** + * The number of blocks guarantied for the MAC #n port. + */ + REG_WR(bp, BRB1_REG_MAC_GUARANTIED_0, + 2 * e3b0_val.mac_0_class_t_guarantied); + REG_WR(bp, BRB1_REG_MAC_GUARANTIED_1, + 2 * e3b0_val.mac_1_class_t_guarantied); + /** + * The number of blocks guarantied for class #t in MAC0. t=0,1 + */ + REG_WR(bp, BRB1_REG_MAC_0_CLASS_0_GUARANTIED, + e3b0_val.mac_0_class_t_guarantied); + REG_WR(bp, BRB1_REG_MAC_0_CLASS_1_GUARANTIED, + e3b0_val.mac_0_class_t_guarantied); + /** + * The hysteresis on the guarantied buffer space for class in + * MAC0. t=0,1 + */ + REG_WR(bp, BRB1_REG_MAC_0_CLASS_0_GUARANTIED_HYST, + e3b0_val.mac_0_class_t_guarantied_hyst); + REG_WR(bp, BRB1_REG_MAC_0_CLASS_1_GUARANTIED_HYST, + e3b0_val.mac_0_class_t_guarantied_hyst); + + /** + * The number of blocks guarantied for class #t in MAC1.t=0,1 + */ + REG_WR(bp, BRB1_REG_MAC_1_CLASS_0_GUARANTIED, + e3b0_val.mac_1_class_t_guarantied); + REG_WR(bp, BRB1_REG_MAC_1_CLASS_1_GUARANTIED, + e3b0_val.mac_1_class_t_guarantied); + /** + * The hysteresis on the guarantied buffer space for class #t + * in MAC1. t=0,1 + */ + REG_WR(bp, BRB1_REG_MAC_1_CLASS_0_GUARANTIED_HYST, + e3b0_val.mac_1_class_t_guarantied_hyst); + REG_WR(bp, BRB1_REG_MAC_1_CLASS_1_GUARANTIED_HYST, + e3b0_val.mac_1_class_t_guarantied_hyst); + + } + + } + + return bnx2x_status; +} + +/****************************************************************************** +* Description: +* This function is needed because NIG ARB_CREDIT_WEIGHT_X are +* not continues and ARB_CREDIT_WEIGHT_0 + offset is suitable. +******************************************************************************/ +int bnx2x_pfc_nig_rx_priority_mask(struct bnx2x *bp, + u8 cos_entry, + u32 priority_mask, u8 port) +{ + u32 nig_reg_rx_priority_mask_add = 0; + + switch (cos_entry) { + case 0: + nig_reg_rx_priority_mask_add = (port) ? + NIG_REG_P1_RX_COS0_PRIORITY_MASK : + NIG_REG_P0_RX_COS0_PRIORITY_MASK; + break; + case 1: + nig_reg_rx_priority_mask_add = (port) ? + NIG_REG_P1_RX_COS1_PRIORITY_MASK : + NIG_REG_P0_RX_COS1_PRIORITY_MASK; + break; + case 2: + nig_reg_rx_priority_mask_add = (port) ? + NIG_REG_P1_RX_COS2_PRIORITY_MASK : + NIG_REG_P0_RX_COS2_PRIORITY_MASK; + break; + case 3: + if (port) + return -EINVAL; + nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS3_PRIORITY_MASK; + break; + case 4: + if (port) + return -EINVAL; + nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS4_PRIORITY_MASK; + break; + case 5: + if (port) + return -EINVAL; + nig_reg_rx_priority_mask_add = NIG_REG_P0_RX_COS5_PRIORITY_MASK; + break; + } + + REG_WR(bp, nig_reg_rx_priority_mask_add, priority_mask); + + return 0; +} +static void bnx2x_update_mng(struct link_params *params, u32 link_status) +{ + struct bnx2x *bp = params->bp; + + REG_WR(bp, params->shmem_base + + offsetof(struct shmem_region, + port_mb[params->port].link_status), link_status); +} + +static void bnx2x_update_pfc_nig(struct link_params *params, + struct link_vars *vars, + struct bnx2x_nig_brb_pfc_port_params *nig_params) +{ + u32 xcm_mask = 0, ppp_enable = 0, pause_enable = 0, llfc_out_en = 0; + u32 llfc_enable = 0, xcm0_out_en = 0, p0_hwpfc_enable = 0; + u32 pkt_priority_to_cos = 0; + struct bnx2x *bp = params->bp; + u8 port = params->port; + + int set_pfc = params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED; + DP(NETIF_MSG_LINK, "updating pfc nig parameters\n"); + + /* + * When NIG_LLH0_XCM_MASK_REG_LLHX_XCM_MASK_BCN bit is set + * MAC control frames (that are not pause packets) + * will be forwarded to the XCM. + */ + xcm_mask = REG_RD(bp, + port ? NIG_REG_LLH1_XCM_MASK : + NIG_REG_LLH0_XCM_MASK); + /* + * nig params will override non PFC params, since it's possible to + * do transition from PFC to SAFC + */ + if (set_pfc) { + pause_enable = 0; + llfc_out_en = 0; + llfc_enable = 0; + if (CHIP_IS_E3(bp)) + ppp_enable = 0; + else + ppp_enable = 1; + xcm_mask &= ~(port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN : + NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN); + xcm0_out_en = 0; + p0_hwpfc_enable = 1; + } else { + if (nig_params) { + llfc_out_en = nig_params->llfc_out_en; + llfc_enable = nig_params->llfc_enable; + pause_enable = nig_params->pause_enable; + } else /*defaul non PFC mode - PAUSE */ + pause_enable = 1; + + xcm_mask |= (port ? NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN : + NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN); + xcm0_out_en = 1; + } + + if (CHIP_IS_E3(bp)) + REG_WR(bp, port ? NIG_REG_BRB1_PAUSE_IN_EN : + NIG_REG_BRB0_PAUSE_IN_EN, pause_enable); + REG_WR(bp, port ? NIG_REG_LLFC_OUT_EN_1 : + NIG_REG_LLFC_OUT_EN_0, llfc_out_en); + REG_WR(bp, port ? NIG_REG_LLFC_ENABLE_1 : + NIG_REG_LLFC_ENABLE_0, llfc_enable); + REG_WR(bp, port ? NIG_REG_PAUSE_ENABLE_1 : + NIG_REG_PAUSE_ENABLE_0, pause_enable); + + REG_WR(bp, port ? NIG_REG_PPP_ENABLE_1 : + NIG_REG_PPP_ENABLE_0, ppp_enable); + + REG_WR(bp, port ? NIG_REG_LLH1_XCM_MASK : + NIG_REG_LLH0_XCM_MASK, xcm_mask); + + REG_WR(bp, NIG_REG_LLFC_EGRESS_SRC_ENABLE_0, 0x7); + + /* output enable for RX_XCM # IF */ + REG_WR(bp, NIG_REG_XCM0_OUT_EN, xcm0_out_en); + + /* HW PFC TX enable */ + REG_WR(bp, NIG_REG_P0_HWPFC_ENABLE, p0_hwpfc_enable); + + if (nig_params) { + u8 i = 0; + pkt_priority_to_cos = nig_params->pkt_priority_to_cos; + + for (i = 0; i < nig_params->num_of_rx_cos_priority_mask; i++) + bnx2x_pfc_nig_rx_priority_mask(bp, i, + nig_params->rx_cos_priority_mask[i], port); + + REG_WR(bp, port ? NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 : + NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0, + nig_params->llfc_high_priority_classes); + + REG_WR(bp, port ? NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 : + NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0, + nig_params->llfc_low_priority_classes); + } + REG_WR(bp, port ? NIG_REG_P1_PKT_PRIORITY_TO_COS : + NIG_REG_P0_PKT_PRIORITY_TO_COS, + pkt_priority_to_cos); +} + +int bnx2x_update_pfc(struct link_params *params, + struct link_vars *vars, + struct bnx2x_nig_brb_pfc_port_params *pfc_params) +{ + /* + * The PFC and pause are orthogonal to one another, meaning when + * PFC is enabled, the pause are disabled, and when PFC is + * disabled, pause are set according to the pause result. + */ + u32 val; + struct bnx2x *bp = params->bp; + int bnx2x_status = 0; + u8 bmac_loopback = (params->loopback_mode == LOOPBACK_BMAC); + + if (params->feature_config_flags & FEATURE_CONFIG_PFC_ENABLED) + vars->link_status |= LINK_STATUS_PFC_ENABLED; + else + vars->link_status &= ~LINK_STATUS_PFC_ENABLED; + + bnx2x_update_mng(params, vars->link_status); + + /* update NIG params */ + bnx2x_update_pfc_nig(params, vars, pfc_params); + + /* update BRB params */ + bnx2x_status = bnx2x_update_pfc_brb(params, vars, pfc_params); + if (0 != bnx2x_status) + return bnx2x_status; + + if (!vars->link_up) + return bnx2x_status; + + DP(NETIF_MSG_LINK, "About to update PFC in BMAC\n"); + if (CHIP_IS_E3(bp)) + bnx2x_update_pfc_xmac(params, vars, 0); + else { + val = REG_RD(bp, MISC_REG_RESET_REG_2); + if ((val & + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) + == 0) { + DP(NETIF_MSG_LINK, "About to update PFC in EMAC\n"); + bnx2x_emac_enable(params, vars, 0); + return bnx2x_status; + } + + if (CHIP_IS_E2(bp)) + bnx2x_update_pfc_bmac2(params, vars, bmac_loopback); + else + bnx2x_update_pfc_bmac1(params, vars); + + val = 0; + if ((params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED) || + (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) + val = 1; + REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val); + } + return bnx2x_status; +} + + +static int bnx2x_bmac1_enable(struct link_params *params, + struct link_vars *vars, + u8 is_lb) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM; + u32 wb_data[2]; + u32 val; + + DP(NETIF_MSG_LINK, "Enabling BigMAC1\n"); + + /* XGXS control */ + wb_data[0] = 0x3c; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_XGXS_CONTROL, + wb_data, 2); + + /* tx MAC SA */ + wb_data[0] = ((params->mac_addr[2] << 24) | + (params->mac_addr[3] << 16) | + (params->mac_addr[4] << 8) | + params->mac_addr[5]); + wb_data[1] = ((params->mac_addr[0] << 8) | + params->mac_addr[1]); + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_SOURCE_ADDR, wb_data, 2); + + /* mac control */ + val = 0x3; + if (is_lb) { + val |= 0x4; + DP(NETIF_MSG_LINK, "enable bmac loopback\n"); + } + wb_data[0] = val; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_BMAC_CONTROL, wb_data, 2); + + /* set rx mtu */ + wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_MAX_SIZE, wb_data, 2); + + bnx2x_update_pfc_bmac1(params, vars); + + /* set tx mtu */ + wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_TX_MAX_SIZE, wb_data, 2); + + /* set cnt max size */ + wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_CNT_MAX_SIZE, wb_data, 2); + + /* configure safc */ + wb_data[0] = 0x1000200; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC_REGISTER_RX_LLFC_MSG_FLDS, + wb_data, 2); + + return 0; +} + +static int bnx2x_bmac2_enable(struct link_params *params, + struct link_vars *vars, + u8 is_lb) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM; + u32 wb_data[2]; + + DP(NETIF_MSG_LINK, "Enabling BigMAC2\n"); + + wb_data[0] = 0; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_CONTROL, wb_data, 2); + udelay(30); + + /* XGXS control: Reset phy HW, MDIO registers, PHY PLL and BMAC */ + wb_data[0] = 0x3c; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_BMAC_XGXS_CONTROL, + wb_data, 2); + + udelay(30); + + /* tx MAC SA */ + wb_data[0] = ((params->mac_addr[2] << 24) | + (params->mac_addr[3] << 16) | + (params->mac_addr[4] << 8) | + params->mac_addr[5]); + wb_data[1] = ((params->mac_addr[0] << 8) | + params->mac_addr[1]); + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_SOURCE_ADDR, + wb_data, 2); + + udelay(30); + + /* Configure SAFC */ + wb_data[0] = 0x1000200; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS, + wb_data, 2); + udelay(30); + + /* set rx mtu */ + wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_RX_MAX_SIZE, wb_data, 2); + udelay(30); + + /* set tx mtu */ + wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_TX_MAX_SIZE, wb_data, 2); + udelay(30); + /* set cnt max size */ + wb_data[0] = ETH_MAX_JUMBO_PACKET_SIZE + ETH_OVREHEAD - 2; + wb_data[1] = 0; + REG_WR_DMAE(bp, bmac_addr + BIGMAC2_REGISTER_CNT_MAX_SIZE, wb_data, 2); + udelay(30); + bnx2x_update_pfc_bmac2(params, vars, is_lb); + + return 0; +} + +static int bnx2x_bmac_enable(struct link_params *params, + struct link_vars *vars, + u8 is_lb) +{ + int rc = 0; + u8 port = params->port; + struct bnx2x *bp = params->bp; + u32 val; + /* reset and unreset the BigMac */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + msleep(1); + + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + + /* enable access for bmac registers */ + REG_WR(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4, 0x1); + + /* Enable BMAC according to BMAC type*/ + if (CHIP_IS_E2(bp)) + rc = bnx2x_bmac2_enable(params, vars, is_lb); + else + rc = bnx2x_bmac1_enable(params, vars, is_lb); + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 0x1); + REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0); + REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0); + val = 0; + if ((params->feature_config_flags & + FEATURE_CONFIG_PFC_ENABLED) || + (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX)) + val = 1; + REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val); + REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0); + REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x0); + REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, 0x0); + REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0x1); + REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0x1); + + vars->mac_type = MAC_TYPE_BMAC; + return rc; +} + +static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port) +{ + u32 bmac_addr = port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM; + u32 wb_data[2]; + u32 nig_bmac_enable = REG_RD(bp, NIG_REG_BMAC0_REGS_OUT_EN + port*4); + + /* Only if the bmac is out of reset */ + if (REG_RD(bp, MISC_REG_RESET_REG_2) & + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port) && + nig_bmac_enable) { + + if (CHIP_IS_E2(bp)) { + /* Clear Rx Enable bit in BMAC_CONTROL register */ + REG_RD_DMAE(bp, bmac_addr + + BIGMAC2_REGISTER_BMAC_CONTROL, + wb_data, 2); + wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE; + REG_WR_DMAE(bp, bmac_addr + + BIGMAC2_REGISTER_BMAC_CONTROL, + wb_data, 2); + } else { + /* Clear Rx Enable bit in BMAC_CONTROL register */ + REG_RD_DMAE(bp, bmac_addr + + BIGMAC_REGISTER_BMAC_CONTROL, + wb_data, 2); + wb_data[0] &= ~BMAC_CONTROL_RX_ENABLE; + REG_WR_DMAE(bp, bmac_addr + + BIGMAC_REGISTER_BMAC_CONTROL, + wb_data, 2); + } + msleep(1); + } +} + +static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, + u32 line_speed) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u32 init_crd, crd; + u32 count = 1000; + + /* disable port */ + REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x1); + + /* wait for init credit */ + init_crd = REG_RD(bp, PBF_REG_P0_INIT_CRD + port*4); + crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); + DP(NETIF_MSG_LINK, "init_crd 0x%x crd 0x%x\n", init_crd, crd); + + while ((init_crd != crd) && count) { + msleep(5); + + crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); + count--; + } + crd = REG_RD(bp, PBF_REG_P0_CREDIT + port*8); + if (init_crd != crd) { + DP(NETIF_MSG_LINK, "BUG! init_crd 0x%x != crd 0x%x\n", + init_crd, crd); + return -EINVAL; + } + + if (flow_ctrl & BNX2X_FLOW_CTRL_RX || + line_speed == SPEED_10 || + line_speed == SPEED_100 || + line_speed == SPEED_1000 || + line_speed == SPEED_2500) { + REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 1); + /* update threshold */ + REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, 0); + /* update init credit */ + init_crd = 778; /* (800-18-4) */ + + } else { + u32 thresh = (ETH_MAX_JUMBO_PACKET_SIZE + + ETH_OVREHEAD)/16; + REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0); + /* update threshold */ + REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, thresh); + /* update init credit */ + switch (line_speed) { + case SPEED_10000: + init_crd = thresh + 553 - 22; + break; + default: + DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", + line_speed); + return -EINVAL; + } + } + REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, init_crd); + DP(NETIF_MSG_LINK, "PBF updated to speed %d credit %d\n", + line_speed, init_crd); + + /* probe the credit changes */ + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x1); + msleep(5); + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0x0); + + /* enable port */ + REG_WR(bp, PBF_REG_DISABLE_NEW_TASK_PROC_P0 + port*4, 0x0); + return 0; +} + +/** + * bnx2x_get_emac_base - retrive emac base address + * + * @bp: driver handle + * @mdc_mdio_access: access type + * @port: port id + * + * This function selects the MDC/MDIO access (through emac0 or + * emac1) depend on the mdc_mdio_access, port, port swapped. Each + * phy has a default access mode, which could also be overridden + * by nvram configuration. This parameter, whether this is the + * default phy configuration, or the nvram overrun + * configuration, is passed here as mdc_mdio_access and selects + * the emac_base for the CL45 read/writes operations + */ +static u32 bnx2x_get_emac_base(struct bnx2x *bp, + u32 mdc_mdio_access, u8 port) +{ + u32 emac_base = 0; + switch (mdc_mdio_access) { + case SHARED_HW_CFG_MDC_MDIO_ACCESS1_PHY_TYPE: + break; + case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC0: + if (REG_RD(bp, NIG_REG_PORT_SWAP)) + emac_base = GRCBASE_EMAC1; + else + emac_base = GRCBASE_EMAC0; + break; + case SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1: + if (REG_RD(bp, NIG_REG_PORT_SWAP)) + emac_base = GRCBASE_EMAC0; + else + emac_base = GRCBASE_EMAC1; + break; + case SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH: + emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + break; + case SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED: + emac_base = (port) ? GRCBASE_EMAC0 : GRCBASE_EMAC1; + break; + default: + break; + } + return emac_base; + +} + +/******************************************************************/ +/* CL22 access functions */ +/******************************************************************/ +static int bnx2x_cl22_write(struct bnx2x *bp, + struct bnx2x_phy *phy, + u16 reg, u16 val) +{ + u32 tmp, mode; + u8 i; + int rc = 0; + /* Switch to CL22 */ + mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, + mode & ~EMAC_MDIO_MODE_CLAUSE_45); + + /* address */ + tmp = ((phy->addr << 21) | (reg << 16) | val | + EMAC_MDIO_COMM_COMMAND_WRITE_22 | + EMAC_MDIO_COMM_START_BUSY); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp); + + for (i = 0; i < 50; i++) { + udelay(10); + + tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); + if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); + break; + } + } + if (tmp & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "write phy register failed\n"); + rc = -EFAULT; + } + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, mode); + return rc; +} + +static int bnx2x_cl22_read(struct bnx2x *bp, + struct bnx2x_phy *phy, + u16 reg, u16 *ret_val) +{ + u32 val, mode; + u16 i; + int rc = 0; + + /* Switch to CL22 */ + mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, + mode & ~EMAC_MDIO_MODE_CLAUSE_45); + + /* address */ + val = ((phy->addr << 21) | (reg << 16) | + EMAC_MDIO_COMM_COMMAND_READ_22 | + EMAC_MDIO_COMM_START_BUSY); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val); + + for (i = 0; i < 50; i++) { + udelay(10); + + val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); + if (!(val & EMAC_MDIO_COMM_START_BUSY)) { + *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA); + udelay(5); + break; + } + } + if (val & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "read phy register failed\n"); + + *ret_val = 0; + rc = -EFAULT; + } + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, mode); + return rc; +} + +/******************************************************************/ +/* CL45 access functions */ +/******************************************************************/ +static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy, + u8 devad, u16 reg, u16 *ret_val) +{ + u32 val; + u16 i; + int rc = 0; + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); + /* address */ + val = ((phy->addr << 21) | (devad << 16) | reg | + EMAC_MDIO_COMM_COMMAND_ADDRESS | + EMAC_MDIO_COMM_START_BUSY); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val); + + for (i = 0; i < 50; i++) { + udelay(10); + + val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); + if (!(val & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); + break; + } + } + if (val & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "read phy register failed\n"); + netdev_err(bp->dev, "MDC/MDIO access timeout\n"); + *ret_val = 0; + rc = -EFAULT; + } else { + /* data */ + val = ((phy->addr << 21) | (devad << 16) | + EMAC_MDIO_COMM_COMMAND_READ_45 | + EMAC_MDIO_COMM_START_BUSY); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val); + + for (i = 0; i < 50; i++) { + udelay(10); + + val = REG_RD(bp, phy->mdio_ctrl + + EMAC_REG_EMAC_MDIO_COMM); + if (!(val & EMAC_MDIO_COMM_START_BUSY)) { + *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA); + break; + } + } + if (val & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "read phy register failed\n"); + netdev_err(bp->dev, "MDC/MDIO access timeout\n"); + *ret_val = 0; + rc = -EFAULT; + } + } + /* Work around for E3 A0 */ + if (phy->flags & FLAGS_MDC_MDIO_WA) { + phy->flags ^= FLAGS_DUMMY_READ; + if (phy->flags & FLAGS_DUMMY_READ) { + u16 temp_val; + bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val); + } + } + + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); + return rc; +} + +static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy, + u8 devad, u16 reg, u16 val) +{ + u32 tmp; + u8 i; + int rc = 0; + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_en(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); + + /* address */ + + tmp = ((phy->addr << 21) | (devad << 16) | reg | + EMAC_MDIO_COMM_COMMAND_ADDRESS | + EMAC_MDIO_COMM_START_BUSY); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp); + + for (i = 0; i < 50; i++) { + udelay(10); + + tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM); + if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); + break; + } + } + if (tmp & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "write phy register failed\n"); + netdev_err(bp->dev, "MDC/MDIO access timeout\n"); + rc = -EFAULT; + + } else { + /* data */ + tmp = ((phy->addr << 21) | (devad << 16) | val | + EMAC_MDIO_COMM_COMMAND_WRITE_45 | + EMAC_MDIO_COMM_START_BUSY); + REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp); + + for (i = 0; i < 50; i++) { + udelay(10); + + tmp = REG_RD(bp, phy->mdio_ctrl + + EMAC_REG_EMAC_MDIO_COMM); + if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) { + udelay(5); + break; + } + } + if (tmp & EMAC_MDIO_COMM_START_BUSY) { + DP(NETIF_MSG_LINK, "write phy register failed\n"); + netdev_err(bp->dev, "MDC/MDIO access timeout\n"); + rc = -EFAULT; + } + } + /* Work around for E3 A0 */ + if (phy->flags & FLAGS_MDC_MDIO_WA) { + phy->flags ^= FLAGS_DUMMY_READ; + if (phy->flags & FLAGS_DUMMY_READ) { + u16 temp_val; + bnx2x_cl45_read(bp, phy, devad, 0xf, &temp_val); + } + } + if (phy->flags & FLAGS_MDC_MDIO_WA_B0) + bnx2x_bits_dis(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_STATUS, + EMAC_MDIO_STATUS_10MB); + return rc; +} + + +/******************************************************************/ +/* BSC access functions from E3 */ +/******************************************************************/ +static void bnx2x_bsc_module_sel(struct link_params *params) +{ + int idx; + u32 board_cfg, sfp_ctrl; + u32 i2c_pins[I2C_SWITCH_WIDTH], i2c_val[I2C_SWITCH_WIDTH]; + struct bnx2x *bp = params->bp; + u8 port = params->port; + /* Read I2C output PINs */ + board_cfg = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.shared_hw_config.board)); + i2c_pins[I2C_BSC0] = board_cfg & SHARED_HW_CFG_E3_I2C_MUX0_MASK; + i2c_pins[I2C_BSC1] = (board_cfg & SHARED_HW_CFG_E3_I2C_MUX1_MASK) >> + SHARED_HW_CFG_E3_I2C_MUX1_SHIFT; + + /* Read I2C output value */ + sfp_ctrl = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].e3_cmn_pin_cfg)); + i2c_val[I2C_BSC0] = (sfp_ctrl & PORT_HW_CFG_E3_I2C_MUX0_MASK) > 0; + i2c_val[I2C_BSC1] = (sfp_ctrl & PORT_HW_CFG_E3_I2C_MUX1_MASK) > 0; + DP(NETIF_MSG_LINK, "Setting BSC switch\n"); + for (idx = 0; idx < I2C_SWITCH_WIDTH; idx++) + bnx2x_set_cfg_pin(bp, i2c_pins[idx], i2c_val[idx]); +} + +static int bnx2x_bsc_read(struct link_params *params, + struct bnx2x_phy *phy, + u8 sl_devid, + u16 sl_addr, + u8 lc_addr, + u8 xfer_cnt, + u32 *data_array) +{ + u32 val, i; + int rc = 0; + struct bnx2x *bp = params->bp; + + if ((sl_devid != 0xa0) && (sl_devid != 0xa2)) { + DP(NETIF_MSG_LINK, "invalid sl_devid 0x%x\n", sl_devid); + return -EINVAL; + } + + if (xfer_cnt > 16) { + DP(NETIF_MSG_LINK, "invalid xfer_cnt %d. Max is 16 bytes\n", + xfer_cnt); + return -EINVAL; + } + bnx2x_bsc_module_sel(params); + + xfer_cnt = 16 - lc_addr; + + /* enable the engine */ + val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND); + val |= MCPR_IMC_COMMAND_ENABLE; + REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val); + + /* program slave device ID */ + val = (sl_devid << 16) | sl_addr; + REG_WR(bp, MCP_REG_MCPR_IMC_SLAVE_CONTROL, val); + + /* start xfer with 0 byte to update the address pointer ???*/ + val = (MCPR_IMC_COMMAND_ENABLE) | + (MCPR_IMC_COMMAND_WRITE_OP << + MCPR_IMC_COMMAND_OPERATION_BITSHIFT) | + (lc_addr << MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT) | (0); + REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val); + + /* poll for completion */ + i = 0; + val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND); + while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) { + udelay(10); + val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND); + if (i++ > 1000) { + DP(NETIF_MSG_LINK, "wr 0 byte timed out after %d try\n", + i); + rc = -EFAULT; + break; + } + } + if (rc == -EFAULT) + return rc; + + /* start xfer with read op */ + val = (MCPR_IMC_COMMAND_ENABLE) | + (MCPR_IMC_COMMAND_READ_OP << + MCPR_IMC_COMMAND_OPERATION_BITSHIFT) | + (lc_addr << MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT) | + (xfer_cnt); + REG_WR(bp, MCP_REG_MCPR_IMC_COMMAND, val); + + /* poll for completion */ + i = 0; + val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND); + while (((val >> MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT) & 0x3) != 1) { + udelay(10); + val = REG_RD(bp, MCP_REG_MCPR_IMC_COMMAND); + if (i++ > 1000) { + DP(NETIF_MSG_LINK, "rd op timed out after %d try\n", i); + rc = -EFAULT; + break; + } + } + if (rc == -EFAULT) + return rc; + + for (i = (lc_addr >> 2); i < 4; i++) { + data_array[i] = REG_RD(bp, (MCP_REG_MCPR_IMC_DATAREG0 + i*4)); +#ifdef __BIG_ENDIAN + data_array[i] = ((data_array[i] & 0x000000ff) << 24) | + ((data_array[i] & 0x0000ff00) << 8) | + ((data_array[i] & 0x00ff0000) >> 8) | + ((data_array[i] & 0xff000000) >> 24); +#endif + } + return rc; +} + +static void bnx2x_cl45_read_or_write(struct bnx2x *bp, struct bnx2x_phy *phy, + u8 devad, u16 reg, u16 or_val) +{ + u16 val; + bnx2x_cl45_read(bp, phy, devad, reg, &val); + bnx2x_cl45_write(bp, phy, devad, reg, val | or_val); +} + +int bnx2x_phy_read(struct link_params *params, u8 phy_addr, + u8 devad, u16 reg, u16 *ret_val) +{ + u8 phy_index; + /* + * Probe for the phy according to the given phy_addr, and execute + * the read request on it + */ + for (phy_index = 0; phy_index < params->num_phys; phy_index++) { + if (params->phy[phy_index].addr == phy_addr) { + return bnx2x_cl45_read(params->bp, + ¶ms->phy[phy_index], devad, + reg, ret_val); + } + } + return -EINVAL; +} + +int bnx2x_phy_write(struct link_params *params, u8 phy_addr, + u8 devad, u16 reg, u16 val) +{ + u8 phy_index; + /* + * Probe for the phy according to the given phy_addr, and execute + * the write request on it + */ + for (phy_index = 0; phy_index < params->num_phys; phy_index++) { + if (params->phy[phy_index].addr == phy_addr) { + return bnx2x_cl45_write(params->bp, + ¶ms->phy[phy_index], devad, + reg, val); + } + } + return -EINVAL; +} +static u8 bnx2x_get_warpcore_lane(struct bnx2x_phy *phy, + struct link_params *params) +{ + u8 lane = 0; + struct bnx2x *bp = params->bp; + u32 path_swap, path_swap_ovr; + u8 path, port; + + path = BP_PATH(bp); + port = params->port; + + if (bnx2x_is_4_port_mode(bp)) { + u32 port_swap, port_swap_ovr; + + /*figure out path swap value */ + path_swap_ovr = REG_RD(bp, MISC_REG_FOUR_PORT_PATH_SWAP_OVWR); + if (path_swap_ovr & 0x1) + path_swap = (path_swap_ovr & 0x2); + else + path_swap = REG_RD(bp, MISC_REG_FOUR_PORT_PATH_SWAP); + + if (path_swap) + path = path ^ 1; + + /*figure out port swap value */ + port_swap_ovr = REG_RD(bp, MISC_REG_FOUR_PORT_PORT_SWAP_OVWR); + if (port_swap_ovr & 0x1) + port_swap = (port_swap_ovr & 0x2); + else + port_swap = REG_RD(bp, MISC_REG_FOUR_PORT_PORT_SWAP); + + if (port_swap) + port = port ^ 1; + + lane = (port<<1) + path; + } else { /* two port mode - no port swap */ + + /*figure out path swap value */ + path_swap_ovr = + REG_RD(bp, MISC_REG_TWO_PORT_PATH_SWAP_OVWR); + if (path_swap_ovr & 0x1) { + path_swap = (path_swap_ovr & 0x2); + } else { + path_swap = + REG_RD(bp, MISC_REG_TWO_PORT_PATH_SWAP); + } + if (path_swap) + path = path ^ 1; + + lane = path << 1 ; + } + return lane; +} + +static void bnx2x_set_aer_mmd(struct link_params *params, + struct bnx2x_phy *phy) +{ + u32 ser_lane; + u16 offset, aer_val; + struct bnx2x *bp = params->bp; + ser_lane = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + + offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ? + (phy->addr + ser_lane) : 0; + + if (USES_WARPCORE(bp)) { + aer_val = bnx2x_get_warpcore_lane(phy, params); + /* + * In Dual-lane mode, two lanes are joined together, + * so in order to configure them, the AER broadcast method is + * used here. + * 0x200 is the broadcast address for lanes 0,1 + * 0x201 is the broadcast address for lanes 2,3 + */ + if (phy->flags & FLAGS_WC_DUAL_MODE) + aer_val = (aer_val >> 1) | 0x200; + } else if (CHIP_IS_E2(bp)) + aer_val = 0x3800 + offset - 1; + else + aer_val = 0x3800 + offset; + DP(NETIF_MSG_LINK, "Set AER to 0x%x\n", aer_val); + CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK, + MDIO_AER_BLOCK_AER_REG, aer_val); + +} + +/******************************************************************/ +/* Internal phy section */ +/******************************************************************/ + +static void bnx2x_set_serdes_access(struct bnx2x *bp, u8 port) +{ + u32 emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + + /* Set Clause 22 */ + REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 1); + REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245f8000); + udelay(500); + REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_COMM, 0x245d000f); + udelay(500); + /* Set Clause 45 */ + REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_ST + port*0x10, 0); +} + +static void bnx2x_serdes_deassert(struct bnx2x *bp, u8 port) +{ + u32 val; + + DP(NETIF_MSG_LINK, "bnx2x_serdes_deassert\n"); + + val = SERDES_RESET_BITS << (port*16); + + /* reset and unreset the SerDes/XGXS */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val); + udelay(500); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val); + + bnx2x_set_serdes_access(bp, port); + + REG_WR(bp, NIG_REG_SERDES0_CTRL_MD_DEVAD + port*0x10, + DEFAULT_PHY_DEV_ADDR); +} + +static void bnx2x_xgxs_deassert(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 port; + u32 val; + DP(NETIF_MSG_LINK, "bnx2x_xgxs_deassert\n"); + port = params->port; + + val = XGXS_RESET_BITS << (port*16); + + /* reset and unreset the SerDes/XGXS */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, val); + udelay(500); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_SET, val); + + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_ST + port*0x18, 0); + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, + params->phy[INT_PHY].def_md_devad); +} + +static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy, + struct link_params *params, u16 *ieee_fc) +{ + struct bnx2x *bp = params->bp; + *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX; + /** + * resolve pause mode and advertisement Please refer to Table + * 28B-3 of the 802.3ab-1999 spec + */ + + switch (phy->req_flow_ctrl) { + case BNX2X_FLOW_CTRL_AUTO: + if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) + *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; + else + *ieee_fc |= + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; + break; + + case BNX2X_FLOW_CTRL_TX: + *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; + break; + + case BNX2X_FLOW_CTRL_RX: + case BNX2X_FLOW_CTRL_BOTH: + *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; + break; + + case BNX2X_FLOW_CTRL_NONE: + default: + *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE; + break; + } + DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc); +} + +static void set_phy_vars(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 actual_phy_idx, phy_index, link_cfg_idx; + u8 phy_config_swapped = params->multi_phy_config & + PORT_HW_CFG_PHY_SWAPPED_ENABLED; + for (phy_index = INT_PHY; phy_index < params->num_phys; + phy_index++) { + link_cfg_idx = LINK_CONFIG_IDX(phy_index); + actual_phy_idx = phy_index; + if (phy_config_swapped) { + if (phy_index == EXT_PHY1) + actual_phy_idx = EXT_PHY2; + else if (phy_index == EXT_PHY2) + actual_phy_idx = EXT_PHY1; + } + params->phy[actual_phy_idx].req_flow_ctrl = + params->req_flow_ctrl[link_cfg_idx]; + + params->phy[actual_phy_idx].req_line_speed = + params->req_line_speed[link_cfg_idx]; + + params->phy[actual_phy_idx].speed_cap_mask = + params->speed_cap_mask[link_cfg_idx]; + + params->phy[actual_phy_idx].req_duplex = + params->req_duplex[link_cfg_idx]; + + if (params->req_line_speed[link_cfg_idx] == + SPEED_AUTO_NEG) + vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED; + + DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x," + " speed_cap_mask %x\n", + params->phy[actual_phy_idx].req_flow_ctrl, + params->phy[actual_phy_idx].req_line_speed, + params->phy[actual_phy_idx].speed_cap_mask); + } +} + +static void bnx2x_ext_phy_set_pause(struct link_params *params, + struct bnx2x_phy *phy, + struct link_vars *vars) +{ + u16 val; + struct bnx2x *bp = params->bp; + /* read modify write pause advertizing */ + bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val); + + val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH; + + /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */ + bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc); + if ((vars->ieee_fc & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) == + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) { + val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC; + } + if ((vars->ieee_fc & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) == + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) { + val |= MDIO_AN_REG_ADV_PAUSE_PAUSE; + } + DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val); + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val); +} + +static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result) +{ /* LD LP */ + switch (pause_result) { /* ASYM P ASYM P */ + case 0xb: /* 1 0 1 1 */ + vars->flow_ctrl = BNX2X_FLOW_CTRL_TX; + break; + + case 0xe: /* 1 1 1 0 */ + vars->flow_ctrl = BNX2X_FLOW_CTRL_RX; + break; + + case 0x5: /* 0 1 0 1 */ + case 0x7: /* 0 1 1 1 */ + case 0xd: /* 1 1 0 1 */ + case 0xf: /* 1 1 1 1 */ + vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH; + break; + + default: + break; + } + if (pause_result & (1<<0)) + vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE; + if (pause_result & (1<<1)) + vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE; +} + +static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 ld_pause; /* local */ + u16 lp_pause; /* link partner */ + u16 pause_result; + u8 ret = 0; + /* read twice */ + + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + + if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO) + vars->flow_ctrl = phy->req_flow_ctrl; + else if (phy->req_line_speed != SPEED_AUTO_NEG) + vars->flow_ctrl = params->req_fc_auto_adv; + else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) { + ret = 1; + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) { + bnx2x_cl22_read(bp, phy, + 0x4, &ld_pause); + bnx2x_cl22_read(bp, phy, + 0x5, &lp_pause); + } else { + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_ADV_PAUSE, &ld_pause); + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_LP_AUTO_NEG, &lp_pause); + } + pause_result = (ld_pause & + MDIO_AN_REG_ADV_PAUSE_MASK) >> 8; + pause_result |= (lp_pause & + MDIO_AN_REG_ADV_PAUSE_MASK) >> 10; + DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n", + pause_result); + bnx2x_pause_resolve(vars, pause_result); + } + return ret; +} +/******************************************************************/ +/* Warpcore section */ +/******************************************************************/ +/* The init_internal_warpcore should mirror the xgxs, + * i.e. reset the lane (if needed), set aer for the + * init configuration, and set/clear SGMII flag. Internal + * phy init is done purely in phy_init stage. + */ +static void bnx2x_warpcore_enable_AN_KR(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { + u16 val16 = 0, lane, bam37 = 0; + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "Enable Auto Negotiation for KR\n"); + /* Check adding advertisement for 1G KX */ + if (((vars->line_speed == SPEED_AUTO_NEG) && + (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) || + (vars->line_speed == SPEED_1000)) { + u16 sd_digital; + val16 |= (1<<5); + + /* Enable CL37 1G Parallel Detect */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &sd_digital); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, + (sd_digital | 0x1)); + + DP(NETIF_MSG_LINK, "Advertize 1G\n"); + } + if (((vars->line_speed == SPEED_AUTO_NEG) && + (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) || + (vars->line_speed == SPEED_10000)) { + /* Check adding advertisement for 10G KR */ + val16 |= (1<<7); + /* Enable 10G Parallel Detect */ + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, + MDIO_WC_REG_PAR_DET_10G_CTRL, 1); + + DP(NETIF_MSG_LINK, "Advertize 10G\n"); + } + + /* Set Transmit PMD settings */ + lane = bnx2x_get_warpcore_lane(phy, params); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane, + ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) | + (0x06 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) | + (0x09 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET))); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_CL72_USERB0_CL72_OS_DEF_CTRL, + 0x03f0); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_CL72_USERB0_CL72_2P5_DEF_CTRL, + 0x03f0); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, + 0x383f); + + /* Advertised speeds */ + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, + MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, val16); + + /* Enable CL37 BAM */ + if (REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_hw_config[params->port].default_cfg)) & + PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) { + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL6_MP5_NEXTPAGECTRL, &bam37); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL6_MP5_NEXTPAGECTRL, bam37 | 1); + DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n"); + } + + /* Advertise pause */ + bnx2x_ext_phy_set_pause(params, phy, vars); + + /* Enable Autoneg */ + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, + MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x1000); + + /* Over 1G - AN local device user page 1 */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL3_UP1, 0x1f); + + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL5_MISC7, &val16); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL5_MISC7, val16 | 0x100); +} + +static void bnx2x_warpcore_set_10G_KR(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 val; + + /* Disable Autoneg */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x7); + + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, + MDIO_WC_REG_PAR_DET_10G_CTRL, 0); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, 0x3f00); + + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, + MDIO_WC_REG_AN_IEEE1BLK_AN_ADVERTISEMENT1, 0); + + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, + MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL3_UP1, 0x1); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL5_MISC7, 0xa); + + /* Disable CL36 PCS Tx */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL0, 0x0); + + /* Double Wide Single Data Rate @ pll rate */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL1, 0xFFFF); + + /* Leave cl72 training enable, needed for KR */ + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, + MDIO_WC_REG_PMD_IEEE9BLK_TENGBASE_KR_PMD_CONTROL_REGISTER_150, + 0x2); + + /* Leave CL72 enabled */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, + &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_CL72_USERB0_CL72_MISC1_CONTROL, + val | 0x3800); + + /* Set speed via PMA/PMD register */ + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, + MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040); + + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, + MDIO_WC_REG_IEEE0BLK_AUTONEGNP, 0xB); + + /*Enable encoded forced speed */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_MISC2, 0x30); + + /* Turn TX scramble payload only the 64/66 scrambler */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_TX66_CONTROL, 0x9); + + /* Turn RX scramble payload only the 64/66 scrambler */ + bnx2x_cl45_read_or_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_CONTROL, 0xF9); + + /* set and clear loopback to cause a reset to 64/66 decoder */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x4000); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x0); + +} + +static void bnx2x_warpcore_set_10G_XFI(struct bnx2x_phy *phy, + struct link_params *params, + u8 is_xfi) +{ + struct bnx2x *bp = params->bp; + u16 misc1_val, tap_val, tx_driver_val, lane, val; + /* Hold rxSeqStart */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, (val | 0x8000)); + + /* Hold tx_fifo_reset */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, (val | 0x1)); + + /* Disable CL73 AN */ + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0); + + /* Disable 100FX Enable and Auto-Detect */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_FX100_CTRL1, &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_FX100_CTRL1, (val & 0xFFFA)); + + /* Disable 100FX Idle detect */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_FX100_CTRL3, &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_FX100_CTRL3, (val | 0x0080)); + + /* Set Block address to Remote PHY & Clear forced_speed[5] */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL4_MISC3, &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL4_MISC3, (val & 0xFF7F)); + + /* Turn off auto-detect & fiber mode */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, + (val & 0xFFEE)); + + /* Set filter_force_link, disable_false_link and parallel_detect */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, + ((val | 0x0006) & 0xFFFE)); + + /* Set XFI / SFI */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_MISC1, &misc1_val); + + misc1_val &= ~(0x1f); + + if (is_xfi) { + misc1_val |= 0x5; + tap_val = ((0x08 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) | + (0x37 << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) | + (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET)); + tx_driver_val = + ((0x00 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) | + (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) | + (0x03 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)); + + } else { + misc1_val |= 0x9; + tap_val = ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) | + (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) | + (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET)); + tx_driver_val = + ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) | + (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) | + (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET)); + } + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_MISC1, misc1_val); + + /* Set Transmit PMD settings */ + lane = bnx2x_get_warpcore_lane(phy, params); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_TX_FIR_TAP, + tap_val | MDIO_WC_REG_TX_FIR_TAP_ENABLE); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane, + tx_driver_val); + + /* Enable fiber mode, enable and invert sig_det */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, val | 0xd); + + /* Set Block address to Remote PHY & Set forced_speed[5], 40bit mode */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL4_MISC3, &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL4_MISC3, val | 0x8080); + + /* 10G XFI Full Duplex */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x100); + + /* Release tx_fifo_reset */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, val & 0xFFFE); + + /* Release rxSeqStart */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, &val); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DSC2B0_DSC_MISC_CTRL0, (val & 0x7FFF)); +} + +static void bnx2x_warpcore_set_20G_KR2(struct bnx2x *bp, + struct bnx2x_phy *phy) +{ + DP(NETIF_MSG_LINK, "KR2 still not supported !!!\n"); +} + +static void bnx2x_warpcore_set_20G_DXGXS(struct bnx2x *bp, + struct bnx2x_phy *phy, + u16 lane) +{ + /* Rx0 anaRxControl1G */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX0_ANARXCONTROL1G, 0x90); + + /* Rx2 anaRxControl1G */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX2_ANARXCONTROL1G, 0x90); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_SCW0, 0xE070); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_SCW1, 0xC0D0); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_SCW2, 0xA0B0); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_SCW3, 0x8090); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_SCW0_MASK, 0xF0F0); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_SCW1_MASK, 0xF0F0); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_SCW2_MASK, 0xF0F0); + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_SCW3_MASK, 0xF0F0); + + /* Serdes Digital Misc1 */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6008); + + /* Serdes Digital4 Misc3 */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL4_MISC3, 0x8088); + + /* Set Transmit PMD settings */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_TX_FIR_TAP, + ((0x12 << MDIO_WC_REG_TX_FIR_TAP_POST_TAP_OFFSET) | + (0x2d << MDIO_WC_REG_TX_FIR_TAP_MAIN_TAP_OFFSET) | + (0x00 << MDIO_WC_REG_TX_FIR_TAP_PRE_TAP_OFFSET) | + MDIO_WC_REG_TX_FIR_TAP_ENABLE)); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane, + ((0x02 << MDIO_WC_REG_TX0_TX_DRIVER_POST2_COEFF_OFFSET) | + (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IDRIVER_OFFSET) | + (0x02 << MDIO_WC_REG_TX0_TX_DRIVER_IPRE_DRIVER_OFFSET))); +} + +static void bnx2x_warpcore_set_sgmii_speed(struct bnx2x_phy *phy, + struct link_params *params, + u8 fiber_mode) +{ + struct bnx2x *bp = params->bp; + u16 val16, digctrl_kx1, digctrl_kx2; + u8 lane; + + lane = bnx2x_get_warpcore_lane(phy, params); + + /* Clear XFI clock comp in non-10G single lane mode. */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_CONTROL, &val16); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_CONTROL, val16 & ~(3<<13)); + + if (phy->req_line_speed == SPEED_AUTO_NEG) { + /* SGMII Autoneg */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_COMBO_IEEE0_MIICTRL, + val16 | 0x1000); + DP(NETIF_MSG_LINK, "set SGMII AUTONEG\n"); + } else { + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16); + val16 &= 0xcfbf; + switch (phy->req_line_speed) { + case SPEED_10: + break; + case SPEED_100: + val16 |= 0x2000; + break; + case SPEED_1000: + val16 |= 0x0040; + break; + default: + DP(NETIF_MSG_LINK, "Speed not supported: 0x%x" + "\n", phy->req_line_speed); + return; + } + + if (phy->req_duplex == DUPLEX_FULL) + val16 |= 0x0100; + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16); + + DP(NETIF_MSG_LINK, "set SGMII force speed %d\n", + phy->req_line_speed); + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16); + DP(NETIF_MSG_LINK, " (readback) %x\n", val16); + } + + /* SGMII Slave mode and disable signal detect */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, &digctrl_kx1); + if (fiber_mode) + digctrl_kx1 = 1; + else + digctrl_kx1 &= 0xff4a; + + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, + digctrl_kx1); + + /* Turn off parallel detect */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, &digctrl_kx2); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, + (digctrl_kx2 & ~(1<<2))); + + /* Re-enable parallel detect */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, + (digctrl_kx2 | (1<<2))); + + /* Enable autodet */ + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, + (digctrl_kx1 | 0x10)); +} + +static void bnx2x_warpcore_reset_lane(struct bnx2x *bp, + struct bnx2x_phy *phy, + u8 reset) +{ + u16 val; + /* Take lane out of reset after configuration is finished */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL5_MISC6, &val); + if (reset) + val |= 0xC000; + else + val &= 0x3FFF; + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL5_MISC6, val); + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL5_MISC6, &val); +} + + + /* Clear SFI/XFI link settings registers */ +static void bnx2x_warpcore_clear_regs(struct bnx2x_phy *phy, + struct link_params *params, + u16 lane) +{ + struct bnx2x *bp = params->bp; + u16 val16; + + /* Set XFI clock comp as default. */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_CONTROL, &val16); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_RX66_CONTROL, val16 | (3<<13)); + + bnx2x_warpcore_reset_lane(bp, phy, 1); + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_FX100_CTRL1, 0x014a); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_FX100_CTRL3, 0x0800); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_DIGITAL4_MISC3, 0x8008); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X1, 0x0195); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X2, 0x0007); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_CONTROL1000X3, 0x0002); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_SERDESDIGITAL_MISC1, 0x6000); + lane = bnx2x_get_warpcore_lane(phy, params); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_TX_FIR_TAP, 0x0000); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_TX0_TX_DRIVER + 0x10*lane, 0x0990); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_IEEE0BLK_MIICNTL, 0x2040); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_COMBO_IEEE0_MIICTRL, 0x0140); + bnx2x_warpcore_reset_lane(bp, phy, 0); +} + +static int bnx2x_get_mod_abs_int_cfg(struct bnx2x *bp, + u32 chip_id, + u32 shmem_base, u8 port, + u8 *gpio_num, u8 *gpio_port) +{ + u32 cfg_pin; + *gpio_num = 0; + *gpio_port = 0; + if (CHIP_IS_E3(bp)) { + cfg_pin = (REG_RD(bp, shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].e3_sfp_ctrl)) & + PORT_HW_CFG_E3_MOD_ABS_MASK) >> + PORT_HW_CFG_E3_MOD_ABS_SHIFT; + + /* + * Should not happen. This function called upon interrupt + * triggered by GPIO ( since EPIO can only generate interrupts + * to MCP). + * So if this function was called and none of the GPIOs was set, + * it means the shit hit the fan. + */ + if ((cfg_pin < PIN_CFG_GPIO0_P0) || + (cfg_pin > PIN_CFG_GPIO3_P1)) { + DP(NETIF_MSG_LINK, "ERROR: Invalid cfg pin %x for " + "module detect indication\n", + cfg_pin); + return -EINVAL; + } + + *gpio_num = (cfg_pin - PIN_CFG_GPIO0_P0) & 0x3; + *gpio_port = (cfg_pin - PIN_CFG_GPIO0_P0) >> 2; + } else { + *gpio_num = MISC_REGISTERS_GPIO_3; + *gpio_port = port; + } + DP(NETIF_MSG_LINK, "MOD_ABS int GPIO%d_P%d\n", *gpio_num, *gpio_port); + return 0; +} + +static int bnx2x_is_sfp_module_plugged(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 gpio_num, gpio_port; + u32 gpio_val; + if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id, + params->shmem_base, params->port, + &gpio_num, &gpio_port) != 0) + return 0; + gpio_val = bnx2x_get_gpio(bp, gpio_num, gpio_port); + + /* Call the handling function in case module is detected */ + if (gpio_val == 0) + return 1; + else + return 0; +} + +static void bnx2x_warpcore_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u32 serdes_net_if; + u8 fiber_mode; + u16 lane = bnx2x_get_warpcore_lane(phy, params); + serdes_net_if = (REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_hw_config[params->port].default_cfg)) & + PORT_HW_CFG_NET_SERDES_IF_MASK); + DP(NETIF_MSG_LINK, "Begin Warpcore init, link_speed %d, " + "serdes_net_if = 0x%x\n", + vars->line_speed, serdes_net_if); + bnx2x_set_aer_mmd(params, phy); + + vars->phy_flags |= PHY_XGXS_FLAG; + if ((serdes_net_if == PORT_HW_CFG_NET_SERDES_IF_SGMII) || + (phy->req_line_speed && + ((phy->req_line_speed == SPEED_100) || + (phy->req_line_speed == SPEED_10)))) { + vars->phy_flags |= PHY_SGMII_FLAG; + DP(NETIF_MSG_LINK, "Setting SGMII mode\n"); + bnx2x_warpcore_clear_regs(phy, params, lane); + bnx2x_warpcore_set_sgmii_speed(phy, params, 0); + } else { + switch (serdes_net_if) { + case PORT_HW_CFG_NET_SERDES_IF_KR: + /* Enable KR Auto Neg */ + if (params->loopback_mode == LOOPBACK_NONE) + bnx2x_warpcore_enable_AN_KR(phy, params, vars); + else { + DP(NETIF_MSG_LINK, "Setting KR 10G-Force\n"); + bnx2x_warpcore_set_10G_KR(phy, params, vars); + } + break; + + case PORT_HW_CFG_NET_SERDES_IF_XFI: + bnx2x_warpcore_clear_regs(phy, params, lane); + if (vars->line_speed == SPEED_10000) { + DP(NETIF_MSG_LINK, "Setting 10G XFI\n"); + bnx2x_warpcore_set_10G_XFI(phy, params, 1); + } else { + if (SINGLE_MEDIA_DIRECT(params)) { + DP(NETIF_MSG_LINK, "1G Fiber\n"); + fiber_mode = 1; + } else { + DP(NETIF_MSG_LINK, "10/100/1G SGMII\n"); + fiber_mode = 0; + } + bnx2x_warpcore_set_sgmii_speed(phy, + params, + fiber_mode); + } + + break; + + case PORT_HW_CFG_NET_SERDES_IF_SFI: + + bnx2x_warpcore_clear_regs(phy, params, lane); + if (vars->line_speed == SPEED_10000) { + DP(NETIF_MSG_LINK, "Setting 10G SFI\n"); + bnx2x_warpcore_set_10G_XFI(phy, params, 0); + } else if (vars->line_speed == SPEED_1000) { + DP(NETIF_MSG_LINK, "Setting 1G Fiber\n"); + bnx2x_warpcore_set_sgmii_speed(phy, params, 1); + } + /* Issue Module detection */ + if (bnx2x_is_sfp_module_plugged(phy, params)) + bnx2x_sfp_module_detection(phy, params); + break; + + case PORT_HW_CFG_NET_SERDES_IF_DXGXS: + if (vars->line_speed != SPEED_20000) { + DP(NETIF_MSG_LINK, "Speed not supported yet\n"); + return; + } + DP(NETIF_MSG_LINK, "Setting 20G DXGXS\n"); + bnx2x_warpcore_set_20G_DXGXS(bp, phy, lane); + /* Issue Module detection */ + + bnx2x_sfp_module_detection(phy, params); + break; + + case PORT_HW_CFG_NET_SERDES_IF_KR2: + if (vars->line_speed != SPEED_20000) { + DP(NETIF_MSG_LINK, "Speed not supported yet\n"); + return; + } + DP(NETIF_MSG_LINK, "Setting 20G KR2\n"); + bnx2x_warpcore_set_20G_KR2(bp, phy); + break; + + default: + DP(NETIF_MSG_LINK, "Unsupported Serdes Net Interface " + "0x%x\n", serdes_net_if); + return; + } + } + + /* Take lane out of reset after configuration is finished */ + bnx2x_warpcore_reset_lane(bp, phy, 0); + DP(NETIF_MSG_LINK, "Exit config init\n"); +} + +static void bnx2x_sfp_e3_set_transmitter(struct link_params *params, + struct bnx2x_phy *phy, + u8 tx_en) +{ + struct bnx2x *bp = params->bp; + u32 cfg_pin; + u8 port = params->port; + + cfg_pin = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].e3_sfp_ctrl)) & + PORT_HW_CFG_TX_LASER_MASK; + /* Set the !tx_en since this pin is DISABLE_TX_LASER */ + DP(NETIF_MSG_LINK, "Setting WC TX to %d\n", tx_en); + /* For 20G, the expected pin to be used is 3 pins after the current */ + + bnx2x_set_cfg_pin(bp, cfg_pin, tx_en ^ 1); + if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_20G) + bnx2x_set_cfg_pin(bp, cfg_pin + 3, tx_en ^ 1); +} + +static void bnx2x_warpcore_link_reset(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 val16; + bnx2x_sfp_e3_set_transmitter(params, phy, 0); + bnx2x_set_mdio_clk(bp, params->chip_id, params->port); + bnx2x_set_aer_mmd(params, phy); + /* Global register */ + bnx2x_warpcore_reset_lane(bp, phy, 1); + + /* Clear loopback settings (if any) */ + /* 10G & 20G */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_COMBO_IEEE0_MIICTRL, &val16); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_COMBO_IEEE0_MIICTRL, val16 & + 0xBFFF); + + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_IEEE0BLK_MIICNTL, &val16); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_IEEE0BLK_MIICNTL, val16 & 0xfffe); + + /* Update those 1-copy registers */ + CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK, + MDIO_AER_BLOCK_AER_REG, 0); + /* Enable 1G MDIO (1-copy) */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK0_XGXSCONTROL, + &val16); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK0_XGXSCONTROL, + val16 & ~0x10); + + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL2, &val16); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL2, + val16 & 0xff00); + +} + +static void bnx2x_set_warpcore_loopback(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 val16; + u32 lane; + DP(NETIF_MSG_LINK, "Setting Warpcore loopback type %x, speed %d\n", + params->loopback_mode, phy->req_line_speed); + + if (phy->req_line_speed < SPEED_10000) { + /* 10/100/1000 */ + + /* Update those 1-copy registers */ + CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK, + MDIO_AER_BLOCK_AER_REG, 0); + /* Enable 1G MDIO (1-copy) */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK0_XGXSCONTROL, + &val16); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK0_XGXSCONTROL, + val16 | 0x10); + /* Set 1G loopback based on lane (1-copy) */ + lane = bnx2x_get_warpcore_lane(phy, params); + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL2, &val16); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_XGXSBLK1_LANECTRL2, + val16 | (1<bp; + u8 link_10g_plus; + u8 port = params->port; + u32 sync_offset, media_types; + /* Update PHY configuration */ + set_phy_vars(params, vars); + + vars->link_status = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + port_mb[port].link_status)); + + vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP); + vars->phy_flags = PHY_XGXS_FLAG; + if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG) + vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG; + + if (vars->link_up) { + DP(NETIF_MSG_LINK, "phy link up\n"); + + vars->phy_link_up = 1; + vars->duplex = DUPLEX_FULL; + switch (vars->link_status & + LINK_STATUS_SPEED_AND_DUPLEX_MASK) { + case LINK_10THD: + vars->duplex = DUPLEX_HALF; + /* fall thru */ + case LINK_10TFD: + vars->line_speed = SPEED_10; + break; + + case LINK_100TXHD: + vars->duplex = DUPLEX_HALF; + /* fall thru */ + case LINK_100T4: + case LINK_100TXFD: + vars->line_speed = SPEED_100; + break; + + case LINK_1000THD: + vars->duplex = DUPLEX_HALF; + /* fall thru */ + case LINK_1000TFD: + vars->line_speed = SPEED_1000; + break; + + case LINK_2500THD: + vars->duplex = DUPLEX_HALF; + /* fall thru */ + case LINK_2500TFD: + vars->line_speed = SPEED_2500; + break; + + case LINK_10GTFD: + vars->line_speed = SPEED_10000; + break; + case LINK_20GTFD: + vars->line_speed = SPEED_20000; + break; + default: + break; + } + vars->flow_ctrl = 0; + if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED) + vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX; + + if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED) + vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX; + + if (!vars->flow_ctrl) + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + + if (vars->line_speed && + ((vars->line_speed == SPEED_10) || + (vars->line_speed == SPEED_100))) { + vars->phy_flags |= PHY_SGMII_FLAG; + } else { + vars->phy_flags &= ~PHY_SGMII_FLAG; + } + if (vars->line_speed && + USES_WARPCORE(bp) && + (vars->line_speed == SPEED_1000)) + vars->phy_flags |= PHY_SGMII_FLAG; + /* anything 10 and over uses the bmac */ + link_10g_plus = (vars->line_speed >= SPEED_10000); + + if (link_10g_plus) { + if (USES_WARPCORE(bp)) + vars->mac_type = MAC_TYPE_XMAC; + else + vars->mac_type = MAC_TYPE_BMAC; + } else { + if (USES_WARPCORE(bp)) + vars->mac_type = MAC_TYPE_UMAC; + else + vars->mac_type = MAC_TYPE_EMAC; + } + } else { /* link down */ + DP(NETIF_MSG_LINK, "phy link down\n"); + + vars->phy_link_up = 0; + + vars->line_speed = 0; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + + /* indicate no mac active */ + vars->mac_type = MAC_TYPE_NONE; + if (vars->link_status & LINK_STATUS_PHYSICAL_LINK_FLAG) + vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG; + } + + /* Sync media type */ + sync_offset = params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].media_type); + media_types = REG_RD(bp, sync_offset); + + params->phy[INT_PHY].media_type = + (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) >> + PORT_HW_CFG_MEDIA_TYPE_PHY0_SHIFT; + params->phy[EXT_PHY1].media_type = + (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY1_MASK) >> + PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT; + params->phy[EXT_PHY2].media_type = + (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY2_MASK) >> + PORT_HW_CFG_MEDIA_TYPE_PHY2_SHIFT; + DP(NETIF_MSG_LINK, "media_types = 0x%x\n", media_types); + + /* Sync AEU offset */ + sync_offset = params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].aeu_int_mask); + + vars->aeu_int_mask = REG_RD(bp, sync_offset); + + /* Sync PFC status */ + if (vars->link_status & LINK_STATUS_PFC_ENABLED) + params->feature_config_flags |= + FEATURE_CONFIG_PFC_ENABLED; + else + params->feature_config_flags &= + ~FEATURE_CONFIG_PFC_ENABLED; + + DP(NETIF_MSG_LINK, "link_status 0x%x phy_link_up %x int_mask 0x%x\n", + vars->link_status, vars->phy_link_up, vars->aeu_int_mask); + DP(NETIF_MSG_LINK, "line_speed %x duplex %x flow_ctrl 0x%x\n", + vars->line_speed, vars->duplex, vars->flow_ctrl); +} + + +static void bnx2x_set_master_ln(struct link_params *params, + struct bnx2x_phy *phy) +{ + struct bnx2x *bp = params->bp; + u16 new_master_ln, ser_lane; + ser_lane = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + + /* set the master_ln for AN */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_TEST_MODE_LANE, + &new_master_ln); + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2 , + MDIO_XGXS_BLOCK2_TEST_MODE_LANE, + (new_master_ln | ser_lane)); +} + +static int bnx2x_reset_unicore(struct link_params *params, + struct bnx2x_phy *phy, + u8 set_serdes) +{ + struct bnx2x *bp = params->bp; + u16 mii_control; + u16 i; + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, &mii_control); + + /* reset the unicore */ + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_RESET)); + if (set_serdes) + bnx2x_set_serdes_access(bp, params->port); + + /* wait for the reset to self clear */ + for (i = 0; i < MDIO_ACCESS_TIMEOUT; i++) { + udelay(5); + + /* the reset erased the previous bank value */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + + if (!(mii_control & MDIO_COMBO_IEEO_MII_CONTROL_RESET)) { + udelay(5); + return 0; + } + } + + netdev_err(bp->dev, "Warning: PHY was not initialized," + " Port %d\n", + params->port); + DP(NETIF_MSG_LINK, "BUG! XGXS is still in reset!\n"); + return -EINVAL; + +} + +static void bnx2x_set_swap_lanes(struct link_params *params, + struct bnx2x_phy *phy) +{ + struct bnx2x *bp = params->bp; + /* + * Each two bits represents a lane number: + * No swap is 0123 => 0x1b no need to enable the swap + */ + u16 ser_lane, rx_lane_swap, tx_lane_swap; + + ser_lane = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + rx_lane_swap = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_RX_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_RX_SHIFT); + tx_lane_swap = ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_TX_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_TX_SHIFT); + + if (rx_lane_swap != 0x1b) { + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_RX_LN_SWAP, + (rx_lane_swap | + MDIO_XGXS_BLOCK2_RX_LN_SWAP_ENABLE | + MDIO_XGXS_BLOCK2_RX_LN_SWAP_FORCE_ENABLE)); + } else { + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_RX_LN_SWAP, 0); + } + + if (tx_lane_swap != 0x1b) { + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_TX_LN_SWAP, + (tx_lane_swap | + MDIO_XGXS_BLOCK2_TX_LN_SWAP_ENABLE)); + } else { + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_TX_LN_SWAP, 0); + } +} + +static void bnx2x_set_parallel_detection(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 control2; + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, + &control2); + if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) + control2 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN; + else + control2 &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL2_PRL_DT_EN; + DP(NETIF_MSG_LINK, "phy->speed_cap_mask = 0x%x, control2 = 0x%x\n", + phy->speed_cap_mask, control2); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL2, + control2); + + if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) && + (phy->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) { + DP(NETIF_MSG_LINK, "XGXS\n"); + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_10G_PARALLEL_DETECT, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_LINK_CNT); + + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_10G_PARALLEL_DETECT, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, + &control2); + + + control2 |= + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL_PARDET10G_EN; + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_10G_PARALLEL_DETECT, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_CONTROL, + control2); + + /* Disable parallel detection of HiG */ + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_XGXS_BLOCK2, + MDIO_XGXS_BLOCK2_UNICORE_MODE_10G, + MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_CX4_XGXS | + MDIO_XGXS_BLOCK2_UNICORE_MODE_10G_HIGIG_XGXS); + } +} + +static void bnx2x_set_autoneg(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars, + u8 enable_cl73) +{ + struct bnx2x *bp = params->bp; + u16 reg_val; + + /* CL37 Autoneg */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); + + /* CL37 Autoneg Enabled */ + if (vars->line_speed == SPEED_AUTO_NEG) + reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_AN_EN; + else /* CL37 Autoneg Disabled */ + reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN); + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); + + /* Enable/Disable Autodetection */ + + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, ®_val); + reg_val &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_SIGNAL_DETECT_EN | + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT); + reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE; + if (vars->line_speed == SPEED_AUTO_NEG) + reg_val |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; + else + reg_val &= ~MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET; + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, reg_val); + + /* Enable TetonII and BAM autoneg */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_BAM_NEXT_PAGE, + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, + ®_val); + if (vars->line_speed == SPEED_AUTO_NEG) { + /* Enable BAM aneg Mode and TetonII aneg Mode */ + reg_val |= (MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE | + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN); + } else { + /* TetonII and BAM Autoneg Disabled */ + reg_val &= ~(MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_BAM_MODE | + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL_TETON_AN); + } + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_BAM_NEXT_PAGE, + MDIO_BAM_NEXT_PAGE_MP5_NEXT_PAGE_CTRL, + reg_val); + + if (enable_cl73) { + /* Enable Cl73 FSM status bits */ + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_UCTRL, + 0xe); + + /* Enable BAM Station Manager*/ + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_BAM_CTRL1, + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_STATION_MNGR_EN | + MDIO_CL73_USERB0_CL73_BAM_CTRL1_BAM_NP_AFTER_BP_EN); + + /* Advertise CL73 link speeds */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, + ®_val); + if (phy->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) + reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_10G_KX4; + if (phy->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) + reg_val |= MDIO_CL73_IEEEB1_AN_ADV2_ADVR_1000M_KX; + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV2, + reg_val); + + /* CL73 Autoneg Enabled */ + reg_val = MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN; + + } else /* CL73 Autoneg Disabled */ + reg_val = 0; + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, reg_val); +} + +/* program SerDes, forced speed */ +static void bnx2x_program_serdes(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 reg_val; + + /* program duplex, disable autoneg and sgmii*/ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, ®_val); + reg_val &= ~(MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX | + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK); + if (phy->req_duplex == DUPLEX_FULL) + reg_val |= MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, reg_val); + + /* + * program speed + * - needed only if the speed is greater than 1G (2.5G or 10G) + */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_MISC1, ®_val); + /* clearing the speed value before setting the right speed */ + DP(NETIF_MSG_LINK, "MDIO_REG_BANK_SERDES_DIGITAL = 0x%x\n", reg_val); + + reg_val &= ~(MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_MASK | + MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL); + + if (!((vars->line_speed == SPEED_1000) || + (vars->line_speed == SPEED_100) || + (vars->line_speed == SPEED_10))) { + + reg_val |= (MDIO_SERDES_DIGITAL_MISC1_REFCLK_SEL_156_25M | + MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_SEL); + if (vars->line_speed == SPEED_10000) + reg_val |= + MDIO_SERDES_DIGITAL_MISC1_FORCE_SPEED_10G_CX4; + } + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_MISC1, reg_val); + +} + +static void bnx2x_set_brcm_cl37_advertisement(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 val = 0; + + /* configure the 48 bits for BAM AN */ + + /* set extended capabilities */ + if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) + val |= MDIO_OVER_1G_UP1_2_5G; + if (phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) + val |= MDIO_OVER_1G_UP1_10G; + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_OVER_1G, + MDIO_OVER_1G_UP1, val); + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_OVER_1G, + MDIO_OVER_1G_UP3, 0x400); +} + +static void bnx2x_set_ieee_aneg_advertisement(struct bnx2x_phy *phy, + struct link_params *params, + u16 ieee_fc) +{ + struct bnx2x *bp = params->bp; + u16 val; + /* for AN, we are always publishing full duplex */ + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_AUTO_NEG_ADV, ieee_fc); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV1, &val); + val &= ~MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_BOTH; + val |= ((ieee_fc<<3) & MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV1, val); +} + +static void bnx2x_restart_autoneg(struct bnx2x_phy *phy, + struct link_params *params, + u8 enable_cl73) +{ + struct bnx2x *bp = params->bp; + u16 mii_control; + + DP(NETIF_MSG_LINK, "bnx2x_restart_autoneg\n"); + /* Enable and restart BAM/CL37 aneg */ + + if (enable_cl73) { + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + &mii_control); + + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + (mii_control | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN | + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_RESTART_AN)); + } else { + + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + DP(NETIF_MSG_LINK, + "bnx2x_restart_autoneg mii_control before = 0x%x\n", + mii_control); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + (mii_control | + MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_RESTART_AN)); + } +} + +static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 control1; + + /* in SGMII mode, the unicore is always slave */ + + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, + &control1); + control1 |= MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_INVERT_SIGNAL_DETECT; + /* set sgmii mode (and not fiber) */ + control1 &= ~(MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_FIBER_MODE | + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_AUTODET | + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1_MSTR_MODE); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_CONTROL1, + control1); + + /* if forced speed */ + if (!(vars->line_speed == SPEED_AUTO_NEG)) { + /* set speed, disable autoneg */ + u16 mii_control; + + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + &mii_control); + mii_control &= ~(MDIO_COMBO_IEEO_MII_CONTROL_AN_EN | + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_MASK| + MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX); + + switch (vars->line_speed) { + case SPEED_100: + mii_control |= + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_100; + break; + case SPEED_1000: + mii_control |= + MDIO_COMBO_IEEO_MII_CONTROL_MAN_SGMII_SP_1000; + break; + case SPEED_10: + /* there is nothing to set for 10M */ + break; + default: + /* invalid speed for SGMII */ + DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", + vars->line_speed); + break; + } + + /* setting the full duplex */ + if (phy->req_duplex == DUPLEX_FULL) + mii_control |= + MDIO_COMBO_IEEO_MII_CONTROL_FULL_DUPLEX; + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_MII_CONTROL, + mii_control); + + } else { /* AN mode */ + /* enable and restart AN */ + bnx2x_restart_autoneg(phy, params, 0); + } +} + + +/* + * link management + */ + +static int bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 pd_10g, status2_1000x; + if (phy->req_line_speed != SPEED_AUTO_NEG) + return 0; + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_STATUS2, + &status2_1000x); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_SERDES_DIGITAL, + MDIO_SERDES_DIGITAL_A_1000X_STATUS2, + &status2_1000x); + if (status2_1000x & MDIO_SERDES_DIGITAL_A_1000X_STATUS2_AN_DISABLED) { + DP(NETIF_MSG_LINK, "1G parallel detect link on port %d\n", + params->port); + return 1; + } + + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_10G_PARALLEL_DETECT, + MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS, + &pd_10g); + + if (pd_10g & MDIO_10G_PARALLEL_DETECT_PAR_DET_10G_STATUS_PD_LINK) { + DP(NETIF_MSG_LINK, "10G parallel detect link on port %d\n", + params->port); + return 1; + } + return 0; +} + +static void bnx2x_flow_ctrl_resolve(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars, + u32 gp_status) +{ + struct bnx2x *bp = params->bp; + u16 ld_pause; /* local driver */ + u16 lp_pause; /* link partner */ + u16 pause_result; + + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + + /* resolve from gp_status in case of AN complete and not sgmii */ + if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO) + vars->flow_ctrl = phy->req_flow_ctrl; + else if (phy->req_line_speed != SPEED_AUTO_NEG) + vars->flow_ctrl = params->req_fc_auto_adv; + else if ((gp_status & MDIO_AN_CL73_OR_37_COMPLETE) && + (!(vars->phy_flags & PHY_SGMII_FLAG))) { + if (bnx2x_direct_parallel_detect_used(phy, params)) { + vars->flow_ctrl = params->req_fc_auto_adv; + return; + } + if ((gp_status & + (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | + MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) == + (MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_AUTONEG_COMPLETE | + MDIO_GP_STATUS_TOP_AN_STATUS1_CL73_MR_LP_NP_AN_ABLE)) { + + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_ADV1, + &ld_pause); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB1, + MDIO_CL73_IEEEB1_AN_LP_ADV1, + &lp_pause); + pause_result = (ld_pause & + MDIO_CL73_IEEEB1_AN_ADV1_PAUSE_MASK) + >> 8; + pause_result |= (lp_pause & + MDIO_CL73_IEEEB1_AN_LP_ADV1_PAUSE_MASK) + >> 10; + DP(NETIF_MSG_LINK, "pause_result CL73 0x%x\n", + pause_result); + } else { + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_AUTO_NEG_ADV, + &ld_pause); + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_COMBO_IEEE0, + MDIO_COMBO_IEEE0_AUTO_NEG_LINK_PARTNER_ABILITY1, + &lp_pause); + pause_result = (ld_pause & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>5; + pause_result |= (lp_pause & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7; + DP(NETIF_MSG_LINK, "pause_result CL37 0x%x\n", + pause_result); + } + bnx2x_pause_resolve(vars, pause_result); + } + DP(NETIF_MSG_LINK, "flow_ctrl 0x%x\n", vars->flow_ctrl); +} + +static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 rx_status, ustat_val, cl37_fsm_received; + DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n"); + /* Step 1: Make sure signal is detected */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_RX0, + MDIO_RX0_RX_STATUS, + &rx_status); + if ((rx_status & MDIO_RX0_RX_STATUS_SIGDET) != + (MDIO_RX0_RX_STATUS_SIGDET)) { + DP(NETIF_MSG_LINK, "Signal is not detected. Restoring CL73." + "rx_status(0x80b0) = 0x%x\n", rx_status); + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL_AN_EN); + return; + } + /* Step 2: Check CL73 state machine */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_USERB0, + MDIO_CL73_USERB0_CL73_USTAT1, + &ustat_val); + if ((ustat_val & + (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK | + MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) != + (MDIO_CL73_USERB0_CL73_USTAT1_LINK_STATUS_CHECK | + MDIO_CL73_USERB0_CL73_USTAT1_AN_GOOD_CHECK_BAM37)) { + DP(NETIF_MSG_LINK, "CL73 state-machine is not stable. " + "ustat_val(0x8371) = 0x%x\n", ustat_val); + return; + } + /* + * Step 3: Check CL37 Message Pages received to indicate LP + * supports only CL37 + */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_REMOTE_PHY, + MDIO_REMOTE_PHY_MISC_RX_STATUS, + &cl37_fsm_received); + if ((cl37_fsm_received & + (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG | + MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) != + (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG | + MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) { + DP(NETIF_MSG_LINK, "No CL37 FSM were received. " + "misc_rx_status(0x8330) = 0x%x\n", + cl37_fsm_received); + return; + } + /* + * The combined cl37/cl73 fsm state information indicating that + * we are connected to a device which does not support cl73, but + * does support cl37 BAM. In this case we disable cl73 and + * restart cl37 auto-neg + */ + + /* Disable CL73 */ + CL22_WR_OVER_CL45(bp, phy, + MDIO_REG_BANK_CL73_IEEEB0, + MDIO_CL73_IEEEB0_CL73_AN_CONTROL, + 0); + /* Restart CL37 autoneg */ + bnx2x_restart_autoneg(phy, params, 0); + DP(NETIF_MSG_LINK, "Disabling CL73, and restarting CL37 autoneg\n"); +} + +static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars, + u32 gp_status) +{ + if (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) + vars->link_status |= + LINK_STATUS_AUTO_NEGOTIATE_COMPLETE; + + if (bnx2x_direct_parallel_detect_used(phy, params)) + vars->link_status |= + LINK_STATUS_PARALLEL_DETECTION_USED; +} +static int bnx2x_get_link_speed_duplex(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars, + u16 is_link_up, + u16 speed_mask, + u16 is_duplex) +{ + struct bnx2x *bp = params->bp; + if (phy->req_line_speed == SPEED_AUTO_NEG) + vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED; + if (is_link_up) { + DP(NETIF_MSG_LINK, "phy link up\n"); + + vars->phy_link_up = 1; + vars->link_status |= LINK_STATUS_LINK_UP; + + switch (speed_mask) { + case GP_STATUS_10M: + vars->line_speed = SPEED_10; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_10TFD; + else + vars->link_status |= LINK_10THD; + break; + + case GP_STATUS_100M: + vars->line_speed = SPEED_100; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_100TXFD; + else + vars->link_status |= LINK_100TXHD; + break; + + case GP_STATUS_1G: + case GP_STATUS_1G_KX: + vars->line_speed = SPEED_1000; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_1000TFD; + else + vars->link_status |= LINK_1000THD; + break; + + case GP_STATUS_2_5G: + vars->line_speed = SPEED_2500; + if (vars->duplex == DUPLEX_FULL) + vars->link_status |= LINK_2500TFD; + else + vars->link_status |= LINK_2500THD; + break; + + case GP_STATUS_5G: + case GP_STATUS_6G: + DP(NETIF_MSG_LINK, + "link speed unsupported gp_status 0x%x\n", + speed_mask); + return -EINVAL; + + case GP_STATUS_10G_KX4: + case GP_STATUS_10G_HIG: + case GP_STATUS_10G_CX4: + case GP_STATUS_10G_KR: + case GP_STATUS_10G_SFI: + case GP_STATUS_10G_XFI: + vars->line_speed = SPEED_10000; + vars->link_status |= LINK_10GTFD; + break; + case GP_STATUS_20G_DXGXS: + vars->line_speed = SPEED_20000; + vars->link_status |= LINK_20GTFD; + break; + default: + DP(NETIF_MSG_LINK, + "link speed unsupported gp_status 0x%x\n", + speed_mask); + return -EINVAL; + } + } else { /* link_down */ + DP(NETIF_MSG_LINK, "phy link down\n"); + + vars->phy_link_up = 0; + + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + vars->mac_type = MAC_TYPE_NONE; + } + DP(NETIF_MSG_LINK, " phy_link_up %x line_speed %d\n", + vars->phy_link_up, vars->line_speed); + return 0; +} + +static int bnx2x_link_settings_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + + struct bnx2x *bp = params->bp; + + u16 gp_status, duplex = DUPLEX_HALF, link_up = 0, speed_mask; + int rc = 0; + + /* Read gp_status */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_GP_STATUS, + MDIO_GP_STATUS_TOP_AN_STATUS1, + &gp_status); + if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_DUPLEX_STATUS) + duplex = DUPLEX_FULL; + if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) + link_up = 1; + speed_mask = gp_status & GP_STATUS_SPEED_MASK; + DP(NETIF_MSG_LINK, "gp_status 0x%x, is_link_up %d, speed_mask 0x%x\n", + gp_status, link_up, speed_mask); + rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, speed_mask, + duplex); + if (rc == -EINVAL) + return rc; + + if (gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS) { + if (SINGLE_MEDIA_DIRECT(params)) { + bnx2x_flow_ctrl_resolve(phy, params, vars, gp_status); + if (phy->req_line_speed == SPEED_AUTO_NEG) + bnx2x_xgxs_an_resolve(phy, params, vars, + gp_status); + } + } else { /* link_down */ + if ((phy->req_line_speed == SPEED_AUTO_NEG) && + SINGLE_MEDIA_DIRECT(params)) { + /* Check signal is detected */ + bnx2x_check_fallback_to_cl37(phy, params); + } + } + + DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n", + vars->duplex, vars->flow_ctrl, vars->link_status); + return rc; +} + +static int bnx2x_warpcore_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + + struct bnx2x *bp = params->bp; + + u8 lane; + u16 gp_status1, gp_speed, link_up, duplex = DUPLEX_FULL; + int rc = 0; + lane = bnx2x_get_warpcore_lane(phy, params); + /* Read gp_status */ + if (phy->req_line_speed > SPEED_10000) { + u16 temp_link_up; + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + 1, &temp_link_up); + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + 1, &link_up); + DP(NETIF_MSG_LINK, "PCS RX link status = 0x%x-->0x%x\n", + temp_link_up, link_up); + link_up &= (1<<2); + if (link_up) + bnx2x_ext_phy_resolve_fc(phy, params, vars); + } else { + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_GP2_STATUS_GP_2_1, &gp_status1); + DP(NETIF_MSG_LINK, "0x81d1 = 0x%x\n", gp_status1); + /* Check for either KR or generic link up. */ + gp_status1 = ((gp_status1 >> 8) & 0xf) | + ((gp_status1 >> 12) & 0xf); + link_up = gp_status1 & (1 << lane); + if (link_up && SINGLE_MEDIA_DIRECT(params)) { + u16 pd, gp_status4; + if (phy->req_line_speed == SPEED_AUTO_NEG) { + /* Check Autoneg complete */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_GP2_STATUS_GP_2_4, + &gp_status4); + if (gp_status4 & ((1<<12)<link_status |= + LINK_STATUS_AUTO_NEGOTIATE_COMPLETE; + + /* Check parallel detect used */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_PAR_DET_10G_STATUS, + &pd); + if (pd & (1<<15)) + vars->link_status |= + LINK_STATUS_PARALLEL_DETECTION_USED; + } + bnx2x_ext_phy_resolve_fc(phy, params, vars); + } + } + + if (lane < 2) { + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_GP2_STATUS_GP_2_2, &gp_speed); + } else { + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_GP2_STATUS_GP_2_3, &gp_speed); + } + DP(NETIF_MSG_LINK, "lane %d gp_speed 0x%x\n", lane, gp_speed); + + if ((lane & 1) == 0) + gp_speed <<= 8; + gp_speed &= 0x3f00; + + + rc = bnx2x_get_link_speed_duplex(phy, params, vars, link_up, gp_speed, + duplex); + + DP(NETIF_MSG_LINK, "duplex %x flow_ctrl 0x%x link_status 0x%x\n", + vars->duplex, vars->flow_ctrl, vars->link_status); + return rc; +} +static void bnx2x_set_gmii_tx_driver(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + struct bnx2x_phy *phy = ¶ms->phy[INT_PHY]; + u16 lp_up2; + u16 tx_driver; + u16 bank; + + /* read precomp */ + CL22_RD_OVER_CL45(bp, phy, + MDIO_REG_BANK_OVER_1G, + MDIO_OVER_1G_LP_UP2, &lp_up2); + + /* bits [10:7] at lp_up2, positioned at [15:12] */ + lp_up2 = (((lp_up2 & MDIO_OVER_1G_LP_UP2_PREEMPHASIS_MASK) >> + MDIO_OVER_1G_LP_UP2_PREEMPHASIS_SHIFT) << + MDIO_TX0_TX_DRIVER_PREEMPHASIS_SHIFT); + + if (lp_up2 == 0) + return; + + for (bank = MDIO_REG_BANK_TX0; bank <= MDIO_REG_BANK_TX3; + bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0)) { + CL22_RD_OVER_CL45(bp, phy, + bank, + MDIO_TX0_TX_DRIVER, &tx_driver); + + /* replace tx_driver bits [15:12] */ + if (lp_up2 != + (tx_driver & MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK)) { + tx_driver &= ~MDIO_TX0_TX_DRIVER_PREEMPHASIS_MASK; + tx_driver |= lp_up2; + CL22_WR_OVER_CL45(bp, phy, + bank, + MDIO_TX0_TX_DRIVER, tx_driver); + } + } +} + +static int bnx2x_emac_program(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u16 mode = 0; + + DP(NETIF_MSG_LINK, "setting link speed & duplex\n"); + bnx2x_bits_dis(bp, GRCBASE_EMAC0 + port*0x400 + + EMAC_REG_EMAC_MODE, + (EMAC_MODE_25G_MODE | + EMAC_MODE_PORT_MII_10M | + EMAC_MODE_HALF_DUPLEX)); + switch (vars->line_speed) { + case SPEED_10: + mode |= EMAC_MODE_PORT_MII_10M; + break; + + case SPEED_100: + mode |= EMAC_MODE_PORT_MII; + break; + + case SPEED_1000: + mode |= EMAC_MODE_PORT_GMII; + break; + + case SPEED_2500: + mode |= (EMAC_MODE_25G_MODE | EMAC_MODE_PORT_GMII); + break; + + default: + /* 10G not valid for EMAC */ + DP(NETIF_MSG_LINK, "Invalid line_speed 0x%x\n", + vars->line_speed); + return -EINVAL; + } + + if (vars->duplex == DUPLEX_HALF) + mode |= EMAC_MODE_HALF_DUPLEX; + bnx2x_bits_en(bp, + GRCBASE_EMAC0 + port*0x400 + EMAC_REG_EMAC_MODE, + mode); + + bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed); + return 0; +} + +static void bnx2x_set_preemphasis(struct bnx2x_phy *phy, + struct link_params *params) +{ + + u16 bank, i = 0; + struct bnx2x *bp = params->bp; + + for (bank = MDIO_REG_BANK_RX0, i = 0; bank <= MDIO_REG_BANK_RX3; + bank += (MDIO_REG_BANK_RX1-MDIO_REG_BANK_RX0), i++) { + CL22_WR_OVER_CL45(bp, phy, + bank, + MDIO_RX0_RX_EQ_BOOST, + phy->rx_preemphasis[i]); + } + + for (bank = MDIO_REG_BANK_TX0, i = 0; bank <= MDIO_REG_BANK_TX3; + bank += (MDIO_REG_BANK_TX1 - MDIO_REG_BANK_TX0), i++) { + CL22_WR_OVER_CL45(bp, phy, + bank, + MDIO_TX0_TX_DRIVER, + phy->tx_preemphasis[i]); + } +} + +static void bnx2x_xgxs_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) || + (params->loopback_mode == LOOPBACK_XGXS)); + if (!(vars->phy_flags & PHY_SGMII_FLAG)) { + if (SINGLE_MEDIA_DIRECT(params) && + (params->feature_config_flags & + FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) + bnx2x_set_preemphasis(phy, params); + + /* forced speed requested? */ + if (vars->line_speed != SPEED_AUTO_NEG || + (SINGLE_MEDIA_DIRECT(params) && + params->loopback_mode == LOOPBACK_EXT)) { + DP(NETIF_MSG_LINK, "not SGMII, no AN\n"); + + /* disable autoneg */ + bnx2x_set_autoneg(phy, params, vars, 0); + + /* program speed and duplex */ + bnx2x_program_serdes(phy, params, vars); + + } else { /* AN_mode */ + DP(NETIF_MSG_LINK, "not SGMII, AN\n"); + + /* AN enabled */ + bnx2x_set_brcm_cl37_advertisement(phy, params); + + /* program duplex & pause advertisement (for aneg) */ + bnx2x_set_ieee_aneg_advertisement(phy, params, + vars->ieee_fc); + + /* enable autoneg */ + bnx2x_set_autoneg(phy, params, vars, enable_cl73); + + /* enable and restart AN */ + bnx2x_restart_autoneg(phy, params, enable_cl73); + } + + } else { /* SGMII mode */ + DP(NETIF_MSG_LINK, "SGMII\n"); + + bnx2x_initialize_sgmii_process(phy, params, vars); + } +} + +static int bnx2x_prepare_xgxs(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + int rc; + vars->phy_flags |= PHY_XGXS_FLAG; + if ((phy->req_line_speed && + ((phy->req_line_speed == SPEED_100) || + (phy->req_line_speed == SPEED_10))) || + (!phy->req_line_speed && + (phy->speed_cap_mask >= + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) && + (phy->speed_cap_mask < + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) || + (phy->type == PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT_SD)) + vars->phy_flags |= PHY_SGMII_FLAG; + else + vars->phy_flags &= ~PHY_SGMII_FLAG; + + bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc); + bnx2x_set_aer_mmd(params, phy); + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) + bnx2x_set_master_ln(params, phy); + + rc = bnx2x_reset_unicore(params, phy, 0); + /* reset the SerDes and wait for reset bit return low */ + if (rc != 0) + return rc; + + bnx2x_set_aer_mmd(params, phy); + /* setting the masterLn_def again after the reset */ + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) { + bnx2x_set_master_ln(params, phy); + bnx2x_set_swap_lanes(params, phy); + } + + return rc; +} + +static u16 bnx2x_wait_reset_complete(struct bnx2x *bp, + struct bnx2x_phy *phy, + struct link_params *params) +{ + u16 cnt, ctrl; + /* Wait for soft reset to get cleared up to 1 sec */ + for (cnt = 0; cnt < 1000; cnt++) { + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE) + bnx2x_cl22_read(bp, phy, + MDIO_PMA_REG_CTRL, &ctrl); + else + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, &ctrl); + if (!(ctrl & (1<<15))) + break; + msleep(1); + } + + if (cnt == 1000) + netdev_err(bp->dev, "Warning: PHY was not initialized," + " Port %d\n", + params->port); + DP(NETIF_MSG_LINK, "control reg 0x%x (after %d ms)\n", ctrl, cnt); + return cnt; +} + +static void bnx2x_link_int_enable(struct link_params *params) +{ + u8 port = params->port; + u32 mask; + struct bnx2x *bp = params->bp; + + /* Setting the status to report on link up for either XGXS or SerDes */ + if (CHIP_IS_E3(bp)) { + mask = NIG_MASK_XGXS0_LINK_STATUS; + if (!(SINGLE_MEDIA_DIRECT(params))) + mask |= NIG_MASK_MI_INT; + } else if (params->switch_cfg == SWITCH_CFG_10G) { + mask = (NIG_MASK_XGXS0_LINK10G | + NIG_MASK_XGXS0_LINK_STATUS); + DP(NETIF_MSG_LINK, "enabled XGXS interrupt\n"); + if (!(SINGLE_MEDIA_DIRECT(params)) && + params->phy[INT_PHY].type != + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) { + mask |= NIG_MASK_MI_INT; + DP(NETIF_MSG_LINK, "enabled external phy int\n"); + } + + } else { /* SerDes */ + mask = NIG_MASK_SERDES0_LINK_STATUS; + DP(NETIF_MSG_LINK, "enabled SerDes interrupt\n"); + if (!(SINGLE_MEDIA_DIRECT(params)) && + params->phy[INT_PHY].type != + PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN) { + mask |= NIG_MASK_MI_INT; + DP(NETIF_MSG_LINK, "enabled external phy int\n"); + } + } + bnx2x_bits_en(bp, + NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + mask); + + DP(NETIF_MSG_LINK, "port %x, is_xgxs %x, int_status 0x%x\n", port, + (params->switch_cfg == SWITCH_CFG_10G), + REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); + DP(NETIF_MSG_LINK, " int_mask 0x%x, MI_INT %x, SERDES_LINK %x\n", + REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), + REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + port*0x18), + REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS+port*0x3c)); + DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n", + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)); +} + +static void bnx2x_rearm_latch_signal(struct bnx2x *bp, u8 port, + u8 exp_mi_int) +{ + u32 latch_status = 0; + + /* + * Disable the MI INT ( external phy int ) by writing 1 to the + * status register. Link down indication is high-active-signal, + * so in this case we need to write the status to clear the XOR + */ + /* Read Latched signals */ + latch_status = REG_RD(bp, + NIG_REG_LATCH_STATUS_0 + port*8); + DP(NETIF_MSG_LINK, "latch_status = 0x%x\n", latch_status); + /* Handle only those with latched-signal=up.*/ + if (exp_mi_int) + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + + port*4, + NIG_STATUS_EMAC0_MI_INT); + else + bnx2x_bits_dis(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + + port*4, + NIG_STATUS_EMAC0_MI_INT); + + if (latch_status & 1) { + + /* For all latched-signal=up : Re-Arm Latch signals */ + REG_WR(bp, NIG_REG_LATCH_STATUS_0 + port*8, + (latch_status & 0xfffe) | (latch_status & 1)); + } + /* For all latched-signal=up,Write original_signal to status */ +} + +static void bnx2x_link_int_ack(struct link_params *params, + struct link_vars *vars, u8 is_10g_plus) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + u32 mask; + /* + * First reset all status we assume only one line will be + * change at a time + */ + bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + (NIG_STATUS_XGXS0_LINK10G | + NIG_STATUS_XGXS0_LINK_STATUS | + NIG_STATUS_SERDES0_LINK_STATUS)); + if (vars->phy_link_up) { + if (USES_WARPCORE(bp)) + mask = NIG_STATUS_XGXS0_LINK_STATUS; + else { + if (is_10g_plus) + mask = NIG_STATUS_XGXS0_LINK10G; + else if (params->switch_cfg == SWITCH_CFG_10G) { + /* + * Disable the link interrupt by writing 1 to + * the relevant lane in the status register + */ + u32 ser_lane = + ((params->lane_config & + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >> + PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT); + mask = ((1 << ser_lane) << + NIG_STATUS_XGXS0_LINK_STATUS_SIZE); + } else + mask = NIG_STATUS_SERDES0_LINK_STATUS; + } + DP(NETIF_MSG_LINK, "Ack link up interrupt with mask 0x%x\n", + mask); + bnx2x_bits_en(bp, + NIG_REG_STATUS_INTERRUPT_PORT0 + port*4, + mask); + } +} + +static int bnx2x_format_ver(u32 num, u8 *str, u16 *len) +{ + u8 *str_ptr = str; + u32 mask = 0xf0000000; + u8 shift = 8*4; + u8 digit; + u8 remove_leading_zeros = 1; + if (*len < 10) { + /* Need more than 10chars for this format */ + *str_ptr = '\0'; + (*len)--; + return -EINVAL; + } + while (shift > 0) { + + shift -= 4; + digit = ((num & mask) >> shift); + if (digit == 0 && remove_leading_zeros) { + mask = mask >> 4; + continue; + } else if (digit < 0xa) + *str_ptr = digit + '0'; + else + *str_ptr = digit - 0xa + 'a'; + remove_leading_zeros = 0; + str_ptr++; + (*len)--; + mask = mask >> 4; + if (shift == 4*4) { + *str_ptr = '.'; + str_ptr++; + (*len)--; + remove_leading_zeros = 1; + } + } + return 0; +} + + +static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len) +{ + str[0] = '\0'; + (*len)--; + return 0; +} + +int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, + u8 *version, u16 len) +{ + struct bnx2x *bp; + u32 spirom_ver = 0; + int status = 0; + u8 *ver_p = version; + u16 remain_len = len; + if (version == NULL || params == NULL) + return -EINVAL; + bp = params->bp; + + /* Extract first external phy*/ + version[0] = '\0'; + spirom_ver = REG_RD(bp, params->phy[EXT_PHY1].ver_addr); + + if (params->phy[EXT_PHY1].format_fw_ver) { + status |= params->phy[EXT_PHY1].format_fw_ver(spirom_ver, + ver_p, + &remain_len); + ver_p += (len - remain_len); + } + if ((params->num_phys == MAX_PHYS) && + (params->phy[EXT_PHY2].ver_addr != 0)) { + spirom_ver = REG_RD(bp, params->phy[EXT_PHY2].ver_addr); + if (params->phy[EXT_PHY2].format_fw_ver) { + *ver_p = '/'; + ver_p++; + remain_len--; + status |= params->phy[EXT_PHY2].format_fw_ver( + spirom_ver, + ver_p, + &remain_len); + ver_p = version + (len - remain_len); + } + } + *ver_p = '\0'; + return status; +} + +static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy, + struct link_params *params) +{ + u8 port = params->port; + struct bnx2x *bp = params->bp; + + if (phy->req_line_speed != SPEED_1000) { + u32 md_devad = 0; + + DP(NETIF_MSG_LINK, "XGXS 10G loopback enable\n"); + + if (!CHIP_IS_E3(bp)) { + /* change the uni_phy_addr in the nig */ + md_devad = REG_RD(bp, (NIG_REG_XGXS0_CTRL_MD_DEVAD + + port*0x18)); + + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, + 0x5); + } + + bnx2x_cl45_write(bp, phy, + 5, + (MDIO_REG_BANK_AER_BLOCK + + (MDIO_AER_BLOCK_AER_REG & 0xf)), + 0x2800); + + bnx2x_cl45_write(bp, phy, + 5, + (MDIO_REG_BANK_CL73_IEEEB0 + + (MDIO_CL73_IEEEB0_CL73_AN_CONTROL & 0xf)), + 0x6041); + msleep(200); + /* set aer mmd back */ + bnx2x_set_aer_mmd(params, phy); + + if (!CHIP_IS_E3(bp)) { + /* and md_devad */ + REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, + md_devad); + } + } else { + u16 mii_ctrl; + DP(NETIF_MSG_LINK, "XGXS 1G loopback enable\n"); + bnx2x_cl45_read(bp, phy, 5, + (MDIO_REG_BANK_COMBO_IEEE0 + + (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)), + &mii_ctrl); + bnx2x_cl45_write(bp, phy, 5, + (MDIO_REG_BANK_COMBO_IEEE0 + + (MDIO_COMBO_IEEE0_MII_CONTROL & 0xf)), + mii_ctrl | + MDIO_COMBO_IEEO_MII_CONTROL_LOOPBACK); + } +} + +int bnx2x_set_led(struct link_params *params, + struct link_vars *vars, u8 mode, u32 speed) +{ + u8 port = params->port; + u16 hw_led_mode = params->hw_led_mode; + int rc = 0; + u8 phy_idx; + u32 tmp; + u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "bnx2x_set_led: port %x, mode %d\n", port, mode); + DP(NETIF_MSG_LINK, "speed 0x%x, hw_led_mode 0x%x\n", + speed, hw_led_mode); + /* In case */ + for (phy_idx = EXT_PHY1; phy_idx < MAX_PHYS; phy_idx++) { + if (params->phy[phy_idx].set_link_led) { + params->phy[phy_idx].set_link_led( + ¶ms->phy[phy_idx], params, mode); + } + } + + switch (mode) { + case LED_MODE_FRONT_PANEL_OFF: + case LED_MODE_OFF: + REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 0); + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, + SHARED_HW_CFG_LED_MAC1); + + tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); + EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp | EMAC_LED_OVERRIDE)); + break; + + case LED_MODE_OPER: + /* + * For all other phys, OPER mode is same as ON, so in case + * link is down, do nothing + */ + if (!vars->link_up) + break; + case LED_MODE_ON: + if (((params->phy[EXT_PHY1].type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) || + (params->phy[EXT_PHY1].type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722)) && + CHIP_IS_E2(bp) && params->num_phys == 2) { + /* + * This is a work-around for E2+8727 Configurations + */ + if (mode == LED_MODE_ON || + speed == SPEED_10000){ + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0); + REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1); + + tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); + EMAC_WR(bp, EMAC_REG_EMAC_LED, + (tmp | EMAC_LED_OVERRIDE)); + /* + * return here without enabling traffic + * LED blink andsetting rate in ON mode. + * In oper mode, enabling LED blink + * and setting rate is needed. + */ + if (mode == LED_MODE_ON) + return rc; + } + } else if (SINGLE_MEDIA_DIRECT(params)) { + /* + * This is a work-around for HW issue found when link + * is up in CL73 + */ + REG_WR(bp, NIG_REG_LED_10G_P0 + port*4, 1); + if (CHIP_IS_E1x(bp) || + CHIP_IS_E2(bp) || + (mode == LED_MODE_ON)) + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, 0); + else + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, + hw_led_mode); + } else + REG_WR(bp, NIG_REG_LED_MODE_P0 + port*4, hw_led_mode); + + REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + port*4, 0); + /* Set blinking rate to ~15.9Hz */ + REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_P0 + port*4, + LED_BLINK_RATE_VAL); + REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 + + port*4, 1); + tmp = EMAC_RD(bp, EMAC_REG_EMAC_LED); + EMAC_WR(bp, EMAC_REG_EMAC_LED, (tmp & (~EMAC_LED_OVERRIDE))); + + if (CHIP_IS_E1(bp) && + ((speed == SPEED_2500) || + (speed == SPEED_1000) || + (speed == SPEED_100) || + (speed == SPEED_10))) { + /* + * On Everest 1 Ax chip versions for speeds less than + * 10G LED scheme is different + */ + REG_WR(bp, NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 + + port*4, 1); + REG_WR(bp, NIG_REG_LED_CONTROL_TRAFFIC_P0 + + port*4, 0); + REG_WR(bp, NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 + + port*4, 1); + } + break; + + default: + rc = -EINVAL; + DP(NETIF_MSG_LINK, "bnx2x_set_led: Invalid led mode %d\n", + mode); + break; + } + return rc; + +} + +/* + * This function comes to reflect the actual link state read DIRECTLY from the + * HW + */ +int bnx2x_test_link(struct link_params *params, struct link_vars *vars, + u8 is_serdes) +{ + struct bnx2x *bp = params->bp; + u16 gp_status = 0, phy_index = 0; + u8 ext_phy_link_up = 0, serdes_phy_type; + struct link_vars temp_vars; + struct bnx2x_phy *int_phy = ¶ms->phy[INT_PHY]; + + if (CHIP_IS_E3(bp)) { + u16 link_up; + if (params->req_line_speed[LINK_CONFIG_IDX(INT_PHY)] + > SPEED_10000) { + /* Check 20G link */ + bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD, + 1, &link_up); + bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD, + 1, &link_up); + link_up &= (1<<2); + } else { + /* Check 10G link and below*/ + u8 lane = bnx2x_get_warpcore_lane(int_phy, params); + bnx2x_cl45_read(bp, int_phy, MDIO_WC_DEVAD, + MDIO_WC_REG_GP2_STATUS_GP_2_1, + &gp_status); + gp_status = ((gp_status >> 8) & 0xf) | + ((gp_status >> 12) & 0xf); + link_up = gp_status & (1 << lane); + } + if (!link_up) + return -ESRCH; + } else { + CL22_RD_OVER_CL45(bp, int_phy, + MDIO_REG_BANK_GP_STATUS, + MDIO_GP_STATUS_TOP_AN_STATUS1, + &gp_status); + /* link is up only if both local phy and external phy are up */ + if (!(gp_status & MDIO_GP_STATUS_TOP_AN_STATUS1_LINK_STATUS)) + return -ESRCH; + } + /* In XGXS loopback mode, do not check external PHY */ + if (params->loopback_mode == LOOPBACK_XGXS) + return 0; + + switch (params->num_phys) { + case 1: + /* No external PHY */ + return 0; + case 2: + ext_phy_link_up = params->phy[EXT_PHY1].read_status( + ¶ms->phy[EXT_PHY1], + params, &temp_vars); + break; + case 3: /* Dual Media */ + for (phy_index = EXT_PHY1; phy_index < params->num_phys; + phy_index++) { + serdes_phy_type = ((params->phy[phy_index].media_type == + ETH_PHY_SFP_FIBER) || + (params->phy[phy_index].media_type == + ETH_PHY_XFP_FIBER) || + (params->phy[phy_index].media_type == + ETH_PHY_DA_TWINAX)); + + if (is_serdes != serdes_phy_type) + continue; + if (params->phy[phy_index].read_status) { + ext_phy_link_up |= + params->phy[phy_index].read_status( + ¶ms->phy[phy_index], + params, &temp_vars); + } + } + break; + } + if (ext_phy_link_up) + return 0; + return -ESRCH; +} + +static int bnx2x_link_initialize(struct link_params *params, + struct link_vars *vars) +{ + int rc = 0; + u8 phy_index, non_ext_phy; + struct bnx2x *bp = params->bp; + /* + * In case of external phy existence, the line speed would be the + * line speed linked up by the external phy. In case it is direct + * only, then the line_speed during initialization will be + * equal to the req_line_speed + */ + vars->line_speed = params->phy[INT_PHY].req_line_speed; + + /* + * Initialize the internal phy in case this is a direct board + * (no external phys), or this board has external phy which requires + * to first. + */ + if (!USES_WARPCORE(bp)) + bnx2x_prepare_xgxs(¶ms->phy[INT_PHY], params, vars); + /* init ext phy and enable link state int */ + non_ext_phy = (SINGLE_MEDIA_DIRECT(params) || + (params->loopback_mode == LOOPBACK_XGXS)); + + if (non_ext_phy || + (params->phy[EXT_PHY1].flags & FLAGS_INIT_XGXS_FIRST) || + (params->loopback_mode == LOOPBACK_EXT_PHY)) { + struct bnx2x_phy *phy = ¶ms->phy[INT_PHY]; + if (vars->line_speed == SPEED_AUTO_NEG && + (CHIP_IS_E1x(bp) || + CHIP_IS_E2(bp))) + bnx2x_set_parallel_detection(phy, params); + if (params->phy[INT_PHY].config_init) + params->phy[INT_PHY].config_init(phy, + params, + vars); + } + + /* Init external phy*/ + if (non_ext_phy) { + if (params->phy[INT_PHY].supported & + SUPPORTED_FIBRE) + vars->link_status |= LINK_STATUS_SERDES_LINK; + } else { + for (phy_index = EXT_PHY1; phy_index < params->num_phys; + phy_index++) { + /* + * No need to initialize second phy in case of first + * phy only selection. In case of second phy, we do + * need to initialize the first phy, since they are + * connected. + */ + if (params->phy[phy_index].supported & + SUPPORTED_FIBRE) + vars->link_status |= LINK_STATUS_SERDES_LINK; + + if (phy_index == EXT_PHY2 && + (bnx2x_phy_selection(params) == + PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) { + DP(NETIF_MSG_LINK, "Not initializing" + " second phy\n"); + continue; + } + params->phy[phy_index].config_init( + ¶ms->phy[phy_index], + params, vars); + } + } + /* Reset the interrupt indication after phy was initialized */ + bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + + params->port*4, + (NIG_STATUS_XGXS0_LINK10G | + NIG_STATUS_XGXS0_LINK_STATUS | + NIG_STATUS_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + bnx2x_update_mng(params, vars->link_status); + return rc; +} + +static void bnx2x_int_link_reset(struct bnx2x_phy *phy, + struct link_params *params) +{ + /* reset the SerDes/XGXS */ + REG_WR(params->bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_3_CLEAR, + (0x1ff << (params->port*16))); +} + +static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 gpio_port; + /* HW reset */ + if (CHIP_IS_E2(bp)) + gpio_port = BP_PATH(bp); + else + gpio_port = params->port; + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW, + gpio_port); + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_LOW, + gpio_port); + DP(NETIF_MSG_LINK, "reset external PHY\n"); +} + +static int bnx2x_update_link_down(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + + DP(NETIF_MSG_LINK, "Port %x: Link is down\n", port); + bnx2x_set_led(params, vars, LED_MODE_OFF, 0); + vars->phy_flags &= ~PHY_PHYSICAL_LINK_FLAG; + /* indicate no mac active */ + vars->mac_type = MAC_TYPE_NONE; + + /* update shared memory */ + vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK | + LINK_STATUS_LINK_UP | + LINK_STATUS_PHYSICAL_LINK_FLAG | + LINK_STATUS_AUTO_NEGOTIATE_COMPLETE | + LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK | + LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK | + LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK); + vars->line_speed = 0; + bnx2x_update_mng(params, vars->link_status); + + /* activate nig drain */ + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1); + + /* disable emac */ + if (!CHIP_IS_E3(bp)) + REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0); + + msleep(10); + /* reset BigMac/Xmac */ + if (CHIP_IS_E1x(bp) || + CHIP_IS_E2(bp)) { + bnx2x_bmac_rx_disable(bp, params->port); + REG_WR(bp, GRCBASE_MISC + + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + } + if (CHIP_IS_E3(bp)) + bnx2x_xmac_disable(params); + + return 0; +} + +static int bnx2x_update_link_up(struct link_params *params, + struct link_vars *vars, + u8 link_10g) +{ + struct bnx2x *bp = params->bp; + u8 port = params->port; + int rc = 0; + + vars->link_status |= (LINK_STATUS_LINK_UP | + LINK_STATUS_PHYSICAL_LINK_FLAG); + vars->phy_flags |= PHY_PHYSICAL_LINK_FLAG; + + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) + vars->link_status |= + LINK_STATUS_TX_FLOW_CONTROL_ENABLED; + + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) + vars->link_status |= + LINK_STATUS_RX_FLOW_CONTROL_ENABLED; + if (USES_WARPCORE(bp)) { + if (link_10g) { + if (bnx2x_xmac_enable(params, vars, 0) == + -ESRCH) { + DP(NETIF_MSG_LINK, "Found errors on XMAC\n"); + vars->link_up = 0; + vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG; + vars->link_status &= ~LINK_STATUS_LINK_UP; + } + } else + bnx2x_umac_enable(params, vars, 0); + bnx2x_set_led(params, vars, + LED_MODE_OPER, vars->line_speed); + } + if ((CHIP_IS_E1x(bp) || + CHIP_IS_E2(bp))) { + if (link_10g) { + if (bnx2x_bmac_enable(params, vars, 0) == + -ESRCH) { + DP(NETIF_MSG_LINK, "Found errors on BMAC\n"); + vars->link_up = 0; + vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG; + vars->link_status &= ~LINK_STATUS_LINK_UP; + } + + bnx2x_set_led(params, vars, + LED_MODE_OPER, SPEED_10000); + } else { + rc = bnx2x_emac_program(params, vars); + bnx2x_emac_enable(params, vars, 0); + + /* AN complete? */ + if ((vars->link_status & + LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) + && (!(vars->phy_flags & PHY_SGMII_FLAG)) && + SINGLE_MEDIA_DIRECT(params)) + bnx2x_set_gmii_tx_driver(params); + } + } + + /* PBF - link up */ + if (CHIP_IS_E1x(bp)) + rc |= bnx2x_pbf_update(params, vars->flow_ctrl, + vars->line_speed); + + /* disable drain */ + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 0); + + /* update shared memory */ + bnx2x_update_mng(params, vars->link_status); + msleep(20); + return rc; +} +/* + * The bnx2x_link_update function should be called upon link + * interrupt. + * Link is considered up as follows: + * - DIRECT_SINGLE_MEDIA - Only XGXS link (internal link) needs + * to be up + * - SINGLE_MEDIA - The link between the 577xx and the external + * phy (XGXS) need to up as well as the external link of the + * phy (PHY_EXT1) + * - DUAL_MEDIA - The link between the 577xx and the first + * external phy needs to be up, and at least one of the 2 + * external phy link must be up. + */ +int bnx2x_link_update(struct link_params *params, struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + struct link_vars phy_vars[MAX_PHYS]; + u8 port = params->port; + u8 link_10g_plus, phy_index; + u8 ext_phy_link_up = 0, cur_link_up; + int rc = 0; + u8 is_mi_int = 0; + u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed; + u8 active_external_phy = INT_PHY; + vars->phy_flags &= ~PHY_HALF_OPEN_CONN_FLAG; + for (phy_index = INT_PHY; phy_index < params->num_phys; + phy_index++) { + phy_vars[phy_index].flow_ctrl = 0; + phy_vars[phy_index].link_status = 0; + phy_vars[phy_index].line_speed = 0; + phy_vars[phy_index].duplex = DUPLEX_FULL; + phy_vars[phy_index].phy_link_up = 0; + phy_vars[phy_index].link_up = 0; + phy_vars[phy_index].fault_detected = 0; + } + + if (USES_WARPCORE(bp)) + bnx2x_set_aer_mmd(params, ¶ms->phy[INT_PHY]); + + DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n", + port, (vars->phy_flags & PHY_XGXS_FLAG), + REG_RD(bp, NIG_REG_STATUS_INTERRUPT_PORT0 + port*4)); + + is_mi_int = (u8)(REG_RD(bp, NIG_REG_EMAC0_STATUS_MISC_MI_INT + + port*0x18) > 0); + DP(NETIF_MSG_LINK, "int_mask 0x%x MI_INT %x, SERDES_LINK %x\n", + REG_RD(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4), + is_mi_int, + REG_RD(bp, NIG_REG_SERDES0_STATUS_LINK_STATUS + port*0x3c)); + + DP(NETIF_MSG_LINK, " 10G %x, XGXS_LINK %x\n", + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK10G + port*0x68), + REG_RD(bp, NIG_REG_XGXS0_STATUS_LINK_STATUS + port*0x68)); + + /* disable emac */ + if (!CHIP_IS_E3(bp)) + REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0); + + /* + * Step 1: + * Check external link change only for external phys, and apply + * priority selection between them in case the link on both phys + * is up. Note that instead of the common vars, a temporary + * vars argument is used since each phy may have different link/ + * speed/duplex result + */ + for (phy_index = EXT_PHY1; phy_index < params->num_phys; + phy_index++) { + struct bnx2x_phy *phy = ¶ms->phy[phy_index]; + if (!phy->read_status) + continue; + /* Read link status and params of this ext phy */ + cur_link_up = phy->read_status(phy, params, + &phy_vars[phy_index]); + if (cur_link_up) { + DP(NETIF_MSG_LINK, "phy in index %d link is up\n", + phy_index); + } else { + DP(NETIF_MSG_LINK, "phy in index %d link is down\n", + phy_index); + continue; + } + + if (!ext_phy_link_up) { + ext_phy_link_up = 1; + active_external_phy = phy_index; + } else { + switch (bnx2x_phy_selection(params)) { + case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: + /* + * In this option, the first PHY makes sure to pass the + * traffic through itself only. + * Its not clear how to reset the link on the second phy + */ + active_external_phy = EXT_PHY1; + break; + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: + /* + * In this option, the first PHY makes sure to pass the + * traffic through the second PHY. + */ + active_external_phy = EXT_PHY2; + break; + default: + /* + * Link indication on both PHYs with the following cases + * is invalid: + * - FIRST_PHY means that second phy wasn't initialized, + * hence its link is expected to be down + * - SECOND_PHY means that first phy should not be able + * to link up by itself (using configuration) + * - DEFAULT should be overriden during initialiazation + */ + DP(NETIF_MSG_LINK, "Invalid link indication" + "mpc=0x%x. DISABLING LINK !!!\n", + params->multi_phy_config); + ext_phy_link_up = 0; + break; + } + } + } + prev_line_speed = vars->line_speed; + /* + * Step 2: + * Read the status of the internal phy. In case of + * DIRECT_SINGLE_MEDIA board, this link is the external link, + * otherwise this is the link between the 577xx and the first + * external phy + */ + if (params->phy[INT_PHY].read_status) + params->phy[INT_PHY].read_status( + ¶ms->phy[INT_PHY], + params, vars); + /* + * The INT_PHY flow control reside in the vars. This include the + * case where the speed or flow control are not set to AUTO. + * Otherwise, the active external phy flow control result is set + * to the vars. The ext_phy_line_speed is needed to check if the + * speed is different between the internal phy and external phy. + * This case may be result of intermediate link speed change. + */ + if (active_external_phy > INT_PHY) { + vars->flow_ctrl = phy_vars[active_external_phy].flow_ctrl; + /* + * Link speed is taken from the XGXS. AN and FC result from + * the external phy. + */ + vars->link_status |= phy_vars[active_external_phy].link_status; + + /* + * if active_external_phy is first PHY and link is up - disable + * disable TX on second external PHY + */ + if (active_external_phy == EXT_PHY1) { + if (params->phy[EXT_PHY2].phy_specific_func) { + DP(NETIF_MSG_LINK, "Disabling TX on" + " EXT_PHY2\n"); + params->phy[EXT_PHY2].phy_specific_func( + ¶ms->phy[EXT_PHY2], + params, DISABLE_TX); + } + } + + ext_phy_line_speed = phy_vars[active_external_phy].line_speed; + vars->duplex = phy_vars[active_external_phy].duplex; + if (params->phy[active_external_phy].supported & + SUPPORTED_FIBRE) + vars->link_status |= LINK_STATUS_SERDES_LINK; + else + vars->link_status &= ~LINK_STATUS_SERDES_LINK; + DP(NETIF_MSG_LINK, "Active external phy selected: %x\n", + active_external_phy); + } + + for (phy_index = EXT_PHY1; phy_index < params->num_phys; + phy_index++) { + if (params->phy[phy_index].flags & + FLAGS_REARM_LATCH_SIGNAL) { + bnx2x_rearm_latch_signal(bp, port, + phy_index == + active_external_phy); + break; + } + } + DP(NETIF_MSG_LINK, "vars->flow_ctrl = 0x%x, vars->link_status = 0x%x," + " ext_phy_line_speed = %d\n", vars->flow_ctrl, + vars->link_status, ext_phy_line_speed); + /* + * Upon link speed change set the NIG into drain mode. Comes to + * deals with possible FIFO glitch due to clk change when speed + * is decreased without link down indicator + */ + + if (vars->phy_link_up) { + if (!(SINGLE_MEDIA_DIRECT(params)) && ext_phy_link_up && + (ext_phy_line_speed != vars->line_speed)) { + DP(NETIF_MSG_LINK, "Internal link speed %d is" + " different than the external" + " link speed %d\n", vars->line_speed, + ext_phy_line_speed); + vars->phy_link_up = 0; + } else if (prev_line_speed != vars->line_speed) { + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, + 0); + msleep(1); + } + } + + /* anything 10 and over uses the bmac */ + link_10g_plus = (vars->line_speed >= SPEED_10000); + + bnx2x_link_int_ack(params, vars, link_10g_plus); + + /* + * In case external phy link is up, and internal link is down + * (not initialized yet probably after link initialization, it + * needs to be initialized. + * Note that after link down-up as result of cable plug, the xgxs + * link would probably become up again without the need + * initialize it + */ + if (!(SINGLE_MEDIA_DIRECT(params))) { + DP(NETIF_MSG_LINK, "ext_phy_link_up = %d, int_link_up = %d," + " init_preceding = %d\n", ext_phy_link_up, + vars->phy_link_up, + params->phy[EXT_PHY1].flags & + FLAGS_INIT_XGXS_FIRST); + if (!(params->phy[EXT_PHY1].flags & + FLAGS_INIT_XGXS_FIRST) + && ext_phy_link_up && !vars->phy_link_up) { + vars->line_speed = ext_phy_line_speed; + if (vars->line_speed < SPEED_1000) + vars->phy_flags |= PHY_SGMII_FLAG; + else + vars->phy_flags &= ~PHY_SGMII_FLAG; + + if (params->phy[INT_PHY].config_init) + params->phy[INT_PHY].config_init( + ¶ms->phy[INT_PHY], params, + vars); + } + } + /* + * Link is up only if both local phy and external phy (in case of + * non-direct board) are up and no fault detected on active PHY. + */ + vars->link_up = (vars->phy_link_up && + (ext_phy_link_up || + SINGLE_MEDIA_DIRECT(params)) && + (phy_vars[active_external_phy].fault_detected == 0)); + + if (vars->link_up) + rc = bnx2x_update_link_up(params, vars, link_10g_plus); + else + rc = bnx2x_update_link_down(params, vars); + + return rc; +} + + +/*****************************************************************************/ +/* External Phy section */ +/*****************************************************************************/ +void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port) +{ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW, port); + msleep(1); + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_HIGH, port); +} + +static void bnx2x_save_spirom_version(struct bnx2x *bp, u8 port, + u32 spirom_ver, u32 ver_addr) +{ + DP(NETIF_MSG_LINK, "FW version 0x%x:0x%x for port %d\n", + (u16)(spirom_ver>>16), (u16)spirom_ver, port); + + if (ver_addr) + REG_WR(bp, ver_addr, spirom_ver); +} + +static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp, + struct bnx2x_phy *phy, + u8 port) +{ + u16 fw_ver1, fw_ver2; + + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER1, &fw_ver1); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, &fw_ver2); + bnx2x_save_spirom_version(bp, port, (u32)(fw_ver1<<16 | fw_ver2), + phy->ver_addr); +} + +static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp, + struct bnx2x_phy *phy, + struct link_vars *vars) +{ + u16 val; + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_STATUS, &val); + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_STATUS, &val); + if (val & (1<<5)) + vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_COMPLETE; + if ((val & (1<<0)) == 0) + vars->link_status |= LINK_STATUS_PARALLEL_DETECTION_USED; +} + +/******************************************************************/ +/* common BCM8073/BCM8727 PHY SECTION */ +/******************************************************************/ +static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + if (phy->req_line_speed == SPEED_10 || + phy->req_line_speed == SPEED_100) { + vars->flow_ctrl = phy->req_flow_ctrl; + return; + } + + if (bnx2x_ext_phy_resolve_fc(phy, params, vars) && + (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE)) { + u16 pause_result; + u16 ld_pause; /* local */ + u16 lp_pause; /* link partner */ + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_FC_LD, &ld_pause); + + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_CL37_FC_LP, &lp_pause); + pause_result = (ld_pause & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 5; + pause_result |= (lp_pause & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) >> 7; + + bnx2x_pause_resolve(vars, pause_result); + DP(NETIF_MSG_LINK, "Ext PHY CL37 pause result 0x%x\n", + pause_result); + } +} +static int bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp, + struct bnx2x_phy *phy, + u8 port) +{ + u32 count = 0; + u16 fw_ver1, fw_msgout; + int rc = 0; + + /* Boot port from external ROM */ + /* EDC grst */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + 0x0001); + + /* ucode reboot and rst */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + 0x008c); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0001); + + /* Reset internal microprocessor */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET); + + /* Release srst bit */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP); + + /* Delay 100ms per the PHY specifications */ + msleep(100); + + /* 8073 sometimes taking longer to download */ + do { + count++; + if (count > 300) { + DP(NETIF_MSG_LINK, + "bnx2x_8073_8727_external_rom_boot port %x:" + "Download failed. fw version = 0x%x\n", + port, fw_ver1); + rc = -EINVAL; + break; + } + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER1, &fw_ver1); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_M8051_MSGOUT_REG, &fw_msgout); + + msleep(1); + } while (fw_ver1 == 0 || fw_ver1 == 0x4321 || + ((fw_msgout & 0xff) != 0x03 && (phy->type == + PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073))); + + /* Clear ser_boot_ctl bit */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0000); + bnx2x_save_bcm_spirom_ver(bp, phy, port); + + DP(NETIF_MSG_LINK, + "bnx2x_8073_8727_external_rom_boot port %x:" + "Download complete. fw version = 0x%x\n", + port, fw_ver1); + + return rc; +} + +/******************************************************************/ +/* BCM8073 PHY SECTION */ +/******************************************************************/ +static int bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy) +{ + /* This is only required for 8073A1, version 102 only */ + u16 val; + + /* Read 8073 HW revision*/ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_CHIP_REV, &val); + + if (val != 1) { + /* No need to workaround in 8073 A1 */ + return 0; + } + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, &val); + + /* SNR should be applied only for version 0x102 */ + if (val != 0x102) + return 0; + + return 1; +} + +static int bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy) +{ + u16 val, cnt, cnt1 ; + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_CHIP_REV, &val); + + if (val > 0) { + /* No need to workaround in 8073 A1 */ + return 0; + } + /* XAUI workaround in 8073 A0: */ + + /* + * After loading the boot ROM and restarting Autoneg, poll + * Dev1, Reg $C820: + */ + + for (cnt = 0; cnt < 1000; cnt++) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_SPEED_LINK_STATUS, + &val); + /* + * If bit [14] = 0 or bit [13] = 0, continue on with + * system initialization (XAUI work-around not required, as + * these bits indicate 2.5G or 1G link up). + */ + if (!(val & (1<<14)) || !(val & (1<<13))) { + DP(NETIF_MSG_LINK, "XAUI work-around not required\n"); + return 0; + } else if (!(val & (1<<15))) { + DP(NETIF_MSG_LINK, "bit 15 went off\n"); + /* + * If bit 15 is 0, then poll Dev1, Reg $C841 until it's + * MSB (bit15) goes to 1 (indicating that the XAUI + * workaround has completed), then continue on with + * system initialization. + */ + for (cnt1 = 0; cnt1 < 1000; cnt1++) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_XAUI_WA, &val); + if (val & (1<<15)) { + DP(NETIF_MSG_LINK, + "XAUI workaround has completed\n"); + return 0; + } + msleep(3); + } + break; + } + msleep(3); + } + DP(NETIF_MSG_LINK, "Warning: XAUI work-around timeout !!!\n"); + return -EINVAL; +} + +static void bnx2x_807x_force_10G(struct bnx2x *bp, struct bnx2x_phy *phy) +{ + /* Force KR or KX */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0x000b); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0000); + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000); +} + +static void bnx2x_8073_set_pause_cl37(struct link_params *params, + struct bnx2x_phy *phy, + struct link_vars *vars) +{ + u16 cl37_val; + struct bnx2x *bp = params->bp; + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &cl37_val); + + cl37_val &= ~MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; + /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */ + bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc); + if ((vars->ieee_fc & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) == + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC) { + cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_SYMMETRIC; + } + if ((vars->ieee_fc & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) == + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) { + cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; + } + if ((vars->ieee_fc & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) == + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) { + cl37_val |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; + } + DP(NETIF_MSG_LINK, + "Ext phy AN advertize cl37 0x%x\n", cl37_val); + + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, cl37_val); + msleep(500); +} + +static int bnx2x_8073_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 val = 0, tmp1; + u8 gpio_port; + DP(NETIF_MSG_LINK, "Init 8073\n"); + + if (CHIP_IS_E2(bp)) + gpio_port = BP_PATH(bp); + else + gpio_port = params->port; + /* Restore normal power mode*/ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port); + + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_HIGH, gpio_port); + + /* enable LASI */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL, (1<<2)); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 0x0004); + + bnx2x_8073_set_pause_cl37(params, phy, vars); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT, &tmp1); + + DP(NETIF_MSG_LINK, "Before rom RX_ALARM(port1): 0x%x\n", tmp1); + + /* Swap polarity if required - Must be done only in non-1G mode */ + if (params->lane_config & PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) { + /* Configure the 8073 to swap _P and _N of the KR lines */ + DP(NETIF_MSG_LINK, "Swapping polarity for the 8073\n"); + /* 10G Rx/Tx and 1G Tx signal polarity swap */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, &val); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_OPT_DIGITAL_CTRL, + (val | (3<<9))); + } + + + /* Enable CL37 BAM */ + if (REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_hw_config[params->port].default_cfg)) & + PORT_HW_CFG_ENABLE_BAM_ON_KR_ENABLED) { + + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_8073_BAM, &val); + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_8073_BAM, val | 1); + DP(NETIF_MSG_LINK, "Enable CL37 BAM on KR\n"); + } + if (params->loopback_mode == LOOPBACK_EXT) { + bnx2x_807x_force_10G(bp, phy); + DP(NETIF_MSG_LINK, "Forced speed 10G on 807X\n"); + return 0; + } else { + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_BCM_CTRL, 0x0002); + } + if (phy->req_line_speed != SPEED_AUTO_NEG) { + if (phy->req_line_speed == SPEED_10000) { + val = (1<<7); + } else if (phy->req_line_speed == SPEED_2500) { + val = (1<<5); + /* + * Note that 2.5G works only when used with 1G + * advertisement + */ + } else + val = (1<<5); + } else { + val = 0; + if (phy->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) + val |= (1<<7); + + /* Note that 2.5G works only when used with 1G advertisement */ + if (phy->speed_cap_mask & + (PORT_HW_CFG_SPEED_CAPABILITY_D0_1G | + PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)) + val |= (1<<5); + DP(NETIF_MSG_LINK, "807x autoneg val = 0x%x\n", val); + } + + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV, val); + bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, &tmp1); + + if (((phy->speed_cap_mask & PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G) && + (phy->req_line_speed == SPEED_AUTO_NEG)) || + (phy->req_line_speed == SPEED_2500)) { + u16 phy_ver; + /* Allow 2.5G for A1 and above */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_CHIP_REV, + &phy_ver); + DP(NETIF_MSG_LINK, "Add 2.5G\n"); + if (phy_ver > 0) + tmp1 |= 1; + else + tmp1 &= 0xfffe; + } else { + DP(NETIF_MSG_LINK, "Disable 2.5G\n"); + tmp1 &= 0xfffe; + } + + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_8073_2_5G, tmp1); + /* Add support for CL37 (passive mode) II */ + + bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, &tmp1); + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, + (tmp1 | ((phy->req_duplex == DUPLEX_FULL) ? + 0x20 : 0x40))); + + /* Add support for CL37 (passive mode) III */ + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000); + + /* + * The SNR will improve about 2db by changing BW and FEE main + * tap. Rest commands are executed after link is up + * Change FFE main cursor to 5 in EDC register + */ + if (bnx2x_8073_is_snr_needed(bp, phy)) + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_EDC_FFE_MAIN, + 0xFB0C); + + /* Enable FEC (Forware Error Correction) Request in the AN */ + bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, &tmp1); + tmp1 |= (1<<15); + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV2, tmp1); + + bnx2x_ext_phy_set_pause(params, phy, vars); + + /* Restart autoneg */ + msleep(500); + bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200); + DP(NETIF_MSG_LINK, "807x Autoneg Restart: Advertise 1G=%x, 10G=%x\n", + ((val & (1<<5)) > 0), ((val & (1<<7)) > 0)); + return 0; +} + +static u8 bnx2x_8073_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 link_up = 0; + u16 val1, val2; + u16 link_status = 0; + u16 an1000_status = 0; + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val1); + + DP(NETIF_MSG_LINK, "8703 LASI status 0x%x\n", val1); + + /* clear the interrupt LASI status register */ + bnx2x_cl45_read(bp, phy, + MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2); + bnx2x_cl45_read(bp, phy, + MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val1); + DP(NETIF_MSG_LINK, "807x PCS status 0x%x->0x%x\n", val2, val1); + /* Clear MSG-OUT */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1); + + /* Check the LASI */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT, &val2); + + DP(NETIF_MSG_LINK, "KR 0x9003 0x%x\n", val2); + + /* Check the link status */ + bnx2x_cl45_read(bp, phy, + MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &val2); + DP(NETIF_MSG_LINK, "KR PCS status 0x%x\n", val2); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1); + link_up = ((val1 & 4) == 4); + DP(NETIF_MSG_LINK, "PMA_REG_STATUS=0x%x\n", val1); + + if (link_up && + ((phy->req_line_speed != SPEED_10000))) { + if (bnx2x_8073_xaui_wa(bp, phy) != 0) + return 0; + } + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status); + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &an1000_status); + + /* Check the link status on 1.1.2 */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1); + DP(NETIF_MSG_LINK, "KR PMA status 0x%x->0x%x," + "an_link_status=0x%x\n", val2, val1, an1000_status); + + link_up = (((val1 & 4) == 4) || (an1000_status & (1<<1))); + if (link_up && bnx2x_8073_is_snr_needed(bp, phy)) { + /* + * The SNR will improve about 2dbby changing the BW and FEE main + * tap. The 1st write to change FFE main tap is set before + * restart AN. Change PLL Bandwidth in EDC register + */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_PLL_BANDWIDTH, + 0x26BC); + + /* Change CDR Bandwidth in EDC register */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_CDR_BANDWIDTH, + 0x0333); + } + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8073_SPEED_LINK_STATUS, + &link_status); + + /* Bits 0..2 --> speed detected, bits 13..15--> link is down */ + if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) { + link_up = 1; + vars->line_speed = SPEED_10000; + DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n", + params->port); + } else if ((link_status & (1<<1)) && (!(link_status & (1<<14)))) { + link_up = 1; + vars->line_speed = SPEED_2500; + DP(NETIF_MSG_LINK, "port %x: External link up in 2.5G\n", + params->port); + } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) { + link_up = 1; + vars->line_speed = SPEED_1000; + DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n", + params->port); + } else { + link_up = 0; + DP(NETIF_MSG_LINK, "port %x: External link is down\n", + params->port); + } + + if (link_up) { + /* Swap polarity if required */ + if (params->lane_config & + PORT_HW_CFG_SWAP_PHY_POLARITY_ENABLED) { + /* Configure the 8073 to swap P and N of the KR lines */ + bnx2x_cl45_read(bp, phy, + MDIO_XS_DEVAD, + MDIO_XS_REG_8073_RX_CTRL_PCIE, &val1); + /* + * Set bit 3 to invert Rx in 1G mode and clear this bit + * when it`s in 10G mode. + */ + if (vars->line_speed == SPEED_1000) { + DP(NETIF_MSG_LINK, "Swapping 1G polarity for" + "the 8073\n"); + val1 |= (1<<3); + } else + val1 &= ~(1<<3); + + bnx2x_cl45_write(bp, phy, + MDIO_XS_DEVAD, + MDIO_XS_REG_8073_RX_CTRL_PCIE, + val1); + } + bnx2x_ext_phy_10G_an_resolve(bp, phy, vars); + bnx2x_8073_resolve_fc(phy, params, vars); + vars->duplex = DUPLEX_FULL; + } + return link_up; +} + +static void bnx2x_8073_link_reset(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 gpio_port; + if (CHIP_IS_E2(bp)) + gpio_port = BP_PATH(bp); + else + gpio_port = params->port; + DP(NETIF_MSG_LINK, "Setting 8073 port %d into low power mode\n", + gpio_port); + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_LOW, + gpio_port); +} + +/******************************************************************/ +/* BCM8705 PHY SECTION */ +/******************************************************************/ +static int bnx2x_8705_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "init 8705\n"); + /* Restore normal power mode*/ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); + /* HW reset */ + bnx2x_ext_phy_hw_reset(bp, params->port); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040); + bnx2x_wait_reset_complete(bp, phy, params); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_MISC_CTRL, 0x8288); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, 0x7fbf); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_CMU_PLL_BYPASS, 0x0100); + bnx2x_cl45_write(bp, phy, + MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_CNTL, 0x1); + /* BCM8705 doesn't have microcode, hence the 0 */ + bnx2x_save_spirom_version(bp, params->port, params->shmem_base, 0); + return 0; +} + +static u8 bnx2x_8705_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + u8 link_up = 0; + u16 val1, rx_sd; + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "read status 8705\n"); + bnx2x_cl45_read(bp, phy, + MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1); + DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1); + + bnx2x_cl45_read(bp, phy, + MDIO_WIS_DEVAD, MDIO_WIS_REG_LASI_STATUS, &val1); + DP(NETIF_MSG_LINK, "8705 LASI status 0x%x\n", val1); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, 0xc809, &val1); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, 0xc809, &val1); + + DP(NETIF_MSG_LINK, "8705 1.c809 val=0x%x\n", val1); + link_up = ((rx_sd & 0x1) && (val1 & (1<<9)) && ((val1 & (1<<8)) == 0)); + if (link_up) { + vars->line_speed = SPEED_10000; + bnx2x_ext_phy_resolve_fc(phy, params, vars); + } + return link_up; +} + +/******************************************************************/ +/* SFP+ module Section */ +/******************************************************************/ +static void bnx2x_set_disable_pmd_transmit(struct link_params *params, + struct bnx2x_phy *phy, + u8 pmd_dis) +{ + struct bnx2x *bp = params->bp; + /* + * Disable transmitter only for bootcodes which can enable it afterwards + * (for D3 link) + */ + if (pmd_dis) { + if (params->feature_config_flags & + FEATURE_CONFIG_BC_SUPPORTS_SFP_TX_DISABLED) + DP(NETIF_MSG_LINK, "Disabling PMD transmitter\n"); + else { + DP(NETIF_MSG_LINK, "NOT disabling PMD transmitter\n"); + return; + } + } else + DP(NETIF_MSG_LINK, "Enabling PMD transmitter\n"); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_DISABLE, pmd_dis); +} + +static u8 bnx2x_get_gpio_port(struct link_params *params) +{ + u8 gpio_port; + u32 swap_val, swap_override; + struct bnx2x *bp = params->bp; + if (CHIP_IS_E2(bp)) + gpio_port = BP_PATH(bp); + else + gpio_port = params->port; + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + return gpio_port ^ (swap_val && swap_override); +} + +static void bnx2x_sfp_e1e2_set_transmitter(struct link_params *params, + struct bnx2x_phy *phy, + u8 tx_en) +{ + u16 val; + u8 port = params->port; + struct bnx2x *bp = params->bp; + u32 tx_en_mode; + + /* Disable/Enable transmitter ( TX laser of the SFP+ module.)*/ + tx_en_mode = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].sfp_ctrl)) & + PORT_HW_CFG_TX_LASER_MASK; + DP(NETIF_MSG_LINK, "Setting transmitter tx_en=%x for port %x " + "mode = %x\n", tx_en, port, tx_en_mode); + switch (tx_en_mode) { + case PORT_HW_CFG_TX_LASER_MDIO: + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + &val); + + if (tx_en) + val &= ~(1<<15); + else + val |= (1<<15); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + val); + break; + case PORT_HW_CFG_TX_LASER_GPIO0: + case PORT_HW_CFG_TX_LASER_GPIO1: + case PORT_HW_CFG_TX_LASER_GPIO2: + case PORT_HW_CFG_TX_LASER_GPIO3: + { + u16 gpio_pin; + u8 gpio_port, gpio_mode; + if (tx_en) + gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_HIGH; + else + gpio_mode = MISC_REGISTERS_GPIO_OUTPUT_LOW; + + gpio_pin = tx_en_mode - PORT_HW_CFG_TX_LASER_GPIO0; + gpio_port = bnx2x_get_gpio_port(params); + bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port); + break; + } + default: + DP(NETIF_MSG_LINK, "Invalid TX_LASER_MDIO 0x%x\n", tx_en_mode); + break; + } +} + +static void bnx2x_sfp_set_transmitter(struct link_params *params, + struct bnx2x_phy *phy, + u8 tx_en) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "Setting SFP+ transmitter to %d\n", tx_en); + if (CHIP_IS_E3(bp)) + bnx2x_sfp_e3_set_transmitter(params, phy, tx_en); + else + bnx2x_sfp_e1e2_set_transmitter(params, phy, tx_en); +} + +static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy, + struct link_params *params, + u16 addr, u8 byte_cnt, u8 *o_buf) +{ + struct bnx2x *bp = params->bp; + u16 val = 0; + u16 i; + if (byte_cnt > 16) { + DP(NETIF_MSG_LINK, "Reading from eeprom is" + " is limited to 0xf\n"); + return -EINVAL; + } + /* Set the read command byte count */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT, + (byte_cnt | 0xa000)); + + /* Set the read command address */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR, + addr); + + /* Activate read command */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, + 0x2c0f); + + /* Wait up to 500us for command complete status */ + for (i = 0; i < 100; i++) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) + break; + udelay(5); + } + + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) != + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) { + DP(NETIF_MSG_LINK, + "Got bad status 0x%x when reading from SFP+ EEPROM\n", + (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK)); + return -EINVAL; + } + + /* Read the buffer */ + for (i = 0; i < byte_cnt; i++) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8726_TWO_WIRE_DATA_BUF + i, &val); + o_buf[i] = (u8)(val & MDIO_PMA_REG_8726_TWO_WIRE_DATA_MASK); + } + + for (i = 0; i < 100; i++) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) + return 0; + msleep(1); + } + return -EINVAL; +} + +static int bnx2x_warpcore_read_sfp_module_eeprom(struct bnx2x_phy *phy, + struct link_params *params, + u16 addr, u8 byte_cnt, + u8 *o_buf) +{ + int rc = 0; + u8 i, j = 0, cnt = 0; + u32 data_array[4]; + u16 addr32; + struct bnx2x *bp = params->bp; + /*DP(NETIF_MSG_LINK, "bnx2x_direct_read_sfp_module_eeprom:" + " addr %d, cnt %d\n", + addr, byte_cnt);*/ + if (byte_cnt > 16) { + DP(NETIF_MSG_LINK, "Reading from eeprom is" + " is limited to 16 bytes\n"); + return -EINVAL; + } + + /* 4 byte aligned address */ + addr32 = addr & (~0x3); + do { + rc = bnx2x_bsc_read(params, phy, 0xa0, addr32, 0, byte_cnt, + data_array); + } while ((rc != 0) && (++cnt < I2C_WA_RETRY_CNT)); + + if (rc == 0) { + for (i = (addr - addr32); i < byte_cnt + (addr - addr32); i++) { + o_buf[j] = *((u8 *)data_array + i); + j++; + } + } + + return rc; +} + +static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy, + struct link_params *params, + u16 addr, u8 byte_cnt, u8 *o_buf) +{ + struct bnx2x *bp = params->bp; + u16 val, i; + + if (byte_cnt > 16) { + DP(NETIF_MSG_LINK, "Reading from eeprom is" + " is limited to 0xf\n"); + return -EINVAL; + } + + /* Need to read from 1.8000 to clear it */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, + &val); + + /* Set the read command byte count */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_BYTE_CNT, + ((byte_cnt < 2) ? 2 : byte_cnt)); + + /* Set the read command address */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_MEM_ADDR, + addr); + /* Set the destination address */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + 0x8004, + MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF); + + /* Activate read command */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, + 0x8002); + /* + * Wait appropriate time for two-wire command to finish before + * polling the status register + */ + msleep(1); + + /* Wait up to 500us for command complete status */ + for (i = 0; i < 100; i++) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) + break; + udelay(5); + } + + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) != + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_COMPLETE) { + DP(NETIF_MSG_LINK, + "Got bad status 0x%x when reading from SFP+ EEPROM\n", + (val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK)); + return -EFAULT; + } + + /* Read the buffer */ + for (i = 0; i < byte_cnt; i++) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_TWO_WIRE_DATA_BUF + i, &val); + o_buf[i] = (u8)(val & MDIO_PMA_REG_8727_TWO_WIRE_DATA_MASK); + } + + for (i = 0; i < 100; i++) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_SFP_TWO_WIRE_CTRL, &val); + if ((val & MDIO_PMA_REG_SFP_TWO_WIRE_CTRL_STATUS_MASK) == + MDIO_PMA_REG_SFP_TWO_WIRE_STATUS_IDLE) + return 0; + msleep(1); + } + + return -EINVAL; +} + +int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy, + struct link_params *params, u16 addr, + u8 byte_cnt, u8 *o_buf) +{ + int rc = -EINVAL; + switch (phy->type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + rc = bnx2x_8726_read_sfp_module_eeprom(phy, params, addr, + byte_cnt, o_buf); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722: + rc = bnx2x_8727_read_sfp_module_eeprom(phy, params, addr, + byte_cnt, o_buf); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + rc = bnx2x_warpcore_read_sfp_module_eeprom(phy, params, addr, + byte_cnt, o_buf); + break; + } + return rc; +} + +static int bnx2x_get_edc_mode(struct bnx2x_phy *phy, + struct link_params *params, + u16 *edc_mode) +{ + struct bnx2x *bp = params->bp; + u32 sync_offset = 0, phy_idx, media_types; + u8 val, check_limiting_mode = 0; + *edc_mode = EDC_MODE_LIMITING; + + phy->media_type = ETH_PHY_UNSPECIFIED; + /* First check for copper cable */ + if (bnx2x_read_sfp_module_eeprom(phy, + params, + SFP_EEPROM_CON_TYPE_ADDR, + 1, + &val) != 0) { + DP(NETIF_MSG_LINK, "Failed to read from SFP+ module EEPROM\n"); + return -EINVAL; + } + + switch (val) { + case SFP_EEPROM_CON_TYPE_VAL_COPPER: + { + u8 copper_module_type; + phy->media_type = ETH_PHY_DA_TWINAX; + /* + * Check if its active cable (includes SFP+ module) + * of passive cable + */ + if (bnx2x_read_sfp_module_eeprom(phy, + params, + SFP_EEPROM_FC_TX_TECH_ADDR, + 1, + &copper_module_type) != 0) { + DP(NETIF_MSG_LINK, + "Failed to read copper-cable-type" + " from SFP+ EEPROM\n"); + return -EINVAL; + } + + if (copper_module_type & + SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_ACTIVE) { + DP(NETIF_MSG_LINK, "Active Copper cable detected\n"); + check_limiting_mode = 1; + } else if (copper_module_type & + SFP_EEPROM_FC_TX_TECH_BITMASK_COPPER_PASSIVE) { + DP(NETIF_MSG_LINK, "Passive Copper" + " cable detected\n"); + *edc_mode = + EDC_MODE_PASSIVE_DAC; + } else { + DP(NETIF_MSG_LINK, "Unknown copper-cable-" + "type 0x%x !!!\n", copper_module_type); + return -EINVAL; + } + break; + } + case SFP_EEPROM_CON_TYPE_VAL_LC: + phy->media_type = ETH_PHY_SFP_FIBER; + DP(NETIF_MSG_LINK, "Optic module detected\n"); + check_limiting_mode = 1; + break; + default: + DP(NETIF_MSG_LINK, "Unable to determine module type 0x%x !!!\n", + val); + return -EINVAL; + } + sync_offset = params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].media_type); + media_types = REG_RD(bp, sync_offset); + /* Update media type for non-PMF sync */ + for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) { + if (&(params->phy[phy_idx]) == phy) { + media_types &= ~(PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK << + (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx)); + media_types |= ((phy->media_type & + PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) << + (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx)); + break; + } + } + REG_WR(bp, sync_offset, media_types); + if (check_limiting_mode) { + u8 options[SFP_EEPROM_OPTIONS_SIZE]; + if (bnx2x_read_sfp_module_eeprom(phy, + params, + SFP_EEPROM_OPTIONS_ADDR, + SFP_EEPROM_OPTIONS_SIZE, + options) != 0) { + DP(NETIF_MSG_LINK, "Failed to read Option" + " field from module EEPROM\n"); + return -EINVAL; + } + if ((options[0] & SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK)) + *edc_mode = EDC_MODE_LINEAR; + else + *edc_mode = EDC_MODE_LIMITING; + } + DP(NETIF_MSG_LINK, "EDC mode is set to 0x%x\n", *edc_mode); + return 0; +} +/* + * This function read the relevant field from the module (SFP+), and verify it + * is compliant with this board + */ +static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u32 val, cmd; + u32 fw_resp, fw_cmd_param; + char vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE+1]; + char vendor_pn[SFP_EEPROM_PART_NO_SIZE+1]; + phy->flags &= ~FLAGS_SFP_NOT_APPROVED; + val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port].config)); + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_NO_ENFORCEMENT) { + DP(NETIF_MSG_LINK, "NOT enforcing module verification\n"); + return 0; + } + + if (params->feature_config_flags & + FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY) { + /* Use specific phy request */ + cmd = DRV_MSG_CODE_VRFY_SPECIFIC_PHY_OPT_MDL; + } else if (params->feature_config_flags & + FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY) { + /* Use first phy request only in case of non-dual media*/ + if (DUAL_MEDIA(params)) { + DP(NETIF_MSG_LINK, "FW does not support OPT MDL " + "verification\n"); + return -EINVAL; + } + cmd = DRV_MSG_CODE_VRFY_FIRST_PHY_OPT_MDL; + } else { + /* No support in OPT MDL detection */ + DP(NETIF_MSG_LINK, "FW does not support OPT MDL " + "verification\n"); + return -EINVAL; + } + + fw_cmd_param = FW_PARAM_SET(phy->addr, phy->type, phy->mdio_ctrl); + fw_resp = bnx2x_fw_command(bp, cmd, fw_cmd_param); + if (fw_resp == FW_MSG_CODE_VRFY_OPT_MDL_SUCCESS) { + DP(NETIF_MSG_LINK, "Approved module\n"); + return 0; + } + + /* format the warning message */ + if (bnx2x_read_sfp_module_eeprom(phy, + params, + SFP_EEPROM_VENDOR_NAME_ADDR, + SFP_EEPROM_VENDOR_NAME_SIZE, + (u8 *)vendor_name)) + vendor_name[0] = '\0'; + else + vendor_name[SFP_EEPROM_VENDOR_NAME_SIZE] = '\0'; + if (bnx2x_read_sfp_module_eeprom(phy, + params, + SFP_EEPROM_PART_NO_ADDR, + SFP_EEPROM_PART_NO_SIZE, + (u8 *)vendor_pn)) + vendor_pn[0] = '\0'; + else + vendor_pn[SFP_EEPROM_PART_NO_SIZE] = '\0'; + + netdev_err(bp->dev, "Warning: Unqualified SFP+ module detected," + " Port %d from %s part number %s\n", + params->port, vendor_name, vendor_pn); + phy->flags |= FLAGS_SFP_NOT_APPROVED; + return -EINVAL; +} + +static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy, + struct link_params *params) + +{ + u8 val; + struct bnx2x *bp = params->bp; + u16 timeout; + /* + * Initialization time after hot-plug may take up to 300ms for + * some phys type ( e.g. JDSU ) + */ + + for (timeout = 0; timeout < 60; timeout++) { + if (bnx2x_read_sfp_module_eeprom(phy, params, 1, 1, &val) + == 0) { + DP(NETIF_MSG_LINK, "SFP+ module initialization " + "took %d ms\n", timeout * 5); + return 0; + } + msleep(5); + } + return -EINVAL; +} + +static void bnx2x_8727_power_module(struct bnx2x *bp, + struct bnx2x_phy *phy, + u8 is_power_up) { + /* Make sure GPIOs are not using for LED mode */ + u16 val; + /* + * In the GPIO register, bit 4 is use to determine if the GPIOs are + * operating as INPUT or as OUTPUT. Bit 1 is for input, and 0 for + * output + * Bits 0-1 determine the GPIOs value for OUTPUT in case bit 4 val is 0 + * Bits 8-9 determine the GPIOs value for INPUT in case bit 4 val is 1 + * where the 1st bit is the over-current(only input), and 2nd bit is + * for power( only output ) + * + * In case of NOC feature is disabled and power is up, set GPIO control + * as input to enable listening of over-current indication + */ + if (phy->flags & FLAGS_NOC) + return; + if (is_power_up) + val = (1<<4); + else + /* + * Set GPIO control to OUTPUT, and set the power bit + * to according to the is_power_up + */ + val = (1<<1); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_GPIO_CTRL, + val); +} + +static int bnx2x_8726_set_limiting_mode(struct bnx2x *bp, + struct bnx2x_phy *phy, + u16 edc_mode) +{ + u16 cur_limiting_mode; + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + &cur_limiting_mode); + DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n", + cur_limiting_mode); + + if (edc_mode == EDC_MODE_LIMITING) { + DP(NETIF_MSG_LINK, "Setting LIMITING MODE\n"); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + EDC_MODE_LIMITING); + } else { /* LRM mode ( default )*/ + + DP(NETIF_MSG_LINK, "Setting LRM MODE\n"); + + /* + * Changing to LRM mode takes quite few seconds. So do it only + * if current mode is limiting (default is LRM) + */ + if (cur_limiting_mode != EDC_MODE_LIMITING) + return 0; + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LRM_MODE, + 0); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + 0x128); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL0, + 0x4008); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_LRM_MODE, + 0xaaaa); + } + return 0; +} + +static int bnx2x_8727_set_limiting_mode(struct bnx2x *bp, + struct bnx2x_phy *phy, + u16 edc_mode) +{ + u16 phy_identifier; + u16 rom_ver2_val; + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + &phy_identifier); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + (phy_identifier & ~(1<<9))); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + &rom_ver2_val); + /* Keep the MSB 8-bits, and set the LSB 8-bits with the edc_mode */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_ROM_VER2, + (rom_ver2_val & 0xff00) | (edc_mode & 0x00ff)); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, + (phy_identifier | (1<<9))); + + return 0; +} + +static void bnx2x_8727_specific_func(struct bnx2x_phy *phy, + struct link_params *params, + u32 action) +{ + struct bnx2x *bp = params->bp; + + switch (action) { + case DISABLE_TX: + bnx2x_sfp_set_transmitter(params, phy, 0); + break; + case ENABLE_TX: + if (!(phy->flags & FLAGS_SFP_NOT_APPROVED)) + bnx2x_sfp_set_transmitter(params, phy, 1); + break; + default: + DP(NETIF_MSG_LINK, "Function 0x%x not supported by 8727\n", + action); + return; + } +} + +static void bnx2x_set_e1e2_module_fault_led(struct link_params *params, + u8 gpio_mode) +{ + struct bnx2x *bp = params->bp; + + u32 fault_led_gpio = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].sfp_ctrl)) & + PORT_HW_CFG_FAULT_MODULE_LED_MASK; + switch (fault_led_gpio) { + case PORT_HW_CFG_FAULT_MODULE_LED_DISABLED: + return; + case PORT_HW_CFG_FAULT_MODULE_LED_GPIO0: + case PORT_HW_CFG_FAULT_MODULE_LED_GPIO1: + case PORT_HW_CFG_FAULT_MODULE_LED_GPIO2: + case PORT_HW_CFG_FAULT_MODULE_LED_GPIO3: + { + u8 gpio_port = bnx2x_get_gpio_port(params); + u16 gpio_pin = fault_led_gpio - + PORT_HW_CFG_FAULT_MODULE_LED_GPIO0; + DP(NETIF_MSG_LINK, "Set fault module-detected led " + "pin %x port %x mode %x\n", + gpio_pin, gpio_port, gpio_mode); + bnx2x_set_gpio(bp, gpio_pin, gpio_mode, gpio_port); + } + break; + default: + DP(NETIF_MSG_LINK, "Error: Invalid fault led mode 0x%x\n", + fault_led_gpio); + } +} + +static void bnx2x_set_e3_module_fault_led(struct link_params *params, + u8 gpio_mode) +{ + u32 pin_cfg; + u8 port = params->port; + struct bnx2x *bp = params->bp; + pin_cfg = (REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].e3_sfp_ctrl)) & + PORT_HW_CFG_E3_FAULT_MDL_LED_MASK) >> + PORT_HW_CFG_E3_FAULT_MDL_LED_SHIFT; + DP(NETIF_MSG_LINK, "Setting Fault LED to %d using pin cfg %d\n", + gpio_mode, pin_cfg); + bnx2x_set_cfg_pin(bp, pin_cfg, gpio_mode); +} + +static void bnx2x_set_sfp_module_fault_led(struct link_params *params, + u8 gpio_mode) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "Setting SFP+ module fault LED to %d\n", gpio_mode); + if (CHIP_IS_E3(bp)) { + /* + * Low ==> if SFP+ module is supported otherwise + * High ==> if SFP+ module is not on the approved vendor list + */ + bnx2x_set_e3_module_fault_led(params, gpio_mode); + } else + bnx2x_set_e1e2_module_fault_led(params, gpio_mode); +} + +static void bnx2x_warpcore_power_module(struct link_params *params, + struct bnx2x_phy *phy, + u8 power) +{ + u32 pin_cfg; + struct bnx2x *bp = params->bp; + + pin_cfg = (REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].e3_sfp_ctrl)) & + PORT_HW_CFG_E3_PWR_DIS_MASK) >> + PORT_HW_CFG_E3_PWR_DIS_SHIFT; + + if (pin_cfg == PIN_CFG_NA) + return; + DP(NETIF_MSG_LINK, "Setting SFP+ module power to %d using pin cfg %d\n", + power, pin_cfg); + /* + * Low ==> corresponding SFP+ module is powered + * high ==> the SFP+ module is powered down + */ + bnx2x_set_cfg_pin(bp, pin_cfg, power ^ 1); +} + +static void bnx2x_warpcore_hw_reset(struct bnx2x_phy *phy, + struct link_params *params) +{ + bnx2x_warpcore_power_module(params, phy, 0); +} + +static void bnx2x_power_sfp_module(struct link_params *params, + struct bnx2x_phy *phy, + u8 power) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "Setting SFP+ power to %x\n", power); + + switch (phy->type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722: + bnx2x_8727_power_module(params->bp, phy, power); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + bnx2x_warpcore_power_module(params, phy, power); + break; + default: + break; + } +} +static void bnx2x_warpcore_set_limiting_mode(struct link_params *params, + struct bnx2x_phy *phy, + u16 edc_mode) +{ + u16 val = 0; + u16 mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT; + struct bnx2x *bp = params->bp; + + u8 lane = bnx2x_get_warpcore_lane(phy, params); + /* This is a global register which controls all lanes */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val); + val &= ~(0xf << (lane << 2)); + + switch (edc_mode) { + case EDC_MODE_LINEAR: + case EDC_MODE_LIMITING: + mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_DEFAULT; + break; + case EDC_MODE_PASSIVE_DAC: + mode = MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE_SFP_DAC; + break; + default: + break; + } + + val |= (mode << (lane << 2)); + bnx2x_cl45_write(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, val); + /* A must read */ + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_UC_INFO_B1_FIRMWARE_MODE, &val); + + /* Restart microcode to re-read the new mode */ + bnx2x_warpcore_reset_lane(bp, phy, 1); + bnx2x_warpcore_reset_lane(bp, phy, 0); + +} + +static void bnx2x_set_limiting_mode(struct link_params *params, + struct bnx2x_phy *phy, + u16 edc_mode) +{ + switch (phy->type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + bnx2x_8726_set_limiting_mode(params->bp, phy, edc_mode); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722: + bnx2x_8727_set_limiting_mode(params->bp, phy, edc_mode); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT: + bnx2x_warpcore_set_limiting_mode(params, phy, edc_mode); + break; + } +} + +int bnx2x_sfp_module_detection(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 edc_mode; + int rc = 0; + + u32 val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port].config)); + + DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n", + params->port); + /* Power up module */ + bnx2x_power_sfp_module(params, phy, 1); + if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) { + DP(NETIF_MSG_LINK, "Failed to get valid module type\n"); + return -EINVAL; + } else if (bnx2x_verify_sfp_module(phy, params) != 0) { + /* check SFP+ module compatibility */ + DP(NETIF_MSG_LINK, "Module verification failed!!\n"); + rc = -EINVAL; + /* Turn on fault module-detected led */ + bnx2x_set_sfp_module_fault_led(params, + MISC_REGISTERS_GPIO_HIGH); + + /* Check if need to power down the SFP+ module */ + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN) { + DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n"); + bnx2x_power_sfp_module(params, phy, 0); + return rc; + } + } else { + /* Turn off fault module-detected led */ + bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_LOW); + } + + /* + * Check and set limiting mode / LRM mode on 8726. On 8727 it + * is done automatically + */ + bnx2x_set_limiting_mode(params, phy, edc_mode); + + /* + * Enable transmit for this module if the module is approved, or + * if unapproved modules should also enable the Tx laser + */ + if (rc == 0 || + (val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) != + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + bnx2x_sfp_set_transmitter(params, phy, 1); + else + bnx2x_sfp_set_transmitter(params, phy, 0); + + return rc; +} + +void bnx2x_handle_module_detect_int(struct link_params *params) +{ + struct bnx2x *bp = params->bp; + struct bnx2x_phy *phy; + u32 gpio_val; + u8 gpio_num, gpio_port; + if (CHIP_IS_E3(bp)) + phy = ¶ms->phy[INT_PHY]; + else + phy = ¶ms->phy[EXT_PHY1]; + + if (bnx2x_get_mod_abs_int_cfg(bp, params->chip_id, params->shmem_base, + params->port, &gpio_num, &gpio_port) == + -EINVAL) { + DP(NETIF_MSG_LINK, "Failed to get MOD_ABS interrupt config\n"); + return; + } + + /* Set valid module led off */ + bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_HIGH); + + /* Get current gpio val reflecting module plugged in / out*/ + gpio_val = bnx2x_get_gpio(bp, gpio_num, gpio_port); + + /* Call the handling function in case module is detected */ + if (gpio_val == 0) { + bnx2x_power_sfp_module(params, phy, 1); + bnx2x_set_gpio_int(bp, gpio_num, + MISC_REGISTERS_GPIO_INT_OUTPUT_CLR, + gpio_port); + if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0) + bnx2x_sfp_module_detection(phy, params); + else + DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n"); + } else { + u32 val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port]. + config)); + bnx2x_set_gpio_int(bp, gpio_num, + MISC_REGISTERS_GPIO_INT_OUTPUT_SET, + gpio_port); + /* + * Module was plugged out. + * Disable transmit for this module + */ + phy->media_type = ETH_PHY_NOT_PRESENT; + if (((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) || + CHIP_IS_E3(bp)) + bnx2x_sfp_set_transmitter(params, phy, 0); + } +} + +/******************************************************************/ +/* Used by 8706 and 8727 */ +/******************************************************************/ +static void bnx2x_sfp_mask_fault(struct bnx2x *bp, + struct bnx2x_phy *phy, + u16 alarm_status_offset, + u16 alarm_ctrl_offset) +{ + u16 alarm_status, val; + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, alarm_status_offset, + &alarm_status); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, alarm_status_offset, + &alarm_status); + /* Mask or enable the fault event. */ + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, &val); + if (alarm_status & (1<<0)) + val &= ~(1<<0); + else + val |= (1<<0); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, val); +} +/******************************************************************/ +/* common BCM8706/BCM8726 PHY SECTION */ +/******************************************************************/ +static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + u8 link_up = 0; + u16 val1, val2, rx_sd, pcs_status; + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "XGXS 8706/8726\n"); + /* Clear RX Alarm*/ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT, &val2); + + bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_LASI_TXSTAT, + MDIO_PMA_LASI_TXCTRL); + + /* clear LASI indication*/ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val1); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val2); + DP(NETIF_MSG_LINK, "8706/8726 LASI status 0x%x--> 0x%x\n", val1, val2); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_SD, &rx_sd); + bnx2x_cl45_read(bp, phy, + MDIO_PCS_DEVAD, MDIO_PCS_REG_STATUS, &pcs_status); + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2); + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_LINK_STATUS, &val2); + + DP(NETIF_MSG_LINK, "8706/8726 rx_sd 0x%x pcs_status 0x%x 1Gbps" + " link_status 0x%x\n", rx_sd, pcs_status, val2); + /* + * link is up if both bit 0 of pmd_rx_sd and bit 0 of pcs_status + * are set, or if the autoneg bit 1 is set + */ + link_up = ((rx_sd & pcs_status & 0x1) || (val2 & (1<<1))); + if (link_up) { + if (val2 & (1<<1)) + vars->line_speed = SPEED_1000; + else + vars->line_speed = SPEED_10000; + bnx2x_ext_phy_resolve_fc(phy, params, vars); + vars->duplex = DUPLEX_FULL; + } + + /* Capture 10G link fault. Read twice to clear stale value. */ + if (vars->line_speed == SPEED_10000) { + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, + MDIO_PMA_LASI_TXSTAT, &val1); + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, + MDIO_PMA_LASI_TXSTAT, &val1); + if (val1 & (1<<0)) + vars->fault_detected = 1; + } + + return link_up; +} + +/******************************************************************/ +/* BCM8706 PHY SECTION */ +/******************************************************************/ +static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + u32 tx_en_mode; + u16 cnt, val, tmp1; + struct bnx2x *bp = params->bp; + + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); + /* HW reset */ + bnx2x_ext_phy_hw_reset(bp, params->port); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0xa040); + bnx2x_wait_reset_complete(bp, phy, params); + + /* Wait until fw is loaded */ + for (cnt = 0; cnt < 100; cnt++) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_ROM_VER1, &val); + if (val) + break; + msleep(10); + } + DP(NETIF_MSG_LINK, "XGXS 8706 is initialized after %d ms\n", cnt); + if ((params->feature_config_flags & + FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) { + u8 i; + u16 reg; + for (i = 0; i < 4; i++) { + reg = MDIO_XS_8706_REG_BANK_RX0 + + i*(MDIO_XS_8706_REG_BANK_RX1 - + MDIO_XS_8706_REG_BANK_RX0); + bnx2x_cl45_read(bp, phy, MDIO_XS_DEVAD, reg, &val); + /* Clear first 3 bits of the control */ + val &= ~0x7; + /* Set control bits according to configuration */ + val |= (phy->rx_preemphasis[i] & 0x7); + DP(NETIF_MSG_LINK, "Setting RX Equalizer to BCM8706" + " reg 0x%x <-- val 0x%x\n", reg, val); + bnx2x_cl45_write(bp, phy, MDIO_XS_DEVAD, reg, val); + } + } + /* Force speed */ + if (phy->req_line_speed == SPEED_10000) { + DP(NETIF_MSG_LINK, "XGXS 8706 force 10Gbps\n"); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_DIGITAL_CTRL, 0x400); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_TXCTRL, + 0); + /* Arm LASI for link and Tx fault. */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 3); + } else { + /* Force 1Gbps using autoneg with 1G advertisement */ + + /* Allow CL37 through CL73 */ + DP(NETIF_MSG_LINK, "XGXS 8706 AutoNeg\n"); + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c); + + /* Enable Full-Duplex advertisement on CL37 */ + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LP, 0x0020); + /* Enable CL37 AN */ + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000); + /* 1G support */ + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_ADV, (1<<5)); + + /* Enable clause 73 AN */ + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL, + 0x0400); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, + 0x0004); + } + bnx2x_save_bcm_spirom_ver(bp, phy, params->port); + + /* + * If TX Laser is controlled by GPIO_0, do not let PHY go into low + * power mode, if TX Laser is disabled + */ + + tx_en_mode = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].sfp_ctrl)) + & PORT_HW_CFG_TX_LASER_MASK; + + if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) { + DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n"); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, &tmp1); + tmp1 |= 0x1; + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_DIGITAL_CTRL, tmp1); + } + + return 0; +} + +static int bnx2x_8706_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + return bnx2x_8706_8726_read_status(phy, params, vars); +} + +/******************************************************************/ +/* BCM8726 PHY SECTION */ +/******************************************************************/ +static void bnx2x_8726_config_loopback(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "PMA/PMD ext_phy_loopback: 8726\n"); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0001); +} + +static void bnx2x_8726_external_rom_boot(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + /* Need to wait 100ms after reset */ + msleep(100); + + /* Micro controller re-boot */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_GEN_CTRL, 0x018B); + + /* Set soft reset */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0001); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, + MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP); + + /* wait for 150ms for microcode load */ + msleep(150); + + /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_MISC_CTRL1, 0x0000); + + msleep(200); + bnx2x_save_bcm_spirom_ver(bp, phy, params->port); +} + +static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 val1; + u8 link_up = bnx2x_8706_8726_read_status(phy, params, vars); + if (link_up) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, + &val1); + if (val1 & (1<<15)) { + DP(NETIF_MSG_LINK, "Tx is disabled\n"); + link_up = 0; + vars->line_speed = 0; + } + } + return link_up; +} + + +static int bnx2x_8726_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "Initializing BCM8726\n"); + + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); + bnx2x_wait_reset_complete(bp, phy, params); + + bnx2x_8726_external_rom_boot(phy, params); + + /* + * Need to call module detected on initialization since the module + * detection triggered by actual module insertion might occur before + * driver is loaded, and when driver is loaded, it reset all + * registers, including the transmitter + */ + bnx2x_sfp_module_detection(phy, params); + + if (phy->req_line_speed == SPEED_1000) { + DP(NETIF_MSG_LINK, "Setting 1G force\n"); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 0x5); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL, + 0x400); + } else if ((phy->req_line_speed == SPEED_AUTO_NEG) && + (phy->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G) && + ((phy->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) != + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) { + DP(NETIF_MSG_LINK, "Setting 1G clause37\n"); + /* Set Flow control */ + bnx2x_ext_phy_set_pause(params, phy, vars); + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_ADV, 0x20); + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CL37_CL73, 0x040c); + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CL37_FC_LD, 0x0020); + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1000); + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x1200); + /* + * Enable RX-ALARM control to receive interrupt for 1G speed + * change + */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 0x4); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL, + 0x400); + + } else { /* Default 10G. Set only LASI control */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 1); + } + + /* Set TX PreEmphasis if needed */ + if ((params->feature_config_flags & + FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) { + DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x," + "TX_CTRL2 0x%x\n", + phy->tx_preemphasis[0], + phy->tx_preemphasis[1]); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8726_TX_CTRL1, + phy->tx_preemphasis[0]); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8726_TX_CTRL2, + phy->tx_preemphasis[1]); + } + + return 0; + +} + +static void bnx2x_8726_link_reset(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "bnx2x_8726_link_reset port %d\n", params->port); + /* Set serial boot control for external load */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_GEN_CTRL, 0x0001); +} + +/******************************************************************/ +/* BCM8727 PHY SECTION */ +/******************************************************************/ + +static void bnx2x_8727_set_link_led(struct bnx2x_phy *phy, + struct link_params *params, u8 mode) +{ + struct bnx2x *bp = params->bp; + u16 led_mode_bitmask = 0; + u16 gpio_pins_bitmask = 0; + u16 val; + /* Only NOC flavor requires to set the LED specifically */ + if (!(phy->flags & FLAGS_NOC)) + return; + switch (mode) { + case LED_MODE_FRONT_PANEL_OFF: + case LED_MODE_OFF: + led_mode_bitmask = 0; + gpio_pins_bitmask = 0x03; + break; + case LED_MODE_ON: + led_mode_bitmask = 0; + gpio_pins_bitmask = 0x02; + break; + case LED_MODE_OPER: + led_mode_bitmask = 0x60; + gpio_pins_bitmask = 0x11; + break; + } + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_OPT_CTRL, + &val); + val &= 0xff8f; + val |= led_mode_bitmask; + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_OPT_CTRL, + val); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_GPIO_CTRL, + &val); + val &= 0xffe0; + val |= gpio_pins_bitmask; + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_GPIO_CTRL, + val); +} +static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy, + struct link_params *params) { + u32 swap_val, swap_override; + u8 port; + /* + * The PHY reset is controlled by GPIO 1. Fake the port number + * to cancel the swap done in set_gpio() + */ + struct bnx2x *bp = params->bp; + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + port = (swap_val && swap_override) ^ 1; + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW, port); +} + +static int bnx2x_8727_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + u32 tx_en_mode; + u16 tmp1, val, mod_abs, tmp2; + u16 rx_alarm_ctrl_val; + u16 lasi_ctrl_val; + struct bnx2x *bp = params->bp; + /* Enable PMD link, MOD_ABS_FLT, and 1G link alarm */ + + bnx2x_wait_reset_complete(bp, phy, params); + rx_alarm_ctrl_val = (1<<2) | (1<<5) ; + /* Should be 0x6 to enable XS on Tx side. */ + lasi_ctrl_val = 0x0006; + + DP(NETIF_MSG_LINK, "Initializing BCM8727\n"); + /* enable LASI */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL, + rx_alarm_ctrl_val); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_TXCTRL, + 0); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, lasi_ctrl_val); + + /* + * Initially configure MOD_ABS to interrupt when module is + * presence( bit 8) + */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs); + /* + * Set EDC off by setting OPTXLOS signal input to low (bit 9). + * When the EDC is off it locks onto a reference clock and avoids + * becoming 'lost' + */ + mod_abs &= ~(1<<8); + if (!(phy->flags & FLAGS_NOC)) + mod_abs &= ~(1<<9); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); + + + /* Enable/Disable PHY transmitter output */ + bnx2x_set_disable_pmd_transmit(params, phy, 0); + + /* Make MOD_ABS give interrupt on change */ + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, + &val); + val |= (1<<12); + if (phy->flags & FLAGS_NOC) + val |= (3<<5); + + /* + * Set 8727 GPIOs to input to allow reading from the 8727 GPIO0 + * status which reflect SFP+ module over-current + */ + if (!(phy->flags & FLAGS_NOC)) + val &= 0xff8f; /* Reset bits 4-6 */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_PCS_OPT_CTRL, val); + + bnx2x_8727_power_module(bp, phy, 1); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &tmp1); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT, &tmp1); + + /* Set option 1G speed */ + if (phy->req_line_speed == SPEED_1000) { + DP(NETIF_MSG_LINK, "Setting 1G force\n"); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x40); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, 0xD); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, &tmp1); + DP(NETIF_MSG_LINK, "1.7 = 0x%x\n", tmp1); + /* + * Power down the XAUI until link is up in case of dual-media + * and 1G + */ + if (DUAL_MEDIA(params)) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_GP, &val); + val |= (3<<10); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_GP, val); + } + } else if ((phy->req_line_speed == SPEED_AUTO_NEG) && + ((phy->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) && + ((phy->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) != + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) { + + DP(NETIF_MSG_LINK, "Setting 1G clause37\n"); + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, 0); + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x1300); + } else { + /* + * Since the 8727 has only single reset pin, need to set the 10G + * registers although it is default + */ + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_8727_MISC_CTRL, + 0x0020); + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CL37_AN, 0x0100); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x2040); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_10G_CTRL2, + 0x0008); + } + + /* + * Set 2-wire transfer rate of SFP+ module EEPROM + * to 100Khz since some DACs(direct attached cables) do + * not work at 400Khz. + */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TWO_WIRE_SLAVE_ADDR, + 0xa001); + + /* Set TX PreEmphasis if needed */ + if ((params->feature_config_flags & + FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED)) { + DP(NETIF_MSG_LINK, "Setting TX_CTRL1 0x%x, TX_CTRL2 0x%x\n", + phy->tx_preemphasis[0], + phy->tx_preemphasis[1]); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL1, + phy->tx_preemphasis[0]); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_TX_CTRL2, + phy->tx_preemphasis[1]); + } + + /* + * If TX Laser is controlled by GPIO_0, do not let PHY go into low + * power mode, if TX Laser is disabled + */ + tx_en_mode = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].sfp_ctrl)) + & PORT_HW_CFG_TX_LASER_MASK; + + if (tx_en_mode == PORT_HW_CFG_TX_LASER_GPIO0) { + + DP(NETIF_MSG_LINK, "Enabling TXONOFF_PWRDN_DIS\n"); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, &tmp2); + tmp2 |= 0x1000; + tmp2 &= 0xFFEF; + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_OPT_CFG_REG, tmp2); + } + + return 0; +} + +static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 mod_abs, rx_alarm_status; + u32 val = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port]. + config)); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, &mod_abs); + if (mod_abs & (1<<8)) { + + /* Module is absent */ + DP(NETIF_MSG_LINK, "MOD_ABS indication " + "show module is absent\n"); + phy->media_type = ETH_PHY_NOT_PRESENT; + /* + * 1. Set mod_abs to detect next module + * presence event + * 2. Set EDC off by setting OPTXLOS signal input to low + * (bit 9). + * When the EDC is off it locks onto a reference clock and + * avoids becoming 'lost'. + */ + mod_abs &= ~(1<<8); + if (!(phy->flags & FLAGS_NOC)) + mod_abs &= ~(1<<9); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); + + /* + * Clear RX alarm since it stays up as long as + * the mod_abs wasn't changed + */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_LASI_RXSTAT, &rx_alarm_status); + + } else { + /* Module is present */ + DP(NETIF_MSG_LINK, "MOD_ABS indication " + "show module is present\n"); + /* + * First disable transmitter, and if the module is ok, the + * module_detection will enable it + * 1. Set mod_abs to detect next module absent event ( bit 8) + * 2. Restore the default polarity of the OPRXLOS signal and + * this signal will then correctly indicate the presence or + * absence of the Rx signal. (bit 9) + */ + mod_abs |= (1<<8); + if (!(phy->flags & FLAGS_NOC)) + mod_abs |= (1<<9); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, mod_abs); + + /* + * Clear RX alarm since it stays up as long as the mod_abs + * wasn't changed. This is need to be done before calling the + * module detection, otherwise it will clear* the link update + * alarm + */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_LASI_RXSTAT, &rx_alarm_status); + + + if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) == + PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER) + bnx2x_sfp_set_transmitter(params, phy, 0); + + if (bnx2x_wait_for_sfp_module_initialized(phy, params) == 0) + bnx2x_sfp_module_detection(phy, params); + else + DP(NETIF_MSG_LINK, "SFP+ module is not initialized\n"); + } + + DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", + rx_alarm_status); + /* No need to check link status in case of module plugged in/out */ +} + +static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) + +{ + struct bnx2x *bp = params->bp; + u8 link_up = 0, oc_port = params->port; + u16 link_status = 0; + u16 rx_alarm_status, lasi_ctrl, val1; + + /* If PHY is not initialized, do not check link status */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, + &lasi_ctrl); + if (!lasi_ctrl) + return 0; + + /* Check the LASI on Rx */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXSTAT, + &rx_alarm_status); + vars->line_speed = 0; + DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS 0x%x\n", rx_alarm_status); + + bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_LASI_TXSTAT, + MDIO_PMA_LASI_TXCTRL); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val1); + + DP(NETIF_MSG_LINK, "8727 LASI status 0x%x\n", val1); + + /* Clear MSG-OUT */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_M8051_MSGOUT_REG, &val1); + + /* + * If a module is present and there is need to check + * for over current + */ + if (!(phy->flags & FLAGS_NOC) && !(rx_alarm_status & (1<<5))) { + /* Check over-current using 8727 GPIO0 input*/ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8727_GPIO_CTRL, + &val1); + + if ((val1 & (1<<8)) == 0) { + if (!CHIP_IS_E1x(bp)) + oc_port = BP_PATH(bp) + (params->port << 1); + DP(NETIF_MSG_LINK, "8727 Power fault has been detected" + " on port %d\n", oc_port); + netdev_err(bp->dev, "Error: Power fault on Port %d has" + " been detected and the power to " + "that SFP+ module has been removed" + " to prevent failure of the card." + " Please remove the SFP+ module and" + " restart the system to clear this" + " error.\n", + oc_port); + /* Disable all RX_ALARMs except for mod_abs */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_LASI_RXCTRL, (1<<5)); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, &val1); + /* Wait for module_absent_event */ + val1 |= (1<<8); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_PHY_IDENTIFIER, val1); + /* Clear RX alarm */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_LASI_RXSTAT, &rx_alarm_status); + return 0; + } + } /* Over current check */ + + /* When module absent bit is set, check module */ + if (rx_alarm_status & (1<<5)) { + bnx2x_8727_handle_mod_abs(phy, params); + /* Enable all mod_abs and link detection bits */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_RXCTRL, + ((1<<5) | (1<<2))); + } + DP(NETIF_MSG_LINK, "Enabling 8727 TX laser if SFP is approved\n"); + bnx2x_8727_specific_func(phy, params, ENABLE_TX); + /* If transmitter is disabled, ignore false link up indication */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_PHY_IDENTIFIER, &val1); + if (val1 & (1<<15)) { + DP(NETIF_MSG_LINK, "Tx is disabled\n"); + return 0; + } + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8073_SPEED_LINK_STATUS, &link_status); + + /* + * Bits 0..2 --> speed detected, + * Bits 13..15--> link is down + */ + if ((link_status & (1<<2)) && (!(link_status & (1<<15)))) { + link_up = 1; + vars->line_speed = SPEED_10000; + DP(NETIF_MSG_LINK, "port %x: External link up in 10G\n", + params->port); + } else if ((link_status & (1<<0)) && (!(link_status & (1<<13)))) { + link_up = 1; + vars->line_speed = SPEED_1000; + DP(NETIF_MSG_LINK, "port %x: External link up in 1G\n", + params->port); + } else { + link_up = 0; + DP(NETIF_MSG_LINK, "port %x: External link is down\n", + params->port); + } + + /* Capture 10G link fault. */ + if (vars->line_speed == SPEED_10000) { + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, + MDIO_PMA_LASI_TXSTAT, &val1); + + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, + MDIO_PMA_LASI_TXSTAT, &val1); + + if (val1 & (1<<0)) { + vars->fault_detected = 1; + } + } + + if (link_up) { + bnx2x_ext_phy_resolve_fc(phy, params, vars); + vars->duplex = DUPLEX_FULL; + DP(NETIF_MSG_LINK, "duplex = 0x%x\n", vars->duplex); + } + + if ((DUAL_MEDIA(params)) && + (phy->req_line_speed == SPEED_1000)) { + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_GP, &val1); + /* + * In case of dual-media board and 1G, power up the XAUI side, + * otherwise power it down. For 10G it is done automatically + */ + if (link_up) + val1 &= ~(3<<10); + else + val1 |= (3<<10); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8727_PCS_GP, val1); + } + return link_up; +} + +static void bnx2x_8727_link_reset(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + + /* Enable/Disable PHY transmitter output */ + bnx2x_set_disable_pmd_transmit(params, phy, 1); + + /* Disable Transmitter */ + bnx2x_sfp_set_transmitter(params, phy, 0); + /* Clear LASI */ + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 0); + +} + +/******************************************************************/ +/* BCM8481/BCM84823/BCM84833 PHY SECTION */ +/******************************************************************/ +static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy, + struct link_params *params) +{ + u16 val, fw_ver1, fw_ver2, cnt; + u8 port; + struct bnx2x *bp = params->bp; + + port = params->port; + + /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/ + /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */ + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009); + + for (cnt = 0; cnt < 100; cnt++) { + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val); + if (val & 1) + break; + udelay(5); + } + if (cnt == 100) { + DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n"); + bnx2x_save_spirom_version(bp, port, 0, + phy->ver_addr); + return; + } + + + /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */ + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200); + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A); + for (cnt = 0; cnt < 100; cnt++) { + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val); + if (val & 1) + break; + udelay(5); + } + if (cnt == 100) { + DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n"); + bnx2x_save_spirom_version(bp, port, 0, + phy->ver_addr); + return; + } + + /* lower 16 bits of the register SPI_FW_STATUS */ + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1); + /* upper 16 bits of register SPI_FW_STATUS */ + bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2); + + bnx2x_save_spirom_version(bp, port, (fw_ver2<<16) | fw_ver1, + phy->ver_addr); +} + +static void bnx2x_848xx_set_led(struct bnx2x *bp, + struct bnx2x_phy *phy) +{ + u16 val; + + /* PHYC_CTL_LED_CTL */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, &val); + val &= 0xFE00; + val |= 0x0092; + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, val); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x80); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED2_MASK, + 0x18); + + /* Select activity source by Tx and Rx, as suggested by PHY AE */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + 0x0006); + + /* Select the closest activity blink rate to that in 10/100/1000 */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_BLINK, + 0); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val); + val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/ + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_84823_CTL_LED_CTL_1, val); + + /* 'Interrupt Mask' */ + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, + 0xFFFB, 0xFFFD); +} + +static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 autoneg_val, an_1000_val, an_10_100_val; + u16 tmp_req_line_speed; + + tmp_req_line_speed = phy->req_line_speed; + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) + if (phy->req_line_speed == SPEED_10000) + phy->req_line_speed = SPEED_AUTO_NEG; + + /* + * This phy uses the NIG latch mechanism since link indication + * arrives through its LED4 and not via its LASI signal, so we + * get steady signal instead of clear on read + */ + bnx2x_bits_en(bp, NIG_REG_LATCH_BC_0 + params->port*4, + 1 << NIG_LATCH_BC_ENABLE_MI_INT); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 0x0000); + + bnx2x_848xx_set_led(bp, phy); + + /* set 1000 speed advertisement */ + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL, + &an_1000_val); + + bnx2x_ext_phy_set_pause(params, phy, vars); + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_AN_ADV, + &an_10_100_val); + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_MII_CTRL, + &autoneg_val); + /* Disable forced speed */ + autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13)); + an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8)); + + if (((phy->req_line_speed == SPEED_AUTO_NEG) && + (phy->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) || + (phy->req_line_speed == SPEED_1000)) { + an_1000_val |= (1<<8); + autoneg_val |= (1<<9 | 1<<12); + if (phy->req_duplex == DUPLEX_FULL) + an_1000_val |= (1<<9); + DP(NETIF_MSG_LINK, "Advertising 1G\n"); + } else + an_1000_val &= ~((1<<8) | (1<<9)); + + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_8481_1000T_CTRL, + an_1000_val); + + /* set 100 speed advertisement */ + if (((phy->req_line_speed == SPEED_AUTO_NEG) && + (phy->speed_cap_mask & + (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL | + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) && + (phy->supported & + (SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full)))) { + an_10_100_val |= (1<<7); + /* Enable autoneg and restart autoneg for legacy speeds */ + autoneg_val |= (1<<9 | 1<<12); + + if (phy->req_duplex == DUPLEX_FULL) + an_10_100_val |= (1<<8); + DP(NETIF_MSG_LINK, "Advertising 100M\n"); + } + /* set 10 speed advertisement */ + if (((phy->req_line_speed == SPEED_AUTO_NEG) && + (phy->speed_cap_mask & + (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL | + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) && + (phy->supported & + (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full)))) { + an_10_100_val |= (1<<5); + autoneg_val |= (1<<9 | 1<<12); + if (phy->req_duplex == DUPLEX_FULL) + an_10_100_val |= (1<<6); + DP(NETIF_MSG_LINK, "Advertising 10M\n"); + } + + /* Only 10/100 are allowed to work in FORCE mode */ + if ((phy->req_line_speed == SPEED_100) && + (phy->supported & + (SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full))) { + autoneg_val |= (1<<13); + /* Enabled AUTO-MDIX when autoneg is disabled */ + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL, + (1<<15 | 1<<9 | 7<<0)); + DP(NETIF_MSG_LINK, "Setting 100M force\n"); + } + if ((phy->req_line_speed == SPEED_10) && + (phy->supported & + (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full))) { + /* Enabled AUTO-MDIX when autoneg is disabled */ + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_8481_AUX_CTRL, + (1<<15 | 1<<9 | 7<<0)); + DP(NETIF_MSG_LINK, "Setting 10M force\n"); + } + + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_8481_LEGACY_AN_ADV, + an_10_100_val); + + if (phy->req_duplex == DUPLEX_FULL) + autoneg_val |= (1<<8); + + /* + * Always write this if this is not 84833. + * For 84833, write it only when it's a forced speed. + */ + if ((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || + ((autoneg_val & (1<<12)) == 0)) + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_CTRL, autoneg_val); + + if (((phy->req_line_speed == SPEED_AUTO_NEG) && + (phy->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) || + (phy->req_line_speed == SPEED_10000)) { + DP(NETIF_MSG_LINK, "Advertising 10G\n"); + /* Restart autoneg for 10G*/ + + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, + 0x3200); + } else + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_10GBASE_T_AN_CTRL, + 1); + + /* Save spirom version */ + bnx2x_save_848xx_spirom_version(phy, params); + + phy->req_line_speed = tmp_req_line_speed; + + return 0; +} + +static int bnx2x_8481_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + /* Restore normal power mode*/ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); + + /* HW reset */ + bnx2x_ext_phy_hw_reset(bp, params->port); + bnx2x_wait_reset_complete(bp, phy, params); + + bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); + return bnx2x_848xx_cmn_config_init(phy, params, vars); +} + + +#define PHY84833_HDSHK_WAIT 300 +static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + u32 idx; + u32 pair_swap; + u16 val; + u16 data; + struct bnx2x *bp = params->bp; + /* Do pair swap */ + + /* Check for configuration. */ + pair_swap = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].xgbt_phy_cfg)) & + PORT_HW_CFG_RJ45_PAIR_SWAP_MASK; + + if (pair_swap == 0) + return 0; + + data = (u16)pair_swap; + + /* Write CMD_OPEN_OVERRIDE to STATUS reg */ + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG2, + PHY84833_CMD_OPEN_OVERRIDE); + for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG2, &val); + if (val == PHY84833_CMD_OPEN_FOR_CMDS) + break; + msleep(1); + } + if (idx >= PHY84833_HDSHK_WAIT) { + DP(NETIF_MSG_LINK, "Pairswap: FW not ready.\n"); + return -EINVAL; + } + + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG4, + data); + /* Issue pair swap command */ + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG0, + PHY84833_DIAG_CMD_PAIR_SWAP_CHANGE); + for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG2, &val); + if ((val == PHY84833_CMD_COMPLETE_PASS) || + (val == PHY84833_CMD_COMPLETE_ERROR)) + break; + msleep(1); + } + if ((idx >= PHY84833_HDSHK_WAIT) || + (val == PHY84833_CMD_COMPLETE_ERROR)) { + DP(NETIF_MSG_LINK, "Pairswap: override failed.\n"); + return -EINVAL; + } + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG2, + PHY84833_CMD_CLEAR_COMPLETE); + DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data); + return 0; +} + + +static u8 bnx2x_84833_get_reset_gpios(struct bnx2x *bp, + u32 shmem_base_path[], + u32 chip_id) +{ + u32 reset_pin[2]; + u32 idx; + u8 reset_gpios; + if (CHIP_IS_E3(bp)) { + /* Assume that these will be GPIOs, not EPIOs. */ + for (idx = 0; idx < 2; idx++) { + /* Map config param to register bit. */ + reset_pin[idx] = REG_RD(bp, shmem_base_path[idx] + + offsetof(struct shmem_region, + dev_info.port_hw_config[0].e3_cmn_pin_cfg)); + reset_pin[idx] = (reset_pin[idx] & + PORT_HW_CFG_E3_PHY_RESET_MASK) >> + PORT_HW_CFG_E3_PHY_RESET_SHIFT; + reset_pin[idx] -= PIN_CFG_GPIO0_P0; + reset_pin[idx] = (1 << reset_pin[idx]); + } + reset_gpios = (u8)(reset_pin[0] | reset_pin[1]); + } else { + /* E2, look from diff place of shmem. */ + for (idx = 0; idx < 2; idx++) { + reset_pin[idx] = REG_RD(bp, shmem_base_path[idx] + + offsetof(struct shmem_region, + dev_info.port_hw_config[0].default_cfg)); + reset_pin[idx] &= PORT_HW_CFG_EXT_PHY_GPIO_RST_MASK; + reset_pin[idx] -= PORT_HW_CFG_EXT_PHY_GPIO_RST_GPIO0_P0; + reset_pin[idx] >>= PORT_HW_CFG_EXT_PHY_GPIO_RST_SHIFT; + reset_pin[idx] = (1 << reset_pin[idx]); + } + reset_gpios = (u8)(reset_pin[0] | reset_pin[1]); + } + + return reset_gpios; +} + +static int bnx2x_84833_hw_reset_phy(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 reset_gpios; + u32 other_shmem_base_addr = REG_RD(bp, params->shmem2_base + + offsetof(struct shmem2_region, + other_shmem_base_addr)); + + u32 shmem_base_path[2]; + shmem_base_path[0] = params->shmem_base; + shmem_base_path[1] = other_shmem_base_addr; + + reset_gpios = bnx2x_84833_get_reset_gpios(bp, shmem_base_path, + params->chip_id); + + bnx2x_set_mult_gpio(bp, reset_gpios, MISC_REGISTERS_GPIO_OUTPUT_LOW); + udelay(10); + DP(NETIF_MSG_LINK, "84833 hw reset on pin values 0x%x\n", + reset_gpios); + + return 0; +} + +static int bnx2x_84833_common_init_phy(struct bnx2x *bp, + u32 shmem_base_path[], + u32 chip_id) +{ + u8 reset_gpios; + + reset_gpios = bnx2x_84833_get_reset_gpios(bp, shmem_base_path, chip_id); + + bnx2x_set_mult_gpio(bp, reset_gpios, MISC_REGISTERS_GPIO_OUTPUT_LOW); + udelay(10); + bnx2x_set_mult_gpio(bp, reset_gpios, MISC_REGISTERS_GPIO_OUTPUT_HIGH); + msleep(800); + DP(NETIF_MSG_LINK, "84833 reset pulse on pin values 0x%x\n", + reset_gpios); + + return 0; +} + +#define PHY84833_CONSTANT_LATENCY 1193 +static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 port, initialize = 1; + u16 val; + u16 temp; + u32 actual_phy_selection, cms_enable, idx; + int rc = 0; + + msleep(1); + + if (!(CHIP_IS_E1(bp))) + port = BP_PATH(bp); + else + port = params->port; + + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) { + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, + MISC_REGISTERS_GPIO_OUTPUT_HIGH, + port); + } else { + /* MDIO reset */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0x8000); + /* Bring PHY out of super isolate mode */ + bnx2x_cl45_read(bp, phy, + MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val); + val &= ~MDIO_84833_SUPER_ISOLATE; + bnx2x_cl45_write(bp, phy, + MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_XGPHY_STRAP1, val); + } + + bnx2x_wait_reset_complete(bp, phy, params); + + /* Wait for GPHY to come out of reset */ + msleep(50); + + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) + bnx2x_84833_pair_swap_cfg(phy, params, vars); + + /* + * BCM84823 requires that XGXS links up first @ 10G for normal behavior + */ + temp = vars->line_speed; + vars->line_speed = SPEED_10000; + bnx2x_set_autoneg(¶ms->phy[INT_PHY], params, vars, 0); + bnx2x_program_serdes(¶ms->phy[INT_PHY], params, vars); + vars->line_speed = temp; + + /* Set dual-media configuration according to configuration */ + + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_CTL_REG_84823_MEDIA, &val); + val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK | + MDIO_CTL_REG_84823_MEDIA_LINE_MASK | + MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN | + MDIO_CTL_REG_84823_MEDIA_PRIORITY_MASK | + MDIO_CTL_REG_84823_MEDIA_FIBER_1G); + + if (CHIP_IS_E3(bp)) { + val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK | + MDIO_CTL_REG_84823_MEDIA_LINE_MASK); + } else { + val |= (MDIO_CTL_REG_84823_CTRL_MAC_XFI | + MDIO_CTL_REG_84823_MEDIA_LINE_XAUI_L); + } + + actual_phy_selection = bnx2x_phy_selection(params); + + switch (actual_phy_selection) { + case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: + /* Do nothing. Essentially this is like the priority copper */ + break; + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: + val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_COPPER; + break; + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: + val |= MDIO_CTL_REG_84823_MEDIA_PRIORITY_FIBER; + break; + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY: + /* Do nothing here. The first PHY won't be initialized at all */ + break; + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY: + val |= MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN; + initialize = 0; + break; + } + if (params->phy[EXT_PHY2].req_line_speed == SPEED_1000) + val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G; + + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_CTL_REG_84823_MEDIA, val); + DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n", + params->multi_phy_config, val); + + /* AutogrEEEn */ + if (params->feature_config_flags & + FEATURE_CONFIG_AUTOGREEEN_ENABLED) { + /* Ensure that f/w is ready */ + for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG2, &val); + if (val == PHY84833_CMD_OPEN_FOR_CMDS) + break; + usleep_range(1000, 1000); + } + if (idx >= PHY84833_HDSHK_WAIT) { + DP(NETIF_MSG_LINK, "AutogrEEEn: FW not ready.\n"); + return -EINVAL; + } + + /* Select EEE mode */ + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG3, + 0x2); + + /* Set Idle and Latency */ + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG4, + PHY84833_CONSTANT_LATENCY + 1); + + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_DATA3_REG, + PHY84833_CONSTANT_LATENCY + 1); + + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_DATA4_REG, + PHY84833_CONSTANT_LATENCY); + + /* Send EEE instruction to command register */ + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG0, + PHY84833_DIAG_CMD_SET_EEE_MODE); + + /* Ensure that the command has completed */ + for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG2, &val); + if ((val == PHY84833_CMD_COMPLETE_PASS) || + (val == PHY84833_CMD_COMPLETE_ERROR)) + break; + usleep_range(1000, 1000); + } + if ((idx >= PHY84833_HDSHK_WAIT) || + (val == PHY84833_CMD_COMPLETE_ERROR)) { + DP(NETIF_MSG_LINK, "AutogrEEEn: command failed.\n"); + return -EINVAL; + } + + /* Reset command handler */ + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_84833_TOP_CFG_SCRATCH_REG2, + PHY84833_CMD_CLEAR_COMPLETE); + } + + if (initialize) + rc = bnx2x_848xx_cmn_config_init(phy, params, vars); + else + bnx2x_save_848xx_spirom_version(phy, params); + /* 84833 PHY has a better feature and doesn't need to support this. */ + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) { + cms_enable = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].default_cfg)) & + PORT_HW_CFG_ENABLE_CMS_MASK; + + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_CTL_REG_84823_USER_CTRL_REG, &val); + if (cms_enable) + val |= MDIO_CTL_REG_84823_USER_CTRL_CMS; + else + val &= ~MDIO_CTL_REG_84823_USER_CTRL_CMS; + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_CTL_REG_84823_USER_CTRL_REG, val); + } + + return rc; +} + +static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 val, val1, val2; + u8 link_up = 0; + + + /* Check 10G-BaseT link status */ + /* Check PMD signal ok */ + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, 0xFFFA, &val1); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL, + &val2); + DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2); + + /* Check link 10G */ + if (val2 & (1<<11)) { + vars->line_speed = SPEED_10000; + vars->duplex = DUPLEX_FULL; + link_up = 1; + bnx2x_ext_phy_10G_an_resolve(bp, phy, vars); + } else { /* Check Legacy speed link */ + u16 legacy_status, legacy_speed; + + /* Enable expansion register 0x42 (Operation mode status) */ + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_EXPANSION_REG_ACCESS, 0xf42); + + /* Get legacy speed operation status */ + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_EXPANSION_REG_RD_RW, + &legacy_status); + + DP(NETIF_MSG_LINK, "Legacy speed status" + " = 0x%x\n", legacy_status); + link_up = ((legacy_status & (1<<11)) == (1<<11)); + if (link_up) { + legacy_speed = (legacy_status & (3<<9)); + if (legacy_speed == (0<<9)) + vars->line_speed = SPEED_10; + else if (legacy_speed == (1<<9)) + vars->line_speed = SPEED_100; + else if (legacy_speed == (2<<9)) + vars->line_speed = SPEED_1000; + else /* Should not happen */ + vars->line_speed = 0; + + if (legacy_status & (1<<8)) + vars->duplex = DUPLEX_FULL; + else + vars->duplex = DUPLEX_HALF; + + DP(NETIF_MSG_LINK, "Link is up in %dMbps," + " is_duplex_full= %d\n", vars->line_speed, + (vars->duplex == DUPLEX_FULL)); + /* Check legacy speed AN resolution */ + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_MII_STATUS, + &val); + if (val & (1<<5)) + vars->link_status |= + LINK_STATUS_AUTO_NEGOTIATE_COMPLETE; + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, + MDIO_AN_REG_8481_LEGACY_AN_EXPANSION, + &val); + if ((val & (1<<0)) == 0) + vars->link_status |= + LINK_STATUS_PARALLEL_DETECTION_USED; + } + } + if (link_up) { + DP(NETIF_MSG_LINK, "BCM84823: link speed is %d\n", + vars->line_speed); + bnx2x_ext_phy_resolve_fc(phy, params, vars); + } + + return link_up; +} + + +static int bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len) +{ + int status = 0; + u32 spirom_ver; + spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F); + status = bnx2x_format_ver(spirom_ver, str, len); + return status; +} + +static void bnx2x_8481_hw_reset(struct bnx2x_phy *phy, + struct link_params *params) +{ + bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW, 0); + bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW, 1); +} + +static void bnx2x_8481_link_reset(struct bnx2x_phy *phy, + struct link_params *params) +{ + bnx2x_cl45_write(params->bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, 0x0000); + bnx2x_cl45_write(params->bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1); +} + +static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u8 port; + u16 val16; + + if (!(CHIP_IS_E1(bp))) + port = BP_PATH(bp); + else + port = params->port; + + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) { + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3, + MISC_REGISTERS_GPIO_OUTPUT_LOW, + port); + } else { + bnx2x_cl45_read(bp, phy, + MDIO_CTL_DEVAD, + 0x400f, &val16); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, 0x800); + } +} + +static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy, + struct link_params *params, u8 mode) +{ + struct bnx2x *bp = params->bp; + u16 val; + u8 port; + + if (!(CHIP_IS_E1(bp))) + port = BP_PATH(bp); + else + port = params->port; + + switch (mode) { + case LED_MODE_OFF: + + DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", port); + + if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) == + SHARED_HW_CFG_LED_EXTPHY1) { + + /* Set LED masks */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x0); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED2_MASK, + 0x0); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + 0x0); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED5_MASK, + 0x0); + + } else { + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x0); + } + break; + case LED_MODE_FRONT_PANEL_OFF: + + DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n", + port); + + if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) == + SHARED_HW_CFG_LED_EXTPHY1) { + + /* Set LED masks */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x0); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED2_MASK, + 0x0); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + 0x0); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED5_MASK, + 0x20); + + } else { + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x0); + } + break; + case LED_MODE_ON: + + DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", port); + + if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) == + SHARED_HW_CFG_LED_EXTPHY1) { + /* Set control reg */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + &val); + val &= 0x8000; + val |= 0x2492; + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + val); + + /* Set LED masks */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x0); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED2_MASK, + 0x20); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + 0x20); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED5_MASK, + 0x0); + } else { + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x20); + } + break; + + case LED_MODE_OPER: + + DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", port); + + if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) == + SHARED_HW_CFG_LED_EXTPHY1) { + + /* Set control reg */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + &val); + + if (!((val & + MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_MASK) + >> MDIO_PMA_REG_8481_LINK_SIGNAL_LED4_ENABLE_SHIFT)) { + DP(NETIF_MSG_LINK, "Setting LINK_SIGNAL\n"); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + 0xa492); + } + + /* Set LED masks */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x10); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED2_MASK, + 0x80); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED3_MASK, + 0x98); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED5_MASK, + 0x40); + + } else { + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LED1_MASK, + 0x80); + + /* Tell LED3 to blink on source */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + &val); + val &= ~(7<<6); + val |= (1<<6); /* A83B[8:6]= 1 */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_8481_LINK_SIGNAL, + val); + } + break; + } + + /* + * This is a workaround for E3+84833 until autoneg + * restart is fixed in f/w + */ + if (CHIP_IS_E3(bp)) { + bnx2x_cl45_read(bp, phy, MDIO_WC_DEVAD, + MDIO_WC_REG_GP2_STATUS_GP_2_1, &val); + } +} + +/******************************************************************/ +/* 54618SE PHY SECTION */ +/******************************************************************/ +static int bnx2x_54618se_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 port; + u16 autoneg_val, an_1000_val, an_10_100_val, fc_val, temp; + u32 cfg_pin; + + DP(NETIF_MSG_LINK, "54618SE cfg init\n"); + usleep_range(1000, 1000); + + /* This works with E3 only, no need to check the chip + before determining the port. */ + port = params->port; + + cfg_pin = (REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].e3_cmn_pin_cfg)) & + PORT_HW_CFG_E3_PHY_RESET_MASK) >> + PORT_HW_CFG_E3_PHY_RESET_SHIFT; + + /* Drive pin high to bring the GPHY out of reset. */ + bnx2x_set_cfg_pin(bp, cfg_pin, 1); + + /* wait for GPHY to reset */ + msleep(50); + + /* reset phy */ + bnx2x_cl22_write(bp, phy, + MDIO_PMA_REG_CTRL, 0x8000); + bnx2x_wait_reset_complete(bp, phy, params); + + /*wait for GPHY to reset */ + msleep(50); + + /* Configure LED4: set to INTR (0x6). */ + /* Accessing shadow register 0xe. */ + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_SHADOW, + MDIO_REG_GPHY_SHADOW_LED_SEL2); + bnx2x_cl22_read(bp, phy, + MDIO_REG_GPHY_SHADOW, + &temp); + temp &= ~(0xf << 4); + temp |= (0x6 << 4); + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_SHADOW, + MDIO_REG_GPHY_SHADOW_WR_ENA | temp); + /* Configure INTR based on link status change. */ + bnx2x_cl22_write(bp, phy, + MDIO_REG_INTR_MASK, + ~MDIO_REG_INTR_MASK_LINK_STATUS); + + /* Flip the signal detect polarity (set 0x1c.0x1e[8]). */ + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_SHADOW, + MDIO_REG_GPHY_SHADOW_AUTO_DET_MED); + bnx2x_cl22_read(bp, phy, + MDIO_REG_GPHY_SHADOW, + &temp); + temp |= MDIO_REG_GPHY_SHADOW_INVERT_FIB_SD; + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_SHADOW, + MDIO_REG_GPHY_SHADOW_WR_ENA | temp); + + /* Set up fc */ + /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */ + bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc); + fc_val = 0; + if ((vars->ieee_fc & MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) == + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) + fc_val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC; + + if ((vars->ieee_fc & MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) == + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) + fc_val |= MDIO_AN_REG_ADV_PAUSE_PAUSE; + + /* read all advertisement */ + bnx2x_cl22_read(bp, phy, + 0x09, + &an_1000_val); + + bnx2x_cl22_read(bp, phy, + 0x04, + &an_10_100_val); + + bnx2x_cl22_read(bp, phy, + MDIO_PMA_REG_CTRL, + &autoneg_val); + + /* Disable forced speed */ + autoneg_val &= ~((1<<6) | (1<<8) | (1<<9) | (1<<12) | (1<<13)); + an_10_100_val &= ~((1<<5) | (1<<6) | (1<<7) | (1<<8) | (1<<10) | + (1<<11)); + + if (((phy->req_line_speed == SPEED_AUTO_NEG) && + (phy->speed_cap_mask & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) || + (phy->req_line_speed == SPEED_1000)) { + an_1000_val |= (1<<8); + autoneg_val |= (1<<9 | 1<<12); + if (phy->req_duplex == DUPLEX_FULL) + an_1000_val |= (1<<9); + DP(NETIF_MSG_LINK, "Advertising 1G\n"); + } else + an_1000_val &= ~((1<<8) | (1<<9)); + + bnx2x_cl22_write(bp, phy, + 0x09, + an_1000_val); + bnx2x_cl22_read(bp, phy, + 0x09, + &an_1000_val); + + /* set 100 speed advertisement */ + if (((phy->req_line_speed == SPEED_AUTO_NEG) && + (phy->speed_cap_mask & + (PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL | + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)))) { + an_10_100_val |= (1<<7); + /* Enable autoneg and restart autoneg for legacy speeds */ + autoneg_val |= (1<<9 | 1<<12); + + if (phy->req_duplex == DUPLEX_FULL) + an_10_100_val |= (1<<8); + DP(NETIF_MSG_LINK, "Advertising 100M\n"); + } + + /* set 10 speed advertisement */ + if (((phy->req_line_speed == SPEED_AUTO_NEG) && + (phy->speed_cap_mask & + (PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL | + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)))) { + an_10_100_val |= (1<<5); + autoneg_val |= (1<<9 | 1<<12); + if (phy->req_duplex == DUPLEX_FULL) + an_10_100_val |= (1<<6); + DP(NETIF_MSG_LINK, "Advertising 10M\n"); + } + + /* Only 10/100 are allowed to work in FORCE mode */ + if (phy->req_line_speed == SPEED_100) { + autoneg_val |= (1<<13); + /* Enabled AUTO-MDIX when autoneg is disabled */ + bnx2x_cl22_write(bp, phy, + 0x18, + (1<<15 | 1<<9 | 7<<0)); + DP(NETIF_MSG_LINK, "Setting 100M force\n"); + } + if (phy->req_line_speed == SPEED_10) { + /* Enabled AUTO-MDIX when autoneg is disabled */ + bnx2x_cl22_write(bp, phy, + 0x18, + (1<<15 | 1<<9 | 7<<0)); + DP(NETIF_MSG_LINK, "Setting 10M force\n"); + } + + /* Check if we should turn on Auto-GrEEEn */ + bnx2x_cl22_read(bp, phy, MDIO_REG_GPHY_PHYID_LSB, &temp); + if (temp == MDIO_REG_GPHY_ID_54618SE) { + if (params->feature_config_flags & + FEATURE_CONFIG_AUTOGREEEN_ENABLED) { + temp = 6; + DP(NETIF_MSG_LINK, "Enabling Auto-GrEEEn\n"); + } else { + temp = 0; + DP(NETIF_MSG_LINK, "Disabling Auto-GrEEEn\n"); + } + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_CL45_ADDR_REG, MDIO_AN_DEVAD); + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_CL45_DATA_REG, + MDIO_REG_GPHY_EEE_ADV); + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_CL45_ADDR_REG, + (0x1 << 14) | MDIO_AN_DEVAD); + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_CL45_DATA_REG, + temp); + } + + bnx2x_cl22_write(bp, phy, + 0x04, + an_10_100_val | fc_val); + + if (phy->req_duplex == DUPLEX_FULL) + autoneg_val |= (1<<8); + + bnx2x_cl22_write(bp, phy, + MDIO_PMA_REG_CTRL, autoneg_val); + + return 0; +} + +static void bnx2x_54618se_set_link_led(struct bnx2x_phy *phy, + struct link_params *params, u8 mode) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "54618SE set link led (mode=%x)\n", mode); + switch (mode) { + case LED_MODE_FRONT_PANEL_OFF: + case LED_MODE_OFF: + case LED_MODE_OPER: + case LED_MODE_ON: + default: + break; + } + return; +} + +static void bnx2x_54618se_link_reset(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u32 cfg_pin; + u8 port; + + /* + * In case of no EPIO routed to reset the GPHY, put it + * in low power mode. + */ + bnx2x_cl22_write(bp, phy, MDIO_PMA_REG_CTRL, 0x800); + /* + * This works with E3 only, no need to check the chip + * before determining the port. + */ + port = params->port; + cfg_pin = (REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].e3_cmn_pin_cfg)) & + PORT_HW_CFG_E3_PHY_RESET_MASK) >> + PORT_HW_CFG_E3_PHY_RESET_SHIFT; + + /* Drive pin low to put GPHY in reset. */ + bnx2x_set_cfg_pin(bp, cfg_pin, 0); +} + +static u8 bnx2x_54618se_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 val; + u8 link_up = 0; + u16 legacy_status, legacy_speed; + + /* Get speed operation status */ + bnx2x_cl22_read(bp, phy, + 0x19, + &legacy_status); + DP(NETIF_MSG_LINK, "54618SE read_status: 0x%x\n", legacy_status); + + /* Read status to clear the PHY interrupt. */ + bnx2x_cl22_read(bp, phy, + MDIO_REG_INTR_STATUS, + &val); + + link_up = ((legacy_status & (1<<2)) == (1<<2)); + + if (link_up) { + legacy_speed = (legacy_status & (7<<8)); + if (legacy_speed == (7<<8)) { + vars->line_speed = SPEED_1000; + vars->duplex = DUPLEX_FULL; + } else if (legacy_speed == (6<<8)) { + vars->line_speed = SPEED_1000; + vars->duplex = DUPLEX_HALF; + } else if (legacy_speed == (5<<8)) { + vars->line_speed = SPEED_100; + vars->duplex = DUPLEX_FULL; + } + /* Omitting 100Base-T4 for now */ + else if (legacy_speed == (3<<8)) { + vars->line_speed = SPEED_100; + vars->duplex = DUPLEX_HALF; + } else if (legacy_speed == (2<<8)) { + vars->line_speed = SPEED_10; + vars->duplex = DUPLEX_FULL; + } else if (legacy_speed == (1<<8)) { + vars->line_speed = SPEED_10; + vars->duplex = DUPLEX_HALF; + } else /* Should not happen */ + vars->line_speed = 0; + + DP(NETIF_MSG_LINK, "Link is up in %dMbps," + " is_duplex_full= %d\n", vars->line_speed, + (vars->duplex == DUPLEX_FULL)); + + /* Check legacy speed AN resolution */ + bnx2x_cl22_read(bp, phy, + 0x01, + &val); + if (val & (1<<5)) + vars->link_status |= + LINK_STATUS_AUTO_NEGOTIATE_COMPLETE; + bnx2x_cl22_read(bp, phy, + 0x06, + &val); + if ((val & (1<<0)) == 0) + vars->link_status |= + LINK_STATUS_PARALLEL_DETECTION_USED; + + DP(NETIF_MSG_LINK, "BCM54618SE: link speed is %d\n", + vars->line_speed); + + /* Report whether EEE is resolved. */ + bnx2x_cl22_read(bp, phy, MDIO_REG_GPHY_PHYID_LSB, &val); + if (val == MDIO_REG_GPHY_ID_54618SE) { + if (vars->link_status & + LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) + val = 0; + else { + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_CL45_ADDR_REG, + MDIO_AN_DEVAD); + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_CL45_DATA_REG, + MDIO_REG_GPHY_EEE_RESOLVED); + bnx2x_cl22_write(bp, phy, + MDIO_REG_GPHY_CL45_ADDR_REG, + (0x1 << 14) | MDIO_AN_DEVAD); + bnx2x_cl22_read(bp, phy, + MDIO_REG_GPHY_CL45_DATA_REG, + &val); + } + DP(NETIF_MSG_LINK, "EEE resolution: 0x%x\n", val); + } + + bnx2x_ext_phy_resolve_fc(phy, params, vars); + } + return link_up; +} + +static void bnx2x_54618se_config_loopback(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + u16 val; + u32 umac_base = params->port ? GRCBASE_UMAC1 : GRCBASE_UMAC0; + + DP(NETIF_MSG_LINK, "2PMA/PMD ext_phy_loopback: 54618se\n"); + + /* Enable master/slave manual mmode and set to master */ + /* mii write 9 [bits set 11 12] */ + bnx2x_cl22_write(bp, phy, 0x09, 3<<11); + + /* forced 1G and disable autoneg */ + /* set val [mii read 0] */ + /* set val [expr $val & [bits clear 6 12 13]] */ + /* set val [expr $val | [bits set 6 8]] */ + /* mii write 0 $val */ + bnx2x_cl22_read(bp, phy, 0x00, &val); + val &= ~((1<<6) | (1<<12) | (1<<13)); + val |= (1<<6) | (1<<8); + bnx2x_cl22_write(bp, phy, 0x00, val); + + /* Set external loopback and Tx using 6dB coding */ + /* mii write 0x18 7 */ + /* set val [mii read 0x18] */ + /* mii write 0x18 [expr $val | [bits set 10 15]] */ + bnx2x_cl22_write(bp, phy, 0x18, 7); + bnx2x_cl22_read(bp, phy, 0x18, &val); + bnx2x_cl22_write(bp, phy, 0x18, val | (1<<10) | (1<<15)); + + /* This register opens the gate for the UMAC despite its name */ + REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + params->port*4, 1); + + /* + * Maximum Frame Length (RW). Defines a 14-Bit maximum frame + * length used by the MAC receive logic to check frames. + */ + REG_WR(bp, umac_base + UMAC_REG_MAXFR, 0x2710); +} + +/******************************************************************/ +/* SFX7101 PHY SECTION */ +/******************************************************************/ +static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy, + struct link_params *params) +{ + struct bnx2x *bp = params->bp; + /* SFX7101_XGXS_TEST1 */ + bnx2x_cl45_write(bp, phy, + MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100); +} + +static int bnx2x_7101_config_init(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + u16 fw_ver1, fw_ver2, val; + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "Setting the SFX7101 LASI indication\n"); + + /* Restore normal power mode*/ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_HIGH, params->port); + /* HW reset */ + bnx2x_ext_phy_hw_reset(bp, params->port); + bnx2x_wait_reset_complete(bp, phy, params); + + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_CTRL, 0x1); + DP(NETIF_MSG_LINK, "Setting the SFX7101 LED to blink on traffic\n"); + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_7107_LED_CNTL, (1<<3)); + + bnx2x_ext_phy_set_pause(params, phy, vars); + /* Restart autoneg */ + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, &val); + val |= 0x200; + bnx2x_cl45_write(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_CTRL, val); + + /* Save spirom version */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER1, &fw_ver1); + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_7101_VER2, &fw_ver2); + bnx2x_save_spirom_version(bp, params->port, + (u32)(fw_ver1<<16 | fw_ver2), phy->ver_addr); + return 0; +} + +static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u8 link_up; + u16 val1, val2; + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val2); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_LASI_STAT, &val1); + DP(NETIF_MSG_LINK, "10G-base-T LASI status 0x%x->0x%x\n", + val2, val1); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val2); + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, MDIO_PMA_REG_STATUS, &val1); + DP(NETIF_MSG_LINK, "10G-base-T PMA status 0x%x->0x%x\n", + val2, val1); + link_up = ((val1 & 4) == 4); + /* if link is up print the AN outcome of the SFX7101 PHY */ + if (link_up) { + bnx2x_cl45_read(bp, phy, + MDIO_AN_DEVAD, MDIO_AN_REG_MASTER_STATUS, + &val2); + vars->line_speed = SPEED_10000; + vars->duplex = DUPLEX_FULL; + DP(NETIF_MSG_LINK, "SFX7101 AN status 0x%x->Master=%x\n", + val2, (val2 & (1<<14))); + bnx2x_ext_phy_10G_an_resolve(bp, phy, vars); + bnx2x_ext_phy_resolve_fc(phy, params, vars); + } + return link_up; +} + +static int bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len) +{ + if (*len < 5) + return -EINVAL; + str[0] = (spirom_ver & 0xFF); + str[1] = (spirom_ver & 0xFF00) >> 8; + str[2] = (spirom_ver & 0xFF0000) >> 16; + str[3] = (spirom_ver & 0xFF000000) >> 24; + str[4] = '\0'; + *len -= 5; + return 0; +} + +void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy) +{ + u16 val, cnt; + + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_RESET, &val); + + for (cnt = 0; cnt < 10; cnt++) { + msleep(50); + /* Writes a self-clearing reset */ + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_RESET, + (val | (1<<15))); + /* Wait for clear */ + bnx2x_cl45_read(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7101_RESET, &val); + + if ((val & (1<<15)) == 0) + break; + } +} + +static void bnx2x_7101_hw_reset(struct bnx2x_phy *phy, + struct link_params *params) { + /* Low power mode is controlled by GPIO 2 */ + bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port); + /* The PHY reset is controlled by GPIO 1 */ + bnx2x_set_gpio(params->bp, MISC_REGISTERS_GPIO_1, + MISC_REGISTERS_GPIO_OUTPUT_LOW, params->port); +} + +static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy, + struct link_params *params, u8 mode) +{ + u16 val = 0; + struct bnx2x *bp = params->bp; + switch (mode) { + case LED_MODE_FRONT_PANEL_OFF: + case LED_MODE_OFF: + val = 2; + break; + case LED_MODE_ON: + val = 1; + break; + case LED_MODE_OPER: + val = 0; + break; + } + bnx2x_cl45_write(bp, phy, + MDIO_PMA_DEVAD, + MDIO_PMA_REG_7107_LINK_LED_CNTL, + val); +} + +/******************************************************************/ +/* STATIC PHY DECLARATION */ +/******************************************************************/ + +static struct bnx2x_phy phy_null = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN, + .addr = 0, + .def_md_devad = 0, + .flags = FLAGS_INIT_XGXS_FIRST, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = 0, + .media_type = ETH_PHY_NOT_PRESENT, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)NULL, + .read_status = (read_status_t)NULL, + .link_reset = (link_reset_t)NULL, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)NULL, + .hw_reset = (hw_reset_t)NULL, + .set_link_led = (set_link_led_t)NULL, + .phy_specific_func = (phy_specific_func_t)NULL +}; + +static struct bnx2x_phy phy_serdes = { + .type = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT, + .addr = 0xff, + .def_md_devad = 0, + .flags = 0, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_2500baseX_Full | + SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_BASE_T, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_xgxs_config_init, + .read_status = (read_status_t)bnx2x_link_settings_status, + .link_reset = (link_reset_t)bnx2x_int_link_reset, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)NULL, + .hw_reset = (hw_reset_t)NULL, + .set_link_led = (set_link_led_t)NULL, + .phy_specific_func = (phy_specific_func_t)NULL +}; + +static struct bnx2x_phy phy_xgxs = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT, + .addr = 0xff, + .def_md_devad = 0, + .flags = 0, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_2500baseX_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_CX4, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_xgxs_config_init, + .read_status = (read_status_t)bnx2x_link_settings_status, + .link_reset = (link_reset_t)bnx2x_int_link_reset, + .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback, + .format_fw_ver = (format_fw_ver_t)NULL, + .hw_reset = (hw_reset_t)NULL, + .set_link_led = (set_link_led_t)NULL, + .phy_specific_func = (phy_specific_func_t)NULL +}; +static struct bnx2x_phy phy_warpcore = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT, + .addr = 0xff, + .def_md_devad = 0, + .flags = (FLAGS_HW_LOCK_REQUIRED | + FLAGS_TX_ERROR_CHECK), + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_20000baseKR2_Full | + SUPPORTED_20000baseMLD2_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_UNSPECIFIED, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + /* req_duplex = */0, + /* rsrv = */0, + .config_init = (config_init_t)bnx2x_warpcore_config_init, + .read_status = (read_status_t)bnx2x_warpcore_read_status, + .link_reset = (link_reset_t)bnx2x_warpcore_link_reset, + .config_loopback = (config_loopback_t)bnx2x_set_warpcore_loopback, + .format_fw_ver = (format_fw_ver_t)NULL, + .hw_reset = (hw_reset_t)bnx2x_warpcore_hw_reset, + .set_link_led = (set_link_led_t)NULL, + .phy_specific_func = (phy_specific_func_t)NULL +}; + + +static struct bnx2x_phy phy_7101 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101, + .addr = 0xff, + .def_md_devad = 0, + .flags = FLAGS_FAN_FAILURE_DET_REQ, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10000baseT_Full | + SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_BASE_T, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_7101_config_init, + .read_status = (read_status_t)bnx2x_7101_read_status, + .link_reset = (link_reset_t)bnx2x_common_ext_link_reset, + .config_loopback = (config_loopback_t)bnx2x_7101_config_loopback, + .format_fw_ver = (format_fw_ver_t)bnx2x_7101_format_ver, + .hw_reset = (hw_reset_t)bnx2x_7101_hw_reset, + .set_link_led = (set_link_led_t)bnx2x_7101_set_link_led, + .phy_specific_func = (phy_specific_func_t)NULL +}; +static struct bnx2x_phy phy_8073 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073, + .addr = 0xff, + .def_md_devad = 0, + .flags = FLAGS_HW_LOCK_REQUIRED, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10000baseT_Full | + SUPPORTED_2500baseX_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_KR, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_8073_config_init, + .read_status = (read_status_t)bnx2x_8073_read_status, + .link_reset = (link_reset_t)bnx2x_8073_link_reset, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, + .hw_reset = (hw_reset_t)NULL, + .set_link_led = (set_link_led_t)NULL, + .phy_specific_func = (phy_specific_func_t)NULL +}; +static struct bnx2x_phy phy_8705 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705, + .addr = 0xff, + .def_md_devad = 0, + .flags = FLAGS_INIT_XGXS_FIRST, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_XFP_FIBER, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_8705_config_init, + .read_status = (read_status_t)bnx2x_8705_read_status, + .link_reset = (link_reset_t)bnx2x_common_ext_link_reset, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)bnx2x_null_format_ver, + .hw_reset = (hw_reset_t)NULL, + .set_link_led = (set_link_led_t)NULL, + .phy_specific_func = (phy_specific_func_t)NULL +}; +static struct bnx2x_phy phy_8706 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706, + .addr = 0xff, + .def_md_devad = 0, + .flags = (FLAGS_INIT_XGXS_FIRST | + FLAGS_TX_ERROR_CHECK), + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_SFP_FIBER, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_8706_config_init, + .read_status = (read_status_t)bnx2x_8706_read_status, + .link_reset = (link_reset_t)bnx2x_common_ext_link_reset, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, + .hw_reset = (hw_reset_t)NULL, + .set_link_led = (set_link_led_t)NULL, + .phy_specific_func = (phy_specific_func_t)NULL +}; + +static struct bnx2x_phy phy_8726 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726, + .addr = 0xff, + .def_md_devad = 0, + .flags = (FLAGS_HW_LOCK_REQUIRED | + FLAGS_INIT_XGXS_FIRST | + FLAGS_TX_ERROR_CHECK), + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_NOT_PRESENT, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_8726_config_init, + .read_status = (read_status_t)bnx2x_8726_read_status, + .link_reset = (link_reset_t)bnx2x_8726_link_reset, + .config_loopback = (config_loopback_t)bnx2x_8726_config_loopback, + .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, + .hw_reset = (hw_reset_t)NULL, + .set_link_led = (set_link_led_t)NULL, + .phy_specific_func = (phy_specific_func_t)NULL +}; + +static struct bnx2x_phy phy_8727 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727, + .addr = 0xff, + .def_md_devad = 0, + .flags = (FLAGS_FAN_FAILURE_DET_REQ | + FLAGS_TX_ERROR_CHECK), + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10000baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_NOT_PRESENT, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_8727_config_init, + .read_status = (read_status_t)bnx2x_8727_read_status, + .link_reset = (link_reset_t)bnx2x_8727_link_reset, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)bnx2x_format_ver, + .hw_reset = (hw_reset_t)bnx2x_8727_hw_reset, + .set_link_led = (set_link_led_t)bnx2x_8727_set_link_led, + .phy_specific_func = (phy_specific_func_t)bnx2x_8727_specific_func +}; +static struct bnx2x_phy phy_8481 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481, + .addr = 0xff, + .def_md_devad = 0, + .flags = FLAGS_FAN_FAILURE_DET_REQ | + FLAGS_REARM_LATCH_SIGNAL, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_BASE_T, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_8481_config_init, + .read_status = (read_status_t)bnx2x_848xx_read_status, + .link_reset = (link_reset_t)bnx2x_8481_link_reset, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, + .hw_reset = (hw_reset_t)bnx2x_8481_hw_reset, + .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led, + .phy_specific_func = (phy_specific_func_t)NULL +}; + +static struct bnx2x_phy phy_84823 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823, + .addr = 0xff, + .def_md_devad = 0, + .flags = FLAGS_FAN_FAILURE_DET_REQ | + FLAGS_REARM_LATCH_SIGNAL, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_BASE_T, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_848x3_config_init, + .read_status = (read_status_t)bnx2x_848xx_read_status, + .link_reset = (link_reset_t)bnx2x_848x3_link_reset, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, + .hw_reset = (hw_reset_t)NULL, + .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led, + .phy_specific_func = (phy_specific_func_t)NULL +}; + +static struct bnx2x_phy phy_84833 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833, + .addr = 0xff, + .def_md_devad = 0, + .flags = FLAGS_FAN_FAILURE_DET_REQ | + FLAGS_REARM_LATCH_SIGNAL, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_BASE_T, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_848x3_config_init, + .read_status = (read_status_t)bnx2x_848xx_read_status, + .link_reset = (link_reset_t)bnx2x_848x3_link_reset, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, + .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, + .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led, + .phy_specific_func = (phy_specific_func_t)NULL +}; + +static struct bnx2x_phy phy_54618se = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE, + .addr = 0xff, + .def_md_devad = 0, + .flags = FLAGS_INIT_XGXS_FIRST, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_BASE_T, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + /* req_duplex = */0, + /* rsrv = */0, + .config_init = (config_init_t)bnx2x_54618se_config_init, + .read_status = (read_status_t)bnx2x_54618se_read_status, + .link_reset = (link_reset_t)bnx2x_54618se_link_reset, + .config_loopback = (config_loopback_t)bnx2x_54618se_config_loopback, + .format_fw_ver = (format_fw_ver_t)NULL, + .hw_reset = (hw_reset_t)NULL, + .set_link_led = (set_link_led_t)bnx2x_54618se_set_link_led, + .phy_specific_func = (phy_specific_func_t)NULL +}; +/*****************************************************************/ +/* */ +/* Populate the phy according. Main function: bnx2x_populate_phy */ +/* */ +/*****************************************************************/ + +static void bnx2x_populate_preemphasis(struct bnx2x *bp, u32 shmem_base, + struct bnx2x_phy *phy, u8 port, + u8 phy_index) +{ + /* Get the 4 lanes xgxs config rx and tx */ + u32 rx = 0, tx = 0, i; + for (i = 0; i < 2; i++) { + /* + * INT_PHY and EXT_PHY1 share the same value location in the + * shmem. When num_phys is greater than 1, than this value + * applies only to EXT_PHY1 + */ + if (phy_index == INT_PHY || phy_index == EXT_PHY1) { + rx = REG_RD(bp, shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].xgxs_config_rx[i<<1])); + + tx = REG_RD(bp, shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].xgxs_config_tx[i<<1])); + } else { + rx = REG_RD(bp, shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].xgxs_config2_rx[i<<1])); + + tx = REG_RD(bp, shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].xgxs_config2_rx[i<<1])); + } + + phy->rx_preemphasis[i << 1] = ((rx>>16) & 0xffff); + phy->rx_preemphasis[(i << 1) + 1] = (rx & 0xffff); + + phy->tx_preemphasis[i << 1] = ((tx>>16) & 0xffff); + phy->tx_preemphasis[(i << 1) + 1] = (tx & 0xffff); + } +} + +static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base, + u8 phy_index, u8 port) +{ + u32 ext_phy_config = 0; + switch (phy_index) { + case EXT_PHY1: + ext_phy_config = REG_RD(bp, shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].external_phy_config)); + break; + case EXT_PHY2: + ext_phy_config = REG_RD(bp, shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].external_phy_config2)); + break; + default: + DP(NETIF_MSG_LINK, "Invalid phy_index %d\n", phy_index); + return -EINVAL; + } + + return ext_phy_config; +} +static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port, + struct bnx2x_phy *phy) +{ + u32 phy_addr; + u32 chip_id; + u32 switch_cfg = (REG_RD(bp, shmem_base + + offsetof(struct shmem_region, + dev_info.port_feature_config[port].link_config)) & + PORT_FEATURE_CONNECTED_SWITCH_MASK); + chip_id = REG_RD(bp, MISC_REG_CHIP_NUM) << 16; + DP(NETIF_MSG_LINK, ":chip_id = 0x%x\n", chip_id); + if (USES_WARPCORE(bp)) { + u32 serdes_net_if; + phy_addr = REG_RD(bp, + MISC_REG_WC0_CTRL_PHY_ADDR); + *phy = phy_warpcore; + if (REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR) == 0x3) + phy->flags |= FLAGS_4_PORT_MODE; + else + phy->flags &= ~FLAGS_4_PORT_MODE; + /* Check Dual mode */ + serdes_net_if = (REG_RD(bp, shmem_base + + offsetof(struct shmem_region, dev_info. + port_hw_config[port].default_cfg)) & + PORT_HW_CFG_NET_SERDES_IF_MASK); + /* + * Set the appropriate supported and flags indications per + * interface type of the chip + */ + switch (serdes_net_if) { + case PORT_HW_CFG_NET_SERDES_IF_SGMII: + phy->supported &= (SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + phy->media_type = ETH_PHY_BASE_T; + break; + case PORT_HW_CFG_NET_SERDES_IF_XFI: + phy->media_type = ETH_PHY_XFP_FIBER; + break; + case PORT_HW_CFG_NET_SERDES_IF_SFI: + phy->supported &= (SUPPORTED_1000baseT_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + phy->media_type = ETH_PHY_SFP_FIBER; + break; + case PORT_HW_CFG_NET_SERDES_IF_KR: + phy->media_type = ETH_PHY_KR; + phy->supported &= (SUPPORTED_1000baseT_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_FIBRE | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + case PORT_HW_CFG_NET_SERDES_IF_DXGXS: + phy->media_type = ETH_PHY_KR; + phy->flags |= FLAGS_WC_DUAL_MODE; + phy->supported &= (SUPPORTED_20000baseMLD2_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + case PORT_HW_CFG_NET_SERDES_IF_KR2: + phy->media_type = ETH_PHY_KR; + phy->flags |= FLAGS_WC_DUAL_MODE; + phy->supported &= (SUPPORTED_20000baseKR2_Full | + SUPPORTED_FIBRE | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + default: + DP(NETIF_MSG_LINK, "Unknown WC interface type 0x%x\n", + serdes_net_if); + break; + } + + /* + * Enable MDC/MDIO work-around for E3 A0 since free running MDC + * was not set as expected. For B0, ECO will be enabled so there + * won't be an issue there + */ + if (CHIP_REV(bp) == CHIP_REV_Ax) + phy->flags |= FLAGS_MDC_MDIO_WA; + else + phy->flags |= FLAGS_MDC_MDIO_WA_B0; + } else { + switch (switch_cfg) { + case SWITCH_CFG_1G: + phy_addr = REG_RD(bp, + NIG_REG_SERDES0_CTRL_PHY_ADDR + + port * 0x10); + *phy = phy_serdes; + break; + case SWITCH_CFG_10G: + phy_addr = REG_RD(bp, + NIG_REG_XGXS0_CTRL_PHY_ADDR + + port * 0x18); + *phy = phy_xgxs; + break; + default: + DP(NETIF_MSG_LINK, "Invalid switch_cfg\n"); + return -EINVAL; + } + } + phy->addr = (u8)phy_addr; + phy->mdio_ctrl = bnx2x_get_emac_base(bp, + SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH, + port); + if (CHIP_IS_E2(bp)) + phy->def_md_devad = E2_DEFAULT_PHY_DEV_ADDR; + else + phy->def_md_devad = DEFAULT_PHY_DEV_ADDR; + + DP(NETIF_MSG_LINK, "Internal phy port=%d, addr=0x%x, mdio_ctl=0x%x\n", + port, phy->addr, phy->mdio_ctrl); + + bnx2x_populate_preemphasis(bp, shmem_base, phy, port, INT_PHY); + return 0; +} + +static int bnx2x_populate_ext_phy(struct bnx2x *bp, + u8 phy_index, + u32 shmem_base, + u32 shmem2_base, + u8 port, + struct bnx2x_phy *phy) +{ + u32 ext_phy_config, phy_type, config2; + u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH; + ext_phy_config = bnx2x_get_ext_phy_config(bp, shmem_base, + phy_index, port); + phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); + /* Select the phy type */ + switch (phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_SWAPPED; + *phy = phy_8073; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705: + *phy = phy_8705; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706: + *phy = phy_8706; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1; + *phy = phy_8726; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC: + /* BCM8727_NOC => BCM8727 no over current */ + mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1; + *phy = phy_8727; + phy->flags |= FLAGS_NOC; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1; + *phy = phy_8727; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481: + *phy = phy_8481; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823: + *phy = phy_84823; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833: + *phy = phy_84833; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE: + *phy = phy_54618se; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101: + *phy = phy_7101; + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: + *phy = phy_null; + return -EINVAL; + default: + *phy = phy_null; + return 0; + } + + phy->addr = XGXS_EXT_PHY_ADDR(ext_phy_config); + bnx2x_populate_preemphasis(bp, shmem_base, phy, port, phy_index); + + /* + * The shmem address of the phy version is located on different + * structures. In case this structure is too old, do not set + * the address + */ + config2 = REG_RD(bp, shmem_base + offsetof(struct shmem_region, + dev_info.shared_hw_config.config2)); + if (phy_index == EXT_PHY1) { + phy->ver_addr = shmem_base + offsetof(struct shmem_region, + port_mb[port].ext_phy_fw_version); + + /* Check specific mdc mdio settings */ + if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK) + mdc_mdio_access = config2 & + SHARED_HW_CFG_MDC_MDIO_ACCESS1_MASK; + } else { + u32 size = REG_RD(bp, shmem2_base); + + if (size > + offsetof(struct shmem2_region, ext_phy_fw_version2)) { + phy->ver_addr = shmem2_base + + offsetof(struct shmem2_region, + ext_phy_fw_version2[port]); + } + /* Check specific mdc mdio settings */ + if (config2 & SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) + mdc_mdio_access = (config2 & + SHARED_HW_CFG_MDC_MDIO_ACCESS2_MASK) >> + (SHARED_HW_CFG_MDC_MDIO_ACCESS2_SHIFT - + SHARED_HW_CFG_MDC_MDIO_ACCESS1_SHIFT); + } + phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port); + + /* + * In case mdc/mdio_access of the external phy is different than the + * mdc/mdio access of the XGXS, a HW lock must be taken in each access + * to prevent one port interfere with another port's CL45 operations. + */ + if (mdc_mdio_access != SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH) + phy->flags |= FLAGS_HW_LOCK_REQUIRED; + DP(NETIF_MSG_LINK, "phy_type 0x%x port %d found in index %d\n", + phy_type, port, phy_index); + DP(NETIF_MSG_LINK, " addr=0x%x, mdio_ctl=0x%x\n", + phy->addr, phy->mdio_ctrl); + return 0; +} + +static int bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base, + u32 shmem2_base, u8 port, struct bnx2x_phy *phy) +{ + int status = 0; + phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN; + if (phy_index == INT_PHY) + return bnx2x_populate_int_phy(bp, shmem_base, port, phy); + status = bnx2x_populate_ext_phy(bp, phy_index, shmem_base, shmem2_base, + port, phy); + return status; +} + +static void bnx2x_phy_def_cfg(struct link_params *params, + struct bnx2x_phy *phy, + u8 phy_index) +{ + struct bnx2x *bp = params->bp; + u32 link_config; + /* Populate the default phy configuration for MF mode */ + if (phy_index == EXT_PHY2) { + link_config = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port].link_config2)); + phy->speed_cap_mask = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info. + port_hw_config[params->port].speed_capability_mask2)); + } else { + link_config = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, dev_info. + port_feature_config[params->port].link_config)); + phy->speed_cap_mask = REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info. + port_hw_config[params->port].speed_capability_mask)); + } + DP(NETIF_MSG_LINK, "Default config phy idx %x cfg 0x%x speed_cap_mask" + " 0x%x\n", phy_index, link_config, phy->speed_cap_mask); + + phy->req_duplex = DUPLEX_FULL; + switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) { + case PORT_FEATURE_LINK_SPEED_10M_HALF: + phy->req_duplex = DUPLEX_HALF; + case PORT_FEATURE_LINK_SPEED_10M_FULL: + phy->req_line_speed = SPEED_10; + break; + case PORT_FEATURE_LINK_SPEED_100M_HALF: + phy->req_duplex = DUPLEX_HALF; + case PORT_FEATURE_LINK_SPEED_100M_FULL: + phy->req_line_speed = SPEED_100; + break; + case PORT_FEATURE_LINK_SPEED_1G: + phy->req_line_speed = SPEED_1000; + break; + case PORT_FEATURE_LINK_SPEED_2_5G: + phy->req_line_speed = SPEED_2500; + break; + case PORT_FEATURE_LINK_SPEED_10G_CX4: + phy->req_line_speed = SPEED_10000; + break; + default: + phy->req_line_speed = SPEED_AUTO_NEG; + break; + } + + switch (link_config & PORT_FEATURE_FLOW_CONTROL_MASK) { + case PORT_FEATURE_FLOW_CONTROL_AUTO: + phy->req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO; + break; + case PORT_FEATURE_FLOW_CONTROL_TX: + phy->req_flow_ctrl = BNX2X_FLOW_CTRL_TX; + break; + case PORT_FEATURE_FLOW_CONTROL_RX: + phy->req_flow_ctrl = BNX2X_FLOW_CTRL_RX; + break; + case PORT_FEATURE_FLOW_CONTROL_BOTH: + phy->req_flow_ctrl = BNX2X_FLOW_CTRL_BOTH; + break; + default: + phy->req_flow_ctrl = BNX2X_FLOW_CTRL_NONE; + break; + } +} + +u32 bnx2x_phy_selection(struct link_params *params) +{ + u32 phy_config_swapped, prio_cfg; + u32 return_cfg = PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT; + + phy_config_swapped = params->multi_phy_config & + PORT_HW_CFG_PHY_SWAPPED_ENABLED; + + prio_cfg = params->multi_phy_config & + PORT_HW_CFG_PHY_SELECTION_MASK; + + if (phy_config_swapped) { + switch (prio_cfg) { + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: + return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY; + break; + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: + return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY; + break; + case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY: + return_cfg = PORT_HW_CFG_PHY_SELECTION_FIRST_PHY; + break; + case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY: + return_cfg = PORT_HW_CFG_PHY_SELECTION_SECOND_PHY; + break; + } + } else + return_cfg = prio_cfg; + + return return_cfg; +} + + +int bnx2x_phy_probe(struct link_params *params) +{ + u8 phy_index, actual_phy_idx, link_cfg_idx; + u32 phy_config_swapped, sync_offset, media_types; + struct bnx2x *bp = params->bp; + struct bnx2x_phy *phy; + params->num_phys = 0; + DP(NETIF_MSG_LINK, "Begin phy probe\n"); + phy_config_swapped = params->multi_phy_config & + PORT_HW_CFG_PHY_SWAPPED_ENABLED; + + for (phy_index = INT_PHY; phy_index < MAX_PHYS; + phy_index++) { + link_cfg_idx = LINK_CONFIG_IDX(phy_index); + actual_phy_idx = phy_index; + if (phy_config_swapped) { + if (phy_index == EXT_PHY1) + actual_phy_idx = EXT_PHY2; + else if (phy_index == EXT_PHY2) + actual_phy_idx = EXT_PHY1; + } + DP(NETIF_MSG_LINK, "phy_config_swapped %x, phy_index %x," + " actual_phy_idx %x\n", phy_config_swapped, + phy_index, actual_phy_idx); + phy = ¶ms->phy[actual_phy_idx]; + if (bnx2x_populate_phy(bp, phy_index, params->shmem_base, + params->shmem2_base, params->port, + phy) != 0) { + params->num_phys = 0; + DP(NETIF_MSG_LINK, "phy probe failed in phy index %d\n", + phy_index); + for (phy_index = INT_PHY; + phy_index < MAX_PHYS; + phy_index++) + *phy = phy_null; + return -EINVAL; + } + if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN) + break; + + sync_offset = params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[params->port].media_type); + media_types = REG_RD(bp, sync_offset); + + /* + * Update media type for non-PMF sync only for the first time + * In case the media type changes afterwards, it will be updated + * using the update_status function + */ + if ((media_types & (PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK << + (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * + actual_phy_idx))) == 0) { + media_types |= ((phy->media_type & + PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) << + (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * + actual_phy_idx)); + } + REG_WR(bp, sync_offset, media_types); + + bnx2x_phy_def_cfg(params, phy, phy_index); + params->num_phys++; + } + + DP(NETIF_MSG_LINK, "End phy probe. #phys found %x\n", params->num_phys); + return 0; +} + +void bnx2x_init_bmac_loopback(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + vars->link_up = 1; + vars->line_speed = SPEED_10000; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + vars->mac_type = MAC_TYPE_BMAC; + + vars->phy_flags = PHY_XGXS_FLAG; + + bnx2x_xgxs_deassert(params); + + /* set bmac loopback */ + bnx2x_bmac_enable(params, vars, 1); + + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); +} + +void bnx2x_init_emac_loopback(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + vars->link_up = 1; + vars->line_speed = SPEED_1000; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + vars->mac_type = MAC_TYPE_EMAC; + + vars->phy_flags = PHY_XGXS_FLAG; + + bnx2x_xgxs_deassert(params); + /* set bmac loopback */ + bnx2x_emac_enable(params, vars, 1); + bnx2x_emac_program(params, vars); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); +} + +void bnx2x_init_xmac_loopback(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + vars->link_up = 1; + if (!params->req_line_speed[0]) + vars->line_speed = SPEED_10000; + else + vars->line_speed = params->req_line_speed[0]; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + vars->mac_type = MAC_TYPE_XMAC; + vars->phy_flags = PHY_XGXS_FLAG; + /* + * Set WC to loopback mode since link is required to provide clock + * to the XMAC in 20G mode + */ + bnx2x_set_aer_mmd(params, ¶ms->phy[0]); + bnx2x_warpcore_reset_lane(bp, ¶ms->phy[0], 0); + params->phy[INT_PHY].config_loopback( + ¶ms->phy[INT_PHY], + params); + + bnx2x_xmac_enable(params, vars, 1); + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); +} + +void bnx2x_init_umac_loopback(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + vars->link_up = 1; + vars->line_speed = SPEED_1000; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + vars->mac_type = MAC_TYPE_UMAC; + vars->phy_flags = PHY_XGXS_FLAG; + bnx2x_umac_enable(params, vars, 1); + + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); +} + +void bnx2x_init_xgxs_loopback(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + vars->link_up = 1; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + vars->duplex = DUPLEX_FULL; + if (params->req_line_speed[0] == SPEED_1000) + vars->line_speed = SPEED_1000; + else + vars->line_speed = SPEED_10000; + + if (!USES_WARPCORE(bp)) + bnx2x_xgxs_deassert(params); + bnx2x_link_initialize(params, vars); + + if (params->req_line_speed[0] == SPEED_1000) { + if (USES_WARPCORE(bp)) + bnx2x_umac_enable(params, vars, 0); + else { + bnx2x_emac_program(params, vars); + bnx2x_emac_enable(params, vars, 0); + } + } else { + if (USES_WARPCORE(bp)) + bnx2x_xmac_enable(params, vars, 0); + else + bnx2x_bmac_enable(params, vars, 0); + } + + if (params->loopback_mode == LOOPBACK_XGXS) { + /* set 10G XGXS loopback */ + params->phy[INT_PHY].config_loopback( + ¶ms->phy[INT_PHY], + params); + + } else { + /* set external phy loopback */ + u8 phy_index; + for (phy_index = EXT_PHY1; + phy_index < params->num_phys; phy_index++) { + if (params->phy[phy_index].config_loopback) + params->phy[phy_index].config_loopback( + ¶ms->phy[phy_index], + params); + } + } + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0); + + bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed); +} + +int bnx2x_phy_init(struct link_params *params, struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + DP(NETIF_MSG_LINK, "Phy Initialization started\n"); + DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n", + params->req_line_speed[0], params->req_flow_ctrl[0]); + DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n", + params->req_line_speed[1], params->req_flow_ctrl[1]); + vars->link_status = 0; + vars->phy_link_up = 0; + vars->link_up = 0; + vars->line_speed = 0; + vars->duplex = DUPLEX_FULL; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; + vars->mac_type = MAC_TYPE_NONE; + vars->phy_flags = 0; + + /* disable attentions */ + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + bnx2x_emac_init(params, vars); + + if (params->num_phys == 0) { + DP(NETIF_MSG_LINK, "No phy found for initialization !!\n"); + return -EINVAL; + } + set_phy_vars(params, vars); + + DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys); + switch (params->loopback_mode) { + case LOOPBACK_BMAC: + bnx2x_init_bmac_loopback(params, vars); + break; + case LOOPBACK_EMAC: + bnx2x_init_emac_loopback(params, vars); + break; + case LOOPBACK_XMAC: + bnx2x_init_xmac_loopback(params, vars); + break; + case LOOPBACK_UMAC: + bnx2x_init_umac_loopback(params, vars); + break; + case LOOPBACK_XGXS: + case LOOPBACK_EXT_PHY: + bnx2x_init_xgxs_loopback(params, vars); + break; + default: + if (!CHIP_IS_E3(bp)) { + if (params->switch_cfg == SWITCH_CFG_10G) + bnx2x_xgxs_deassert(params); + else + bnx2x_serdes_deassert(bp, params->port); + } + bnx2x_link_initialize(params, vars); + msleep(30); + bnx2x_link_int_enable(params); + break; + } + return 0; +} + +int bnx2x_link_reset(struct link_params *params, struct link_vars *vars, + u8 reset_ext_phy) +{ + struct bnx2x *bp = params->bp; + u8 phy_index, port = params->port, clear_latch_ind = 0; + DP(NETIF_MSG_LINK, "Resetting the link of port %d\n", port); + /* disable attentions */ + vars->link_status = 0; + bnx2x_update_mng(params, vars->link_status); + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + /* activate nig drain */ + REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + port*4, 1); + + /* disable nig egress interface */ + if (!CHIP_IS_E3(bp)) { + REG_WR(bp, NIG_REG_BMAC0_OUT_EN + port*4, 0); + REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0); + } + + /* Stop BigMac rx */ + if (!CHIP_IS_E3(bp)) + bnx2x_bmac_rx_disable(bp, port); + else + bnx2x_xmac_disable(params); + /* disable emac */ + if (!CHIP_IS_E3(bp)) + REG_WR(bp, NIG_REG_NIG_EMAC0_EN + port*4, 0); + + msleep(10); + /* The PHY reset is controlled by GPIO 1 + * Hold it as vars low + */ + /* clear link led */ + bnx2x_set_led(params, vars, LED_MODE_OFF, 0); + + if (reset_ext_phy) { + bnx2x_set_mdio_clk(bp, params->chip_id, port); + for (phy_index = EXT_PHY1; phy_index < params->num_phys; + phy_index++) { + if (params->phy[phy_index].link_reset) { + bnx2x_set_aer_mmd(params, + ¶ms->phy[phy_index]); + params->phy[phy_index].link_reset( + ¶ms->phy[phy_index], + params); + } + if (params->phy[phy_index].flags & + FLAGS_REARM_LATCH_SIGNAL) + clear_latch_ind = 1; + } + } + + if (clear_latch_ind) { + /* Clear latching indication */ + bnx2x_rearm_latch_signal(bp, port, 0); + bnx2x_bits_dis(bp, NIG_REG_LATCH_BC_0 + port*4, + 1 << NIG_LATCH_BC_ENABLE_MI_INT); + } + if (params->phy[INT_PHY].link_reset) + params->phy[INT_PHY].link_reset( + ¶ms->phy[INT_PHY], params); + /* reset BigMac */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << port)); + + /* disable nig ingress interface */ + if (!CHIP_IS_E3(bp)) { + REG_WR(bp, NIG_REG_BMAC0_IN_EN + port*4, 0); + REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0); + } + vars->link_up = 0; + vars->phy_flags = 0; + return 0; +} + +/****************************************************************************/ +/* Common function */ +/****************************************************************************/ +static int bnx2x_8073_common_init_phy(struct bnx2x *bp, + u32 shmem_base_path[], + u32 shmem2_base_path[], u8 phy_index, + u32 chip_id) +{ + struct bnx2x_phy phy[PORT_MAX]; + struct bnx2x_phy *phy_blk[PORT_MAX]; + u16 val; + s8 port = 0; + s8 port_of_path = 0; + u32 swap_val, swap_override; + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + port ^= (swap_val && swap_override); + bnx2x_ext_phy_hw_reset(bp, port); + /* PART1 - Reset both phys */ + for (port = PORT_MAX - 1; port >= PORT_0; port--) { + u32 shmem_base, shmem2_base; + /* In E2, same phy is using for port0 of the two paths */ + if (CHIP_IS_E1x(bp)) { + shmem_base = shmem_base_path[0]; + shmem2_base = shmem2_base_path[0]; + port_of_path = port; + } else { + shmem_base = shmem_base_path[port]; + shmem2_base = shmem2_base_path[port]; + port_of_path = 0; + } + + /* Extract the ext phy address for the port */ + if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base, + port_of_path, &phy[port]) != + 0) { + DP(NETIF_MSG_LINK, "populate_phy failed\n"); + return -EINVAL; + } + /* disable attentions */ + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + + port_of_path*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + /* Need to take the phy out of low power mode in order + to write to access its registers */ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_HIGH, + port); + + /* Reset the phy */ + bnx2x_cl45_write(bp, &phy[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_CTRL, + 1<<15); + } + + /* Add delay of 150ms after reset */ + msleep(150); + + if (phy[PORT_0].addr & 0x1) { + phy_blk[PORT_0] = &(phy[PORT_1]); + phy_blk[PORT_1] = &(phy[PORT_0]); + } else { + phy_blk[PORT_0] = &(phy[PORT_0]); + phy_blk[PORT_1] = &(phy[PORT_1]); + } + + /* PART2 - Download firmware to both phys */ + for (port = PORT_MAX - 1; port >= PORT_0; port--) { + if (CHIP_IS_E1x(bp)) + port_of_path = port; + else + port_of_path = 0; + + DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n", + phy_blk[port]->addr); + if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port], + port_of_path)) + return -EINVAL; + + /* Only set bit 10 = 1 (Tx power down) */ + bnx2x_cl45_read(bp, phy_blk[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_POWER_DOWN, &val); + + /* Phase1 of TX_POWER_DOWN reset */ + bnx2x_cl45_write(bp, phy_blk[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_POWER_DOWN, + (val | 1<<10)); + } + + /* + * Toggle Transmitter: Power down and then up with 600ms delay + * between + */ + msleep(600); + + /* PART3 - complete TX_POWER_DOWN process, and set GPIO2 back to low */ + for (port = PORT_MAX - 1; port >= PORT_0; port--) { + /* Phase2 of POWER_DOWN_RESET */ + /* Release bit 10 (Release Tx power down) */ + bnx2x_cl45_read(bp, phy_blk[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_POWER_DOWN, &val); + + bnx2x_cl45_write(bp, phy_blk[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_POWER_DOWN, (val & (~(1<<10)))); + msleep(15); + + /* Read modify write the SPI-ROM version select register */ + bnx2x_cl45_read(bp, phy_blk[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_EDC_FFE_MAIN, &val); + bnx2x_cl45_write(bp, phy_blk[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_EDC_FFE_MAIN, (val | (1<<12))); + + /* set GPIO2 back to LOW */ + bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_2, + MISC_REGISTERS_GPIO_OUTPUT_LOW, port); + } + return 0; +} +static int bnx2x_8726_common_init_phy(struct bnx2x *bp, + u32 shmem_base_path[], + u32 shmem2_base_path[], u8 phy_index, + u32 chip_id) +{ + u32 val; + s8 port; + struct bnx2x_phy phy; + /* Use port1 because of the static port-swap */ + /* Enable the module detection interrupt */ + val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN); + val |= ((1<= PORT_0; port--) { + u32 shmem_base, shmem2_base; + + /* In E2, same phy is using for port0 of the two paths */ + if (CHIP_IS_E1x(bp)) { + shmem_base = shmem_base_path[0]; + shmem2_base = shmem2_base_path[0]; + port_of_path = port; + } else { + shmem_base = shmem_base_path[port]; + shmem2_base = shmem2_base_path[port]; + port_of_path = 0; + } + + /* Extract the ext phy address for the port */ + if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base, + port_of_path, &phy[port]) != + 0) { + DP(NETIF_MSG_LINK, "populate phy failed\n"); + return -EINVAL; + } + /* disable attentions */ + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + + port_of_path*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + + /* Reset the phy */ + bnx2x_cl45_write(bp, &phy[port], + MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15); + } + + /* Add delay of 150ms after reset */ + msleep(150); + if (phy[PORT_0].addr & 0x1) { + phy_blk[PORT_0] = &(phy[PORT_1]); + phy_blk[PORT_1] = &(phy[PORT_0]); + } else { + phy_blk[PORT_0] = &(phy[PORT_0]); + phy_blk[PORT_1] = &(phy[PORT_1]); + } + /* PART2 - Download firmware to both phys */ + for (port = PORT_MAX - 1; port >= PORT_0; port--) { + if (CHIP_IS_E1x(bp)) + port_of_path = port; + else + port_of_path = 0; + DP(NETIF_MSG_LINK, "Loading spirom for phy address 0x%x\n", + phy_blk[port]->addr); + if (bnx2x_8073_8727_external_rom_boot(bp, phy_blk[port], + port_of_path)) + return -EINVAL; + /* Disable PHY transmitter output */ + bnx2x_cl45_write(bp, phy_blk[port], + MDIO_PMA_DEVAD, + MDIO_PMA_REG_TX_DISABLE, 1); + + } + return 0; +} + +static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[], + u32 shmem2_base_path[], u8 phy_index, + u32 ext_phy_type, u32 chip_id) +{ + int rc = 0; + + switch (ext_phy_type) { + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073: + rc = bnx2x_8073_common_init_phy(bp, shmem_base_path, + shmem2_base_path, + phy_index, chip_id); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC: + rc = bnx2x_8727_common_init_phy(bp, shmem_base_path, + shmem2_base_path, + phy_index, chip_id); + break; + + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726: + /* + * GPIO1 affects both ports, so there's need to pull + * it for single port alone + */ + rc = bnx2x_8726_common_init_phy(bp, shmem_base_path, + shmem2_base_path, + phy_index, chip_id); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833: + /* + * GPIO3's are linked, and so both need to be toggled + * to obtain required 2us pulse. + */ + rc = bnx2x_84833_common_init_phy(bp, shmem_base_path, chip_id); + break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE: + rc = -EINVAL; + break; + default: + DP(NETIF_MSG_LINK, + "ext_phy 0x%x common init not required\n", + ext_phy_type); + break; + } + + if (rc != 0) + netdev_err(bp->dev, "Warning: PHY was not initialized," + " Port %d\n", + 0); + return rc; +} + +int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[], + u32 shmem2_base_path[], u32 chip_id) +{ + int rc = 0; + u32 phy_ver, val; + u8 phy_index = 0; + u32 ext_phy_type, ext_phy_config; + bnx2x_set_mdio_clk(bp, chip_id, PORT_0); + bnx2x_set_mdio_clk(bp, chip_id, PORT_1); + DP(NETIF_MSG_LINK, "Begin common phy init\n"); + if (CHIP_IS_E3(bp)) { + /* Enable EPIO */ + val = REG_RD(bp, MISC_REG_GEN_PURP_HWG); + REG_WR(bp, MISC_REG_GEN_PURP_HWG, val | 1); + } + /* Check if common init was already done */ + phy_ver = REG_RD(bp, shmem_base_path[0] + + offsetof(struct shmem_region, + port_mb[PORT_0].ext_phy_fw_version)); + if (phy_ver) { + DP(NETIF_MSG_LINK, "Not doing common init; phy ver is 0x%x\n", + phy_ver); + return 0; + } + + /* Read the ext_phy_type for arbitrary port(0) */ + for (phy_index = EXT_PHY1; phy_index < MAX_PHYS; + phy_index++) { + ext_phy_config = bnx2x_get_ext_phy_config(bp, + shmem_base_path[0], + phy_index, 0); + ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); + rc |= bnx2x_ext_phy_common_init(bp, shmem_base_path, + shmem2_base_path, + phy_index, ext_phy_type, + chip_id); + } + return rc; +} + +static void bnx2x_check_over_curr(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u32 cfg_pin; + u8 port = params->port; + u32 pin_val; + + cfg_pin = (REG_RD(bp, params->shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].e3_cmn_pin_cfg1)) & + PORT_HW_CFG_E3_OVER_CURRENT_MASK) >> + PORT_HW_CFG_E3_OVER_CURRENT_SHIFT; + + /* Ignore check if no external input PIN available */ + if (bnx2x_get_cfg_pin(bp, cfg_pin, &pin_val) != 0) + return; + + if (!pin_val) { + if ((vars->phy_flags & PHY_OVER_CURRENT_FLAG) == 0) { + netdev_err(bp->dev, "Error: Power fault on Port %d has" + " been detected and the power to " + "that SFP+ module has been removed" + " to prevent failure of the card." + " Please remove the SFP+ module and" + " restart the system to clear this" + " error.\n", + params->port); + vars->phy_flags |= PHY_OVER_CURRENT_FLAG; + } + } else + vars->phy_flags &= ~PHY_OVER_CURRENT_FLAG; +} + +static void bnx2x_analyze_link_error(struct link_params *params, + struct link_vars *vars, u32 lss_status) +{ + struct bnx2x *bp = params->bp; + /* Compare new value with previous value */ + u8 led_mode; + u32 half_open_conn = (vars->phy_flags & PHY_HALF_OPEN_CONN_FLAG) > 0; + + if ((lss_status ^ half_open_conn) == 0) + return; + + /* If values differ */ + DP(NETIF_MSG_LINK, "Link changed:%x %x->%x\n", vars->link_up, + half_open_conn, lss_status); + + /* + * a. Update shmem->link_status accordingly + * b. Update link_vars->link_up + */ + if (lss_status) { + DP(NETIF_MSG_LINK, "Remote Fault detected !!!\n"); + vars->link_status &= ~LINK_STATUS_LINK_UP; + vars->link_up = 0; + vars->phy_flags |= PHY_HALF_OPEN_CONN_FLAG; + /* + * Set LED mode to off since the PHY doesn't know about these + * errors + */ + led_mode = LED_MODE_OFF; + } else { + DP(NETIF_MSG_LINK, "Remote Fault cleared\n"); + vars->link_status |= LINK_STATUS_LINK_UP; + vars->link_up = 1; + vars->phy_flags &= ~PHY_HALF_OPEN_CONN_FLAG; + led_mode = LED_MODE_OPER; + } + /* Update the LED according to the link state */ + bnx2x_set_led(params, vars, led_mode, SPEED_10000); + + /* Update link status in the shared memory */ + bnx2x_update_mng(params, vars->link_status); + + /* C. Trigger General Attention */ + vars->periodic_flags |= PERIODIC_FLAGS_LINK_EVENT; + bnx2x_notify_link_changed(bp); +} + +/****************************************************************************** +* Description: +* This function checks for half opened connection change indication. +* When such change occurs, it calls the bnx2x_analyze_link_error +* to check if Remote Fault is set or cleared. Reception of remote fault +* status message in the MAC indicates that the peer's MAC has detected +* a fault, for example, due to break in the TX side of fiber. +* +******************************************************************************/ +static void bnx2x_check_half_open_conn(struct link_params *params, + struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u32 lss_status = 0; + u32 mac_base; + /* In case link status is physically up @ 10G do */ + if ((vars->phy_flags & PHY_PHYSICAL_LINK_FLAG) == 0) + return; + + if (CHIP_IS_E3(bp) && + (REG_RD(bp, MISC_REG_RESET_REG_2) & + (MISC_REGISTERS_RESET_REG_2_XMAC))) { + /* Check E3 XMAC */ + /* + * Note that link speed cannot be queried here, since it may be + * zero while link is down. In case UMAC is active, LSS will + * simply not be set + */ + mac_base = (params->port) ? GRCBASE_XMAC1 : GRCBASE_XMAC0; + + /* Clear stick bits (Requires rising edge) */ + REG_WR(bp, mac_base + XMAC_REG_CLEAR_RX_LSS_STATUS, 0); + REG_WR(bp, mac_base + XMAC_REG_CLEAR_RX_LSS_STATUS, + XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_LOCAL_FAULT_STATUS | + XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_REMOTE_FAULT_STATUS); + if (REG_RD(bp, mac_base + XMAC_REG_RX_LSS_STATUS)) + lss_status = 1; + + bnx2x_analyze_link_error(params, vars, lss_status); + } else if (REG_RD(bp, MISC_REG_RESET_REG_2) & + (MISC_REGISTERS_RESET_REG_2_RST_BMAC0 << params->port)) { + /* Check E1X / E2 BMAC */ + u32 lss_status_reg; + u32 wb_data[2]; + mac_base = params->port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM; + /* Read BIGMAC_REGISTER_RX_LSS_STATUS */ + if (CHIP_IS_E2(bp)) + lss_status_reg = BIGMAC2_REGISTER_RX_LSS_STAT; + else + lss_status_reg = BIGMAC_REGISTER_RX_LSS_STATUS; + + REG_RD_DMAE(bp, mac_base + lss_status_reg, wb_data, 2); + lss_status = (wb_data[0] > 0); + + bnx2x_analyze_link_error(params, vars, lss_status); + } +} + +void bnx2x_period_func(struct link_params *params, struct link_vars *vars) +{ + struct bnx2x *bp = params->bp; + u16 phy_idx; + if (!params) { + DP(NETIF_MSG_LINK, "Uninitialized params !\n"); + return; + } + + for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) { + if (params->phy[phy_idx].flags & FLAGS_TX_ERROR_CHECK) { + bnx2x_set_aer_mmd(params, ¶ms->phy[phy_idx]); + bnx2x_check_half_open_conn(params, vars); + break; + } + } + + if (CHIP_IS_E3(bp)) + bnx2x_check_over_curr(params, vars); +} + +u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, u32 shmem2_base) +{ + u8 phy_index; + struct bnx2x_phy phy; + for (phy_index = INT_PHY; phy_index < MAX_PHYS; + phy_index++) { + if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base, + 0, &phy) != 0) { + DP(NETIF_MSG_LINK, "populate phy failed\n"); + return 0; + } + + if (phy.flags & FLAGS_HW_LOCK_REQUIRED) + return 1; + } + return 0; +} + +u8 bnx2x_fan_failure_det_req(struct bnx2x *bp, + u32 shmem_base, + u32 shmem2_base, + u8 port) +{ + u8 phy_index, fan_failure_det_req = 0; + struct bnx2x_phy phy; + for (phy_index = EXT_PHY1; phy_index < MAX_PHYS; + phy_index++) { + if (bnx2x_populate_phy(bp, phy_index, shmem_base, shmem2_base, + port, &phy) + != 0) { + DP(NETIF_MSG_LINK, "populate phy failed\n"); + return 0; + } + fan_failure_det_req |= (phy.flags & + FLAGS_FAN_FAILURE_DET_REQ); + } + return fan_failure_det_req; +} + +void bnx2x_hw_reset_phy(struct link_params *params) +{ + u8 phy_index; + struct bnx2x *bp = params->bp; + bnx2x_update_mng(params, 0); + bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4, + (NIG_MASK_XGXS0_LINK_STATUS | + NIG_MASK_XGXS0_LINK10G | + NIG_MASK_SERDES0_LINK_STATUS | + NIG_MASK_MI_INT)); + + for (phy_index = INT_PHY; phy_index < MAX_PHYS; + phy_index++) { + if (params->phy[phy_index].hw_reset) { + params->phy[phy_index].hw_reset( + ¶ms->phy[phy_index], + params); + params->phy[phy_index] = phy_null; + } + } +} + +void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars, + u32 chip_id, u32 shmem_base, u32 shmem2_base, + u8 port) +{ + u8 gpio_num = 0xff, gpio_port = 0xff, phy_index; + u32 val; + u32 offset, aeu_mask, swap_val, swap_override, sync_offset; + if (CHIP_IS_E3(bp)) { + if (bnx2x_get_mod_abs_int_cfg(bp, chip_id, + shmem_base, + port, + &gpio_num, + &gpio_port) != 0) + return; + } else { + struct bnx2x_phy phy; + for (phy_index = EXT_PHY1; phy_index < MAX_PHYS; + phy_index++) { + if (bnx2x_populate_phy(bp, phy_index, shmem_base, + shmem2_base, port, &phy) + != 0) { + DP(NETIF_MSG_LINK, "populate phy failed\n"); + return; + } + if (phy.type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) { + gpio_num = MISC_REGISTERS_GPIO_3; + gpio_port = port; + break; + } + } + } + + if (gpio_num == 0xff) + return; + + /* Set GPIO3 to trigger SFP+ module insertion/removal */ + bnx2x_set_gpio(bp, gpio_num, MISC_REGISTERS_GPIO_INPUT_HI_Z, gpio_port); + + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + gpio_port ^= (swap_val && swap_override); + + vars->aeu_int_mask = AEU_INPUTS_ATTN_BITS_GPIO0_FUNCTION_0 << + (gpio_num + (gpio_port << 2)); + + sync_offset = shmem_base + + offsetof(struct shmem_region, + dev_info.port_hw_config[port].aeu_int_mask); + REG_WR(bp, sync_offset, vars->aeu_int_mask); + + DP(NETIF_MSG_LINK, "Setting MOD_ABS (GPIO%d_P%d) AEU to 0x%x\n", + gpio_num, gpio_port, vars->aeu_int_mask); + + if (port == 0) + offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0; + else + offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0; + + /* Open appropriate AEU for interrupts */ + aeu_mask = REG_RD(bp, offset); + aeu_mask |= vars->aeu_int_mask; + REG_WR(bp, offset, aeu_mask); + + /* Enable the GPIO to trigger interrupt */ + val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN); + val |= 1 << (gpio_num + (gpio_port << 2)); + REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val); +} diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h new file mode 100644 index 000000000000..c12db6da213e --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h @@ -0,0 +1,493 @@ +/* Copyright 2008-2011 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + * + * Written by Yaniv Rosner + * + */ + +#ifndef BNX2X_LINK_H +#define BNX2X_LINK_H + + + +/***********************************************************/ +/* Defines */ +/***********************************************************/ +#define DEFAULT_PHY_DEV_ADDR 3 +#define E2_DEFAULT_PHY_DEV_ADDR 5 + + + +#define BNX2X_FLOW_CTRL_AUTO PORT_FEATURE_FLOW_CONTROL_AUTO +#define BNX2X_FLOW_CTRL_TX PORT_FEATURE_FLOW_CONTROL_TX +#define BNX2X_FLOW_CTRL_RX PORT_FEATURE_FLOW_CONTROL_RX +#define BNX2X_FLOW_CTRL_BOTH PORT_FEATURE_FLOW_CONTROL_BOTH +#define BNX2X_FLOW_CTRL_NONE PORT_FEATURE_FLOW_CONTROL_NONE + +#define NET_SERDES_IF_XFI 1 +#define NET_SERDES_IF_SFI 2 +#define NET_SERDES_IF_KR 3 +#define NET_SERDES_IF_DXGXS 4 + +#define SPEED_AUTO_NEG 0 +#define SPEED_20000 20000 + +#define SFP_EEPROM_VENDOR_NAME_ADDR 0x14 +#define SFP_EEPROM_VENDOR_NAME_SIZE 16 +#define SFP_EEPROM_VENDOR_OUI_ADDR 0x25 +#define SFP_EEPROM_VENDOR_OUI_SIZE 3 +#define SFP_EEPROM_PART_NO_ADDR 0x28 +#define SFP_EEPROM_PART_NO_SIZE 16 +#define SFP_EEPROM_REVISION_ADDR 0x38 +#define SFP_EEPROM_REVISION_SIZE 4 +#define SFP_EEPROM_SERIAL_ADDR 0x44 +#define SFP_EEPROM_SERIAL_SIZE 16 +#define SFP_EEPROM_DATE_ADDR 0x54 /* ASCII YYMMDD */ +#define SFP_EEPROM_DATE_SIZE 6 +#define PWR_FLT_ERR_MSG_LEN 250 + +#define XGXS_EXT_PHY_TYPE(ext_phy_config) \ + ((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK) +#define XGXS_EXT_PHY_ADDR(ext_phy_config) \ + (((ext_phy_config) & PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >> \ + PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT) +#define SERDES_EXT_PHY_TYPE(ext_phy_config) \ + ((ext_phy_config) & PORT_HW_CFG_SERDES_EXT_PHY_TYPE_MASK) + +/* Single Media Direct board is the plain 577xx board with CX4/RJ45 jacks */ +#define SINGLE_MEDIA_DIRECT(params) (params->num_phys == 1) +/* Single Media board contains single external phy */ +#define SINGLE_MEDIA(params) (params->num_phys == 2) +/* Dual Media board contains two external phy with different media */ +#define DUAL_MEDIA(params) (params->num_phys == 3) + +#define FW_PARAM_PHY_ADDR_MASK 0x000000FF +#define FW_PARAM_PHY_TYPE_MASK 0x0000FF00 +#define FW_PARAM_MDIO_CTRL_MASK 0xFFFF0000 +#define FW_PARAM_MDIO_CTRL_OFFSET 16 +#define FW_PARAM_PHY_ADDR(fw_param) (fw_param & \ + FW_PARAM_PHY_ADDR_MASK) +#define FW_PARAM_PHY_TYPE(fw_param) (fw_param & \ + FW_PARAM_PHY_TYPE_MASK) +#define FW_PARAM_MDIO_CTRL(fw_param) ((fw_param & \ + FW_PARAM_MDIO_CTRL_MASK) >> \ + FW_PARAM_MDIO_CTRL_OFFSET) +#define FW_PARAM_SET(phy_addr, phy_type, mdio_access) \ + (phy_addr | phy_type | mdio_access << FW_PARAM_MDIO_CTRL_OFFSET) + + +#define PFC_BRB_FULL_LB_XOFF_THRESHOLD 170 +#define PFC_BRB_FULL_LB_XON_THRESHOLD 250 + +#define MAXVAL(a, b) (((a) > (b)) ? (a) : (b)) +/***********************************************************/ +/* Structs */ +/***********************************************************/ +#define INT_PHY 0 +#define EXT_PHY1 1 +#define EXT_PHY2 2 +#define MAX_PHYS 3 + +/* Same configuration is shared between the XGXS and the first external phy */ +#define LINK_CONFIG_SIZE (MAX_PHYS - 1) +#define LINK_CONFIG_IDX(_phy_idx) ((_phy_idx == INT_PHY) ? \ + 0 : (_phy_idx - 1)) +/***********************************************************/ +/* bnx2x_phy struct */ +/* Defines the required arguments and function per phy */ +/***********************************************************/ +struct link_vars; +struct link_params; +struct bnx2x_phy; + +typedef u8 (*config_init_t)(struct bnx2x_phy *phy, struct link_params *params, + struct link_vars *vars); +typedef u8 (*read_status_t)(struct bnx2x_phy *phy, struct link_params *params, + struct link_vars *vars); +typedef void (*link_reset_t)(struct bnx2x_phy *phy, + struct link_params *params); +typedef void (*config_loopback_t)(struct bnx2x_phy *phy, + struct link_params *params); +typedef u8 (*format_fw_ver_t)(u32 raw, u8 *str, u16 *len); +typedef void (*hw_reset_t)(struct bnx2x_phy *phy, struct link_params *params); +typedef void (*set_link_led_t)(struct bnx2x_phy *phy, + struct link_params *params, u8 mode); +typedef void (*phy_specific_func_t)(struct bnx2x_phy *phy, + struct link_params *params, u32 action); + +struct bnx2x_phy { + u32 type; + + /* Loaded during init */ + u8 addr; + u8 def_md_devad; + u16 flags; + /* Require HW lock */ +#define FLAGS_HW_LOCK_REQUIRED (1<<0) + /* No Over-Current detection */ +#define FLAGS_NOC (1<<1) + /* Fan failure detection required */ +#define FLAGS_FAN_FAILURE_DET_REQ (1<<2) + /* Initialize first the XGXS and only then the phy itself */ +#define FLAGS_INIT_XGXS_FIRST (1<<3) +#define FLAGS_WC_DUAL_MODE (1<<4) +#define FLAGS_4_PORT_MODE (1<<5) +#define FLAGS_REARM_LATCH_SIGNAL (1<<6) +#define FLAGS_SFP_NOT_APPROVED (1<<7) +#define FLAGS_MDC_MDIO_WA (1<<8) +#define FLAGS_DUMMY_READ (1<<9) +#define FLAGS_MDC_MDIO_WA_B0 (1<<10) +#define FLAGS_TX_ERROR_CHECK (1<<12) + + /* preemphasis values for the rx side */ + u16 rx_preemphasis[4]; + + /* preemphasis values for the tx side */ + u16 tx_preemphasis[4]; + + /* EMAC address for access MDIO */ + u32 mdio_ctrl; + + u32 supported; + + u32 media_type; +#define ETH_PHY_UNSPECIFIED 0x0 +#define ETH_PHY_SFP_FIBER 0x1 +#define ETH_PHY_XFP_FIBER 0x2 +#define ETH_PHY_DA_TWINAX 0x3 +#define ETH_PHY_BASE_T 0x4 +#define ETH_PHY_KR 0xf0 +#define ETH_PHY_CX4 0xf1 +#define ETH_PHY_NOT_PRESENT 0xff + + /* The address in which version is located*/ + u32 ver_addr; + + u16 req_flow_ctrl; + + u16 req_line_speed; + + u32 speed_cap_mask; + + u16 req_duplex; + u16 rsrv; + /* Called per phy/port init, and it configures LASI, speed, autoneg, + duplex, flow control negotiation, etc. */ + config_init_t config_init; + + /* Called due to interrupt. It determines the link, speed */ + read_status_t read_status; + + /* Called when driver is unloading. Should reset the phy */ + link_reset_t link_reset; + + /* Set the loopback configuration for the phy */ + config_loopback_t config_loopback; + + /* Format the given raw number into str up to len */ + format_fw_ver_t format_fw_ver; + + /* Reset the phy (both ports) */ + hw_reset_t hw_reset; + + /* Set link led mode (on/off/oper)*/ + set_link_led_t set_link_led; + + /* PHY Specific tasks */ + phy_specific_func_t phy_specific_func; +#define DISABLE_TX 1 +#define ENABLE_TX 2 +}; + +/* Inputs parameters to the CLC */ +struct link_params { + + u8 port; + + /* Default / User Configuration */ + u8 loopback_mode; +#define LOOPBACK_NONE 0 +#define LOOPBACK_EMAC 1 +#define LOOPBACK_BMAC 2 +#define LOOPBACK_XGXS 3 +#define LOOPBACK_EXT_PHY 4 +#define LOOPBACK_EXT 5 +#define LOOPBACK_UMAC 6 +#define LOOPBACK_XMAC 7 + + /* Device parameters */ + u8 mac_addr[6]; + + u16 req_duplex[LINK_CONFIG_SIZE]; + u16 req_flow_ctrl[LINK_CONFIG_SIZE]; + + u16 req_line_speed[LINK_CONFIG_SIZE]; /* Also determine AutoNeg */ + + /* shmem parameters */ + u32 shmem_base; + u32 shmem2_base; + u32 speed_cap_mask[LINK_CONFIG_SIZE]; + u32 switch_cfg; +#define SWITCH_CFG_1G PORT_FEATURE_CON_SWITCH_1G_SWITCH +#define SWITCH_CFG_10G PORT_FEATURE_CON_SWITCH_10G_SWITCH +#define SWITCH_CFG_AUTO_DETECT PORT_FEATURE_CON_SWITCH_AUTO_DETECT + + u32 lane_config; + + /* Phy register parameter */ + u32 chip_id; + + /* features */ + u32 feature_config_flags; +#define FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED (1<<0) +#define FEATURE_CONFIG_PFC_ENABLED (1<<1) +#define FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY (1<<2) +#define FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY (1<<3) +#define FEATURE_CONFIG_AUTOGREEEN_ENABLED (1<<9) +#define FEATURE_CONFIG_BC_SUPPORTS_SFP_TX_DISABLED (1<<10) + /* Will be populated during common init */ + struct bnx2x_phy phy[MAX_PHYS]; + + /* Will be populated during common init */ + u8 num_phys; + + u8 rsrv; + u16 hw_led_mode; /* part of the hw_config read from the shmem */ + u32 multi_phy_config; + + /* Device pointer passed to all callback functions */ + struct bnx2x *bp; + u16 req_fc_auto_adv; /* Should be set to TX / BOTH when + req_flow_ctrl is set to AUTO */ +}; + +/* Output parameters */ +struct link_vars { + u8 phy_flags; +#define PHY_XGXS_FLAG (1<<0) +#define PHY_SGMII_FLAG (1<<1) +#define PHY_PHYSICAL_LINK_FLAG (1<<2) +#define PHY_HALF_OPEN_CONN_FLAG (1<<3) +#define PHY_OVER_CURRENT_FLAG (1<<4) + + u8 mac_type; +#define MAC_TYPE_NONE 0 +#define MAC_TYPE_EMAC 1 +#define MAC_TYPE_BMAC 2 +#define MAC_TYPE_UMAC 3 +#define MAC_TYPE_XMAC 4 + + u8 phy_link_up; /* internal phy link indication */ + u8 link_up; + + u16 line_speed; + u16 duplex; + + u16 flow_ctrl; + u16 ieee_fc; + + /* The same definitions as the shmem parameter */ + u32 link_status; + u8 fault_detected; + u8 rsrv1; + u16 periodic_flags; +#define PERIODIC_FLAGS_LINK_EVENT 0x0001 + + u32 aeu_int_mask; +}; + +/***********************************************************/ +/* Functions */ +/***********************************************************/ +int bnx2x_phy_init(struct link_params *params, struct link_vars *vars); + +/* Reset the link. Should be called when driver or interface goes down + Before calling phy firmware upgrade, the reset_ext_phy should be set + to 0 */ +int bnx2x_link_reset(struct link_params *params, struct link_vars *vars, + u8 reset_ext_phy); + +/* bnx2x_link_update should be called upon link interrupt */ +int bnx2x_link_update(struct link_params *params, struct link_vars *vars); + +/* use the following phy functions to read/write from external_phy + In order to use it to read/write internal phy registers, use + DEFAULT_PHY_DEV_ADDR as devad, and (_bank + (_addr & 0xf)) as + the register */ +int bnx2x_phy_read(struct link_params *params, u8 phy_addr, + u8 devad, u16 reg, u16 *ret_val); + +int bnx2x_phy_write(struct link_params *params, u8 phy_addr, + u8 devad, u16 reg, u16 val); + +/* Reads the link_status from the shmem, + and update the link vars accordingly */ +void bnx2x_link_status_update(struct link_params *input, + struct link_vars *output); +/* returns string representing the fw_version of the external phy */ +int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded, + u8 *version, u16 len); + +/* Set/Unset the led + Basically, the CLC takes care of the led for the link, but in case one needs + to set/unset the led unnaturally, set the "mode" to LED_MODE_OPER to + blink the led, and LED_MODE_OFF to set the led off.*/ +int bnx2x_set_led(struct link_params *params, + struct link_vars *vars, u8 mode, u32 speed); +#define LED_MODE_OFF 0 +#define LED_MODE_ON 1 +#define LED_MODE_OPER 2 +#define LED_MODE_FRONT_PANEL_OFF 3 + +/* bnx2x_handle_module_detect_int should be called upon module detection + interrupt */ +void bnx2x_handle_module_detect_int(struct link_params *params); + +/* Get the actual link status. In case it returns 0, link is up, + otherwise link is down*/ +int bnx2x_test_link(struct link_params *params, struct link_vars *vars, + u8 is_serdes); + +/* One-time initialization for external phy after power up */ +int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[], + u32 shmem2_base_path[], u32 chip_id); + +/* Reset the external PHY using GPIO */ +void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port); + +/* Reset the external of SFX7101 */ +void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy); + +/* Read "byte_cnt" bytes from address "addr" from the SFP+ EEPROM */ +int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy, + struct link_params *params, u16 addr, + u8 byte_cnt, u8 *o_buf); + +void bnx2x_hw_reset_phy(struct link_params *params); + +/* Checks if HW lock is required for this phy/board type */ +u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base, + u32 shmem2_base); + +/* Check swap bit and adjust PHY order */ +u32 bnx2x_phy_selection(struct link_params *params); + +/* Probe the phys on board, and populate them in "params" */ +int bnx2x_phy_probe(struct link_params *params); + +/* Checks if fan failure detection is required on one of the phys on board */ +u8 bnx2x_fan_failure_det_req(struct bnx2x *bp, u32 shmem_base, + u32 shmem2_base, u8 port); + + + +/* DCBX structs */ + +/* Number of maximum COS per chip */ +#define DCBX_E2E3_MAX_NUM_COS (2) +#define DCBX_E3B0_MAX_NUM_COS_PORT0 (6) +#define DCBX_E3B0_MAX_NUM_COS_PORT1 (3) +#define DCBX_E3B0_MAX_NUM_COS ( \ + MAXVAL(DCBX_E3B0_MAX_NUM_COS_PORT0, \ + DCBX_E3B0_MAX_NUM_COS_PORT1)) + +#define DCBX_MAX_NUM_COS ( \ + MAXVAL(DCBX_E3B0_MAX_NUM_COS, \ + DCBX_E2E3_MAX_NUM_COS)) + +/* PFC port configuration params */ +struct bnx2x_nig_brb_pfc_port_params { + /* NIG */ + u32 pause_enable; + u32 llfc_out_en; + u32 llfc_enable; + u32 pkt_priority_to_cos; + u8 num_of_rx_cos_priority_mask; + u32 rx_cos_priority_mask[DCBX_MAX_NUM_COS]; + u32 llfc_high_priority_classes; + u32 llfc_low_priority_classes; + /* BRB */ + u32 cos0_pauseable; + u32 cos1_pauseable; +}; + + +/* ETS port configuration params */ +struct bnx2x_ets_bw_params { + u8 bw; +}; + +struct bnx2x_ets_sp_params { + /** + * valid values are 0 - 5. 0 is highest strict priority. + * There can't be two COS's with the same pri. + */ + u8 pri; +}; + +enum bnx2x_cos_state { + bnx2x_cos_state_strict = 0, + bnx2x_cos_state_bw = 1, +}; + +struct bnx2x_ets_cos_params { + enum bnx2x_cos_state state ; + union { + struct bnx2x_ets_bw_params bw_params; + struct bnx2x_ets_sp_params sp_params; + } params; +}; + +struct bnx2x_ets_params { + u8 num_of_cos; /* Number of valid COS entries*/ + struct bnx2x_ets_cos_params cos[DCBX_MAX_NUM_COS]; +}; + +/** + * Used to update the PFC attributes in EMAC, BMAC, NIG and BRB + * when link is already up + */ +int bnx2x_update_pfc(struct link_params *params, + struct link_vars *vars, + struct bnx2x_nig_brb_pfc_port_params *pfc_params); + + +/* Used to configure the ETS to disable */ +int bnx2x_ets_disabled(struct link_params *params, + struct link_vars *vars); + +/* Used to configure the ETS to BW limited */ +void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw, + const u32 cos1_bw); + +/* Used to configure the ETS to strict */ +int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos); + + +/* Configure the COS to ETS according to BW and SP settings.*/ +int bnx2x_ets_e3b0_config(const struct link_params *params, + const struct link_vars *vars, + const struct bnx2x_ets_params *ets_params); +/* Read pfc statistic*/ +void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars, + u32 pfc_frames_sent[2], + u32 pfc_frames_received[2]); +void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars, + u32 chip_id, u32 shmem_base, u32 shmem2_base, + u8 port); + +int bnx2x_sfp_module_detection(struct bnx2x_phy *phy, + struct link_params *params); + +void bnx2x_period_func(struct link_params *params, struct link_vars *vars); + +#endif /* BNX2X_LINK_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c new file mode 100644 index 000000000000..150709111548 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -0,0 +1,11531 @@ +/* bnx2x_main.c: Broadcom Everest network driver. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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: Eilon Greenstein + * 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 + * + */ + +#include +#include +#include +#include /* for dev_info() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bnx2x.h" +#include "bnx2x_init.h" +#include "bnx2x_init_ops.h" +#include "bnx2x_cmn.h" +#include "bnx2x_dcb.h" +#include "bnx2x_sp.h" + +#include +#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_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" + +/* Time in jiffies before concluding the transmitter is hung */ +#define TX_TIMEOUT (5*HZ) + +static char version[] __devinitdata = + "Broadcom NetXtreme II 5771x/578xx 10/20-Gigabit Ethernet Driver " + DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; + +MODULE_AUTHOR("Eliezer Tamir"); +MODULE_DESCRIPTION("Broadcom NetXtreme II " + "BCM57710/57711/57711E/" + "57712/57712_MF/57800/57800_MF/57810/57810_MF/" + "57840/57840_MF Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); +MODULE_FIRMWARE(FW_FILE_NAME_E1); +MODULE_FIRMWARE(FW_FILE_NAME_E1H); +MODULE_FIRMWARE(FW_FILE_NAME_E2); + +static int multi_mode = 1; +module_param(multi_mode, int, 0); +MODULE_PARM_DESC(multi_mode, " Multi queue mode " + "(0 Disable; 1 Enable (default))"); + +int num_queues; +module_param(num_queues, int, 0); +MODULE_PARM_DESC(num_queues, " Number of queues for multi_mode=1" + " (default is as a number of CPUs)"); + +static int disable_tpa; +module_param(disable_tpa, int, 0); +MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature"); + +#define INT_MODE_INTx 1 +#define INT_MODE_MSI 2 +static int int_mode; +module_param(int_mode, int, 0); +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, 0); +MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring"); + +static int poll; +module_param(poll, int, 0); +MODULE_PARM_DESC(poll, " Use polling (for debug)"); + +static int mrrs = -1; +module_param(mrrs, int, 0); +MODULE_PARM_DESC(mrrs, " Force Max Read Req Size (0..3) (for debug)"); + +static int debug; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, " Default debug msglevel"); + + + +struct workqueue_struct *bnx2x_wq; + +enum bnx2x_board_type { + BCM57710 = 0, + BCM57711, + BCM57711E, + BCM57712, + BCM57712_MF, + BCM57800, + BCM57800_MF, + BCM57810, + BCM57810_MF, + BCM57840, + BCM57840_MF +}; + +/* indexed by board_type, above */ +static struct { + char *name; +} board_info[] __devinitdata = { + { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" }, + { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" }, + { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" }, + { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" }, + { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" }, + { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" }, + { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" }, + { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" }, + { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" }, + { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" }, + { "Broadcom NetXtreme II BCM57840 10/20 Gigabit " + "Ethernet Multi 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_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_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 +#define PCI_DEVICE_ID_NX2_57840 CHIP_NUM_57840 +#endif +#ifndef PCI_DEVICE_ID_NX2_57840_MF +#define PCI_DEVICE_ID_NX2_57840_MF CHIP_NUM_57840_MF +#endif +static DEFINE_PCI_DEVICE_TABLE(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_57800), BCM57800 }, + { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57800_MF), BCM57800_MF }, + { 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), BCM57840 }, + { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MF), BCM57840_MF }, + { 0 } +}; + +MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl); + +/**************************************************************************** +* General service functions +****************************************************************************/ + +static inline 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 inline 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 inline 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 inline 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 inline 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 inline 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; + + 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" + DP_LEVEL "src_addr [%x:%08x] len [%d * 4] " + "dst_addr [none]\n" + DP_LEVEL "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" + DP_LEVEL "src_addr [%08x] len [%d * 4] " + "dst_addr [none]\n" + DP_LEVEL "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; + } + +} + +/* 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)); + + DP(BNX2X_MSG_OFF, "DMAE cmd[%d].%d (0x%08x) : 0x%08x\n", + idx, i, 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_E1HVN(bp) << DMAE_CMD_E1HVN_SHIFT) | + (BP_E1HVN(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; +} + +static 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 wailt for completion */ +static int bnx2x_issue_dmae_with_comp(struct bnx2x *bp, + struct dmae_command *dmae) +{ + u32 *wb_comp = bnx2x_sp(bp, wb_comp); + int cnt = CHIP_REV_IS_SLOW(bp) ? (400000) : 4000; + int rc = 0; + + DP(BNX2X_MSG_OFF, "data before [0x%08x 0x%08x 0x%08x 0x%08x]\n", + bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], + bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); + + /* + * 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 */ + *wb_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 ((*wb_comp & ~DMAE_PCI_ERR_FLAG) != DMAE_COMP_VAL) { + DP(BNX2X_MSG_OFF, "wb_comp 0x%08x\n", *wb_comp); + + if (!cnt) { + BNX2X_ERR("DMAE timeout!\n"); + rc = DMAE_TIMEOUT; + goto unlock; + } + cnt--; + udelay(50); + } + if (*wb_comp & DMAE_PCI_ERR_FLAG) { + BNX2X_ERR("DMAE PCI error!\n"); + rc = DMAE_PCI_ERROR; + } + + DP(BNX2X_MSG_OFF, "data after [0x%08x 0x%08x 0x%08x 0x%08x]\n", + bp->slowpath->wb_data[0], bp->slowpath->wb_data[1], + bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]); + +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) +{ + struct dmae_command dmae; + + if (!bp->dmae_ready) { + u32 *data = bnx2x_sp(bp, wb_data[0]); + + DP(BNX2X_MSG_OFF, "DMAE is not ready (dst_addr %08x len32 %d)" + " using indirect\n", dst_addr, len32); + bnx2x_init_ind_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; + + bnx2x_dp_dmae(bp, &dmae, BNX2X_MSG_OFF); + + /* issue the command and wait for completion */ + bnx2x_issue_dmae_with_comp(bp, &dmae); +} + +void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32) +{ + struct dmae_command dmae; + + if (!bp->dmae_ready) { + u32 *data = bnx2x_sp(bp, wb_data[0]); + int i; + + DP(BNX2X_MSG_OFF, "DMAE is not ready (src_addr %08x len32 %d)" + " using indirect\n", src_addr, len32); + for (i = 0; i < len32; i++) + data[i] = bnx2x_reg_rd_ind(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; + + bnx2x_dp_dmae(bp, &dmae, BNX2X_MSG_OFF); + + /* issue the command and wait for completion */ + bnx2x_issue_dmae_with_comp(bp, &dmae); +} + +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); +} + +/* used only for slowpath so not inlined */ +static void bnx2x_wb_wr(struct bnx2x *bp, int reg, u32 val_hi, u32 val_lo) +{ + u32 wb_write[2]; + + wb_write[0] = val_hi; + wb_write[1] = val_lo; + REG_WR_DMAE(bp, reg, wb_write, 2); +} + +#ifdef USE_WB_RD +static u64 bnx2x_wb_rd(struct bnx2x *bp, int reg) +{ + u32 wb_data[2]; + + REG_RD_DMAE(bp, reg, wb_data, 2); + + return HILO_U64(wb_data[0], wb_data[1]); +} +#endif + +static int bnx2x_mc_assert(struct bnx2x *bp) +{ + char last_idx; + int i, rc = 0; + u32 row0, row1, row2, row3; + + /* XSTORM */ + last_idx = REG_RD8(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("XSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_XSTRORM_INTMEM + + XSTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("XSTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + + /* TSTORM */ + last_idx = REG_RD8(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("TSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_TSTRORM_INTMEM + + TSTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("TSTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + + /* CSTORM */ + last_idx = REG_RD8(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("CSTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("CSTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + + /* USTORM */ + last_idx = REG_RD8(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_INDEX_OFFSET); + if (last_idx) + BNX2X_ERR("USTORM_ASSERT_LIST_INDEX 0x%x\n", last_idx); + + /* print the asserts */ + for (i = 0; i < STROM_ASSERT_ARRAY_SIZE; i++) { + + row0 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i)); + row1 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i) + 4); + row2 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i) + 8); + row3 = REG_RD(bp, BAR_USTRORM_INTMEM + + USTORM_ASSERT_LIST_OFFSET(i) + 12); + + if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) { + BNX2X_ERR("USTORM_ASSERT_INDEX 0x%x = 0x%08x" + " 0x%08x 0x%08x 0x%08x\n", + i, row3, row2, row1, row0); + rc++; + } else { + break; + } + } + + return rc; +} + +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)); + + val = REG_RD(bp, MCP_REG_MCPR_CPU_PROGRAM_COUNTER); + if (val == REG_RD(bp, MCP_REG_MCPR_CPU_PROGRAM_COUNTER)) + printk("%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); + addr = trace_shmem_base - 0x0800 + 4; + mark = REG_RD(bp, addr); + mark = (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH) + + ((mark + 0x3) & ~0x3) - 0x08000000; + printk("%s" "begin fw dump (mark 0x%x)\n", lvl, mark); + + printk("%s", lvl); + 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); + } + 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 inline void bnx2x_fw_dump(struct bnx2x *bp) +{ + bnx2x_fw_dump_lvl(bp, KERN_ERR); +} + +void bnx2x_panic_dump(struct bnx2x *bp) +{ + 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 + + bp->stats_state = STATS_STATE_DISABLED; + DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n"); + + BNX2X_ERR("begin crash dump -----------------\n"); + + /* Indices */ + /* Common */ + 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", + bp->def_status_blk->atten_status_block.attn_bits, + bp->def_status_blk->atten_status_block.attn_bits_ack, + bp->def_status_blk->atten_status_block.status_block_id, + bp->def_status_blk->atten_status_block.attn_bits_index); + BNX2X_ERR(" def ("); + for (i = 0; i < HC_SP_SB_MAX_INDICES; i++) + pr_cont("0x%x%s", + bp->def_status_blk->sp_sb.index_values[i], + (i == HC_SP_SB_MAX_INDICES - 1) ? ") " : " "); + + for (i = 0; i < sizeof(struct hc_sp_status_block_data)/sizeof(u32); i++) + *((u32 *)&sp_sb_data + i) = REG_RD(bp, BAR_CSTRORM_INTMEM + + CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func) + + 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; + + /* 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) + { + txdata = fp->txdata[cos]; + 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 */ + +#ifdef BCM_CNIC + if (IS_FCOE_FP(fp)) + continue; +#endif + 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) ? ")" : " "); + /* 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); + } + + /* Indecies 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 + /* Rings */ + /* Rx */ + for_each_rx_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + 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->skb); + } + + 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_tx_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + for_each_cos_in_tx_queue(fp, cos) { + struct bnx2x_fp_txdata *txdata = &fp->txdata[cos]; + + 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 + bnx2x_fw_dump(bp); + 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 miliseconds */ +#define FLR_WAIT_INTERAVAL 50 /* usec */ +#define FLR_POLL_CNT (FLR_WAIT_USEC/FLR_WAIT_INTERAVAL) /* 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_INTERAVAL); + 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_INTERAVAL, 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_INTERAVAL); + 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_INTERAVAL, regs->pN); +} + +static inline 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_INTERAVAL); + + return val; +} + +static inline 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; +} + +static 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; +} + +static 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) + + +static inline int bnx2x_send_final_clnup(struct bnx2x *bp, u8 clnup_func, + u32 poll_cnt) +{ + struct sdm_op_gen op_gen = {0}; + + u32 comp_addr = BAR_CSTRORM_INTMEM + + CSTORM_FINAL_CLEANUP_COMPLETE_OFFSET(clnup_func); + int ret = 0; + + if (REG_RD(bp, comp_addr)) { + BNX2X_ERR("Cleanup complete is not 0\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, "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"); + ret = 1; + } + /* Zero completion for nxt FLR */ + REG_WR(bp, comp_addr, 0); + + return ret; +} + +static inline u8 bnx2x_is_pcie_pending(struct pci_dev *dev) +{ + int pos; + u16 status; + + pos = pci_pcie_cap(dev); + if (!pos) + return false; + + pci_read_config_word(dev, pos + 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 dommand 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 */ + 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); + int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; + int msi = (bp->flags & USING_MSI_FLAG) ? 1 : 0; + + 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); + } 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_INTR, "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_INTR, "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 + */ + mmiowb(); + barrier(); + + if (!CHIP_IS_E1(bp)) { + /* init leading/trailing edge */ + if (IS_MF(bp)) { + val = (0xee0f | (1 << (BP_E1HVN(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); + } + + /* Make sure that interrupts are indeed enabled from here on */ + mmiowb(); +} + +static void bnx2x_igu_int_enable(struct bnx2x *bp) +{ + u32 val; + int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; + int msi = (bp->flags & USING_MSI_FLAG) ? 1 : 0; + + 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_FUNC_EN | + IGU_PF_CONF_MSI_MSIX_EN | + IGU_PF_CONF_ATTN_BIT_EN); + } else if (msi) { + val &= ~IGU_PF_CONF_INT_LINE_EN; + val |= (IGU_PF_CONF_FUNC_EN | + 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_FUNC_EN | + IGU_PF_CONF_INT_LINE_EN | + IGU_PF_CONF_ATTN_BIT_EN | + IGU_PF_CONF_SINGLE_ISR_EN); + } + + DP(NETIF_MSG_INTR, "write 0x%x to IGU mode %s\n", + val, (msix ? "MSI-X" : (msi ? "MSI" : "INTx"))); + + REG_WR(bp, IGU_REG_PF_CONFIGURATION, val); + + barrier(); + + /* init leading/trailing edge */ + if (IS_MF(bp)) { + val = (0xee0f | (1 << (BP_E1HVN(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); + + /* Make sure that interrupts are indeed enabled from here on */ + mmiowb(); +} + +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); +} + +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 capablility + * It's forbitten 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_INTR, "write %x to HC %d (addr 0x%x)\n", + val, port, addr); + + /* flush all outstanding writes */ + mmiowb(); + + 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_INTR, "write %x to IGU\n", val); + + /* flush all outstanding writes */ + mmiowb(); + + 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"); +} + +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_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; +#ifdef BCM_CNIC + offset++; +#endif + 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, "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, + "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, "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 only 2 engines is supported. + */ +static inline 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 aquire a leader lock. + * + * @bp: driver handle + * + * Tries to aquire a leader lock for cuurent engine. + */ +static inline bool bnx2x_trylock_leader_lock(struct bnx2x *bp) +{ + return bnx2x_trylock_hw_lock(bp, bnx2x_get_leader_lock_resource(bp)); +} + +#ifdef BCM_CNIC +static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid, u8 err); +#endif + +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 = &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); + + 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(NETIF_MSG_IFUP, "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] teminate 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; + + 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_inc(); + atomic_inc(&bp->cq_spq_left); + /* push the change in bp->spq_left and towards the memory */ + smp_mb__after_atomic_inc(); + + DP(BNX2X_MSG_SP, "bp->cq_spq_left %x\n", atomic_read(&bp->cq_spq_left)); + + return; +} + +void bnx2x_update_rx_prod(struct bnx2x *bp, struct bnx2x_fastpath *fp, + u16 bd_prod, u16 rx_comp_prod, u16 rx_sge_prod) +{ + u32 start = BAR_USTRORM_INTMEM + fp->ustorm_rx_prods_offset; + + bnx2x_update_rx_prod_gen(bp, fp, bd_prod, rx_comp_prod, rx_sge_prod, + start); +} + +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_PRESENT); + if (status & mask) { + /* Handle Rx or Tx according to SB id */ + prefetch(fp->rx_cons_sb); + for_each_cos_in_tx_queue(fp, cos) + prefetch(fp->txdata[cos].tx_cons_sb); + prefetch(&fp->sb_running_index[SM_RX_ID]); + napi_schedule(&bnx2x_fp(bp, fp->index, napi)); + status &= ~mask; + } + } + +#ifdef BCM_CNIC + mask = 0x2; + if (status & (mask | 0x1)) { + struct cnic_ops *c_ops = NULL; + + if (likely(bp->state == BNX2X_STATE_OPEN)) { + rcu_read_lock(); + c_ops = rcu_dereference(bp->cnic_ops); + if (c_ops) + c_ops->cnic_handler(bp->cnic_data, NULL); + rcu_read_unlock(); + } + + status &= ~mask; + } +#endif + + if (unlikely(status & 0x1)) { + queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); + + 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) { + DP(NETIF_MSG_HW, + "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) { + DP(NETIF_MSG_HW, "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; + + msleep(5); + } + DP(NETIF_MSG_HW, "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; + + DP(NETIF_MSG_HW, "Releasing 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, + "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)) { + DP(NETIF_MSG_HW, "lock_status 0x%x resource_bit 0x%x\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; + + DP(NETIF_MSG_LINK, "pin %d value 0x%x\n", gpio_num, value); + + 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_num, u32 mode) +{ + u32 spio_mask = (1 << spio_num); + u32 spio_reg; + + if ((spio_num < MISC_REGISTERS_SPIO_4) || + (spio_num > MISC_REGISTERS_SPIO_7)) { + BNX2X_ERR("Invalid SPIO %d\n", spio_num); + 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_REGISTERS_SPIO_FLOAT); + + switch (mode) { + case MISC_REGISTERS_SPIO_OUTPUT_LOW: + DP(NETIF_MSG_LINK, "Set SPIO %d -> output low\n", spio_num); + /* clear FLOAT and set CLR */ + spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS); + spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_CLR_POS); + break; + + case MISC_REGISTERS_SPIO_OUTPUT_HIGH: + DP(NETIF_MSG_LINK, "Set SPIO %d -> output high\n", spio_num); + /* clear FLOAT and set SET */ + spio_reg &= ~(spio_mask << MISC_REGISTERS_SPIO_FLOAT_POS); + spio_reg |= (spio_mask << MISC_REGISTERS_SPIO_SET_POS); + break; + + case MISC_REGISTERS_SPIO_INPUT_HI_Z: + DP(NETIF_MSG_LINK, "Set SPIO %d -> input\n", spio_num); + /* set FLOAT */ + spio_reg |= (spio_mask << MISC_REGISTERS_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); + switch (bp->link_vars.ieee_fc & + MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK) { + case MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE: + bp->port.advertising[cfg_idx] &= ~(ADVERTISED_Asym_Pause | + ADVERTISED_Pause); + break; + + 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: + bp->port.advertising[cfg_idx] &= ~(ADVERTISED_Asym_Pause | + ADVERTISED_Pause); + break; + } +} + +u8 bnx2x_initial_phy_init(struct bnx2x *bp, int load_mode) +{ + if (!BP_NOMCP(bp)) { + u8 rc; + int cfx_idx = bnx2x_get_link_cfg_idx(bp); + u16 req_line_speed = bp->link_params.req_line_speed[cfx_idx]; + /* + * 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 + bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH; + + bnx2x_acquire_phy_lock(bp); + + if (load_mode == LOAD_DIAG) { + struct link_params *lp = &bp->link_params; + lp->loopback_mode = LOOPBACK_XGXS; + /* do PHY loopback at 10G speed, if possible */ + if (lp->req_line_speed[cfx_idx] < SPEED_10000) { + if (lp->speed_cap_mask[cfx_idx] & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G) + lp->req_line_speed[cfx_idx] = + SPEED_10000; + else + lp->req_line_speed[cfx_idx] = + SPEED_1000; + } + } + + rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars); + + bnx2x_release_phy_lock(bp); + + bnx2x_calc_fc_adv(bp); + + if (CHIP_REV_IS_SLOW(bp) && bp->link_vars.link_up) { + bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP); + bnx2x_link_report(bp); + } else + queue_delayed_work(bnx2x_wq, &bp->period_task, 0); + bp->link_params.req_line_speed[cfx_idx] = req_line_speed; + return rc; + } + BNX2X_ERR("Bootcode is missing - can not initialize link\n"); + return -EINVAL; +} + +void bnx2x_link_set(struct bnx2x *bp) +{ + if (!BP_NOMCP(bp)) { + bnx2x_acquire_phy_lock(bp); + bnx2x_link_reset(&bp->link_params, &bp->link_vars, 1); + bnx2x_phy_init(&bp->link_params, &bp->link_vars); + bnx2x_release_phy_lock(bp); + + bnx2x_calc_fc_adv(bp); + } else + BNX2X_ERR("Bootcode is missing - can not set link\n"); +} + +static void bnx2x__link_reset(struct bnx2x *bp) +{ + if (!BP_NOMCP(bp)) { + bnx2x_acquire_phy_lock(bp); + bnx2x_link_reset(&bp->link_params, &bp->link_vars, 1); + bnx2x_release_phy_lock(bp); + } else + BNX2X_ERR("Bootcode is missing - can not reset link\n"); +} + +u8 bnx2x_link_test(struct bnx2x *bp, u8 is_serdes) +{ + u8 rc = 0; + + if (!BP_NOMCP(bp)) { + bnx2x_acquire_phy_lock(bp); + rc = bnx2x_test_link(&bp->link_params, &bp->link_vars, + is_serdes); + bnx2x_release_phy_lock(bp); + } else + BNX2X_ERR("Bootcode is missing - can not test link\n"); + + return rc; +} + +static void bnx2x_init_port_minmax(struct bnx2x *bp) +{ + u32 r_param = bp->link_vars.line_speed / 8; + u32 fair_periodic_timeout_usec; + u32 t_fair; + + memset(&(bp->cmng.rs_vars), 0, + sizeof(struct rate_shaping_vars_per_port)); + memset(&(bp->cmng.fair_vars), 0, sizeof(struct fairness_vars_per_port)); + + /* 100 usec in SDM ticks = 25 since each tick is 4 usec */ + bp->cmng.rs_vars.rs_periodic_timeout = RS_PERIODIC_TIMEOUT_USEC / 4; + + /* this is the threshold below which no timer arming will occur + 1.25 coefficient is for the threshold to be a little bigger + than the real time, to compensate for timer in-accuracy */ + bp->cmng.rs_vars.rs_threshold = + (RS_PERIODIC_TIMEOUT_USEC * r_param * 5) / 4; + + /* resolution of fairness timer */ + fair_periodic_timeout_usec = QM_ARB_BYTES / r_param; + /* for 10G it is 1000usec. for 1G it is 10000usec. */ + t_fair = T_FAIR_COEF / bp->link_vars.line_speed; + + /* this is the threshold below which we won't arm the timer anymore */ + bp->cmng.fair_vars.fair_threshold = QM_ARB_BYTES; + + /* we multiply by 1e3/8 to get bytes/msec. + We don't want the credits to pass a credit + of the t_fair*FAIR_MEM (algorithm resolution) */ + bp->cmng.fair_vars.upper_bound = r_param * t_fair * FAIR_MEM; + /* since each tick is 4 usec */ + bp->cmng.fair_vars.fairness_timeout = fair_periodic_timeout_usec / 4; +} + +/* Calculates the sum of vn_min_rates. + It's needed for further normalizing of the min_rates. + Returns: + sum of vn_min_rates. + or + 0 - if all the min_rates are 0. + In the later case fainess algorithm should be deactivated. + If not all min_rates are zero then those that are zeroes will be set to 1. + */ +static void bnx2x_calc_vn_weight_sum(struct bnx2x *bp) +{ + int all_zero = 1; + int vn; + + bp->vn_weight_sum = 0; + for (vn = VN_0; vn < E1HVN_MAX; vn++) { + u32 vn_cfg = bp->mf_config[vn]; + u32 vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >> + FUNC_MF_CFG_MIN_BW_SHIFT) * 100; + + /* Skip hidden vns */ + if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE) + continue; + + /* If min rate is zero - set it to 1 */ + if (!vn_min_rate) + vn_min_rate = DEF_MIN_RATE; + else + all_zero = 0; + + bp->vn_weight_sum += vn_min_rate; + } + + /* if ETS or all min rates are zeros - disable fairness */ + if (BNX2X_IS_ETS_ENABLED(bp)) { + bp->cmng.flags.cmng_enables &= + ~CMNG_FLAGS_PER_PORT_FAIRNESS_VN; + DP(NETIF_MSG_IFUP, "Fairness will be disabled due to ETS\n"); + } else if (all_zero) { + bp->cmng.flags.cmng_enables &= + ~CMNG_FLAGS_PER_PORT_FAIRNESS_VN; + DP(NETIF_MSG_IFUP, "All MIN values are zeroes" + " fairness will be disabled\n"); + } else + bp->cmng.flags.cmng_enables |= + CMNG_FLAGS_PER_PORT_FAIRNESS_VN; +} + +static void bnx2x_init_vn_minmax(struct bnx2x *bp, int vn) +{ + struct rate_shaping_vars_per_vn m_rs_vn; + struct fairness_vars_per_vn m_fair_vn; + u32 vn_cfg = bp->mf_config[vn]; + int func = 2*vn + BP_PORT(bp); + u16 vn_min_rate, vn_max_rate; + int i; + + /* If function is hidden - set min and max to zeroes */ + if (vn_cfg & FUNC_MF_CFG_FUNC_HIDE) { + vn_min_rate = 0; + vn_max_rate = 0; + + } else { + u32 maxCfg = bnx2x_extract_max_cfg(bp, vn_cfg); + + vn_min_rate = ((vn_cfg & FUNC_MF_CFG_MIN_BW_MASK) >> + FUNC_MF_CFG_MIN_BW_SHIFT) * 100; + /* If fairness is enabled (not all min rates are zeroes) and + if current min rate is zero - set it to 1. + This is a requirement of the algorithm. */ + if (bp->vn_weight_sum && (vn_min_rate == 0)) + vn_min_rate = DEF_MIN_RATE; + + if (IS_MF_SI(bp)) + /* maxCfg in percents of linkspeed */ + vn_max_rate = (bp->link_vars.line_speed * maxCfg) / 100; + else + /* maxCfg is absolute in 100Mb units */ + vn_max_rate = maxCfg * 100; + } + + DP(NETIF_MSG_IFUP, + "func %d: vn_min_rate %d vn_max_rate %d vn_weight_sum %d\n", + func, vn_min_rate, vn_max_rate, bp->vn_weight_sum); + + memset(&m_rs_vn, 0, sizeof(struct rate_shaping_vars_per_vn)); + memset(&m_fair_vn, 0, sizeof(struct fairness_vars_per_vn)); + + /* global vn counter - maximal Mbps for this vn */ + m_rs_vn.vn_counter.rate = vn_max_rate; + + /* quota - number of bytes transmitted in this period */ + m_rs_vn.vn_counter.quota = + (vn_max_rate * RS_PERIODIC_TIMEOUT_USEC) / 8; + + if (bp->vn_weight_sum) { + /* credit for each period of the fairness algorithm: + number of bytes in T_FAIR (the vn share the port rate). + vn_weight_sum should not be larger than 10000, thus + T_FAIR_COEF / (8 * vn_weight_sum) will always be greater + than zero */ + m_fair_vn.vn_credit_delta = + max_t(u32, (vn_min_rate * (T_FAIR_COEF / + (8 * bp->vn_weight_sum))), + (bp->cmng.fair_vars.fair_threshold + + MIN_ABOVE_THRESH)); + DP(NETIF_MSG_IFUP, "m_fair_vn.vn_credit_delta %d\n", + m_fair_vn.vn_credit_delta); + } + + /* Store it to internal memory */ + for (i = 0; i < sizeof(struct rate_shaping_vars_per_vn)/4; i++) + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_RATE_SHAPING_PER_VN_VARS_OFFSET(func) + i * 4, + ((u32 *)(&m_rs_vn))[i]); + + for (i = 0; i < sizeof(struct fairness_vars_per_vn)/4; i++) + REG_WR(bp, BAR_XSTRORM_INTMEM + + XSTORM_FAIRNESS_PER_VN_VARS_OFFSET(func) + i * 4, + ((u32 *)(&m_fair_vn))[i]); +} + +static int bnx2x_get_cmng_fns_mode(struct bnx2x *bp) +{ + if (CHIP_REV_IS_SLOW(bp)) + return CMNG_FNS_NONE; + if (IS_MF(bp)) + return CMNG_FNS_MINMAX; + + return CMNG_FNS_NONE; +} + +void bnx2x_read_mf_cfg(struct bnx2x *bp) +{ + int vn, n = (CHIP_MODE_IS_4_PORT(bp) ? 2 : 1); + + if (BP_NOMCP(bp)) + return; /* what should be the default bvalue in this case */ + + /* For 2 port configuration the absolute function number formula + * is: + * abs_func = 2 * vn + BP_PORT + BP_PATH + * + * and there are 4 functions per port + * + * For 4 port configuration it is + * abs_func = 4 * vn + 2 * BP_PORT + BP_PATH + * + * and there are 2 functions per port + */ + for (vn = VN_0; vn < E1HVN_MAX; vn++) { + int /*abs*/func = n * (2 * vn + BP_PORT(bp)) + BP_PATH(bp); + + if (func >= E1H_FUNC_MAX) + break; + + bp->mf_config[vn] = + MF_CFG_RD(bp, func_mf_config[func].config); + } +} + +static void bnx2x_cmng_fns_init(struct bnx2x *bp, u8 read_cfg, u8 cmng_type) +{ + + if (cmng_type == CMNG_FNS_MINMAX) { + int vn; + + /* clear cmng_enables */ + bp->cmng.flags.cmng_enables = 0; + + /* read mf conf from shmem */ + if (read_cfg) + bnx2x_read_mf_cfg(bp); + + /* Init rate shaping and fairness contexts */ + bnx2x_init_port_minmax(bp); + + /* vn_weight_sum and enable fairness if not 0 */ + bnx2x_calc_vn_weight_sum(bp); + + /* calculate and set min-max rate for each vn */ + if (bp->port.pmf) + for (vn = VN_0; vn < E1HVN_MAX; vn++) + bnx2x_init_vn_minmax(bp, vn); + + /* always enable rate shaping and fairness */ + bp->cmng.flags.cmng_enables |= + CMNG_FLAGS_PER_PORT_RATE_SHAPING_VN; + if (!bp->vn_weight_sum) + DP(NETIF_MSG_IFUP, "All MIN values are zeroes" + " fairness will be disabled\n"); + return; + } + + /* rate shaping and fairness are disabled */ + DP(NETIF_MSG_IFUP, + "rate shaping and fairness are disabled\n"); +} + +static inline void bnx2x_link_sync_notify(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int func; + int vn; + + /* Set the attention towards other drivers on the same port */ + for (vn = VN_0; vn < E1HVN_MAX; vn++) { + if (vn == BP_E1HVN(bp)) + continue; + + func = ((vn << 1) | port); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_0 + + (LINK_SYNC_ATTENTION_BIT_FUNC_0 + func)*4, 1); + } +} + +/* This function is called upon link interrupt */ +static void bnx2x_link_attn(struct bnx2x *bp) +{ + /* Make sure that we are synced with the current statistics */ + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + + bnx2x_link_update(&bp->link_params, &bp->link_vars); + + if (bp->link_vars.link_up) { + + /* dropless flow control */ + if (!CHIP_IS_E1(bp) && bp->dropless_fc) { + int port = BP_PORT(bp); + u32 pause_enabled = 0; + + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) + pause_enabled = 1; + + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_ETH_PAUSE_ENABLED_OFFSET(port), + pause_enabled); + } + + if (bp->link_vars.mac_type != MAC_TYPE_EMAC) { + struct host_port_stats *pstats; + + pstats = bnx2x_sp(bp, port_stats); + /* reset old mac stats */ + memset(&(pstats->mac_stx[0]), 0, + sizeof(struct mac_stx)); + } + if (bp->state == BNX2X_STATE_OPEN) + bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP); + } + + if (bp->link_vars.link_up && bp->link_vars.line_speed) { + int cmng_fns = bnx2x_get_cmng_fns_mode(bp); + + if (cmng_fns != CMNG_FNS_NONE) { + bnx2x_cmng_fns_init(bp, false, cmng_fns); + storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp)); + } else + /* rate shaping and fairness are disabled */ + DP(NETIF_MSG_IFUP, + "single function mode without fairness\n"); + } + + __bnx2x_link_report(bp); + + if (IS_MF(bp)) + bnx2x_link_sync_notify(bp); +} + +void bnx2x__link_status_update(struct bnx2x *bp) +{ + if (bp->state != BNX2X_STATE_OPEN) + return; + + bnx2x_link_status_update(&bp->link_params, &bp->link_vars); + + if (bp->link_vars.link_up) + bnx2x_stats_handle(bp, STATS_EVENT_LINK_UP); + else + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + + /* indicate link status */ + bnx2x_link_report(bp); +} + +static void bnx2x_pmf_update(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 val; + + bp->port.pmf = 1; + DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf); + + /* + * We need the mb() to ensure the ordering between the writing to + * bp->port.pmf here and reading it from the bnx2x_periodic_task(). + */ + smp_mb(); + + /* queue a periodic task */ + queue_delayed_work(bnx2x_wq, &bp->period_task, 0); + + bnx2x_dcbx_pmf_update(bp); + + /* enable nig attention */ + val = (0xff0f | (1 << (BP_E1HVN(bp) + 4))); + if (bp->common.int_block == INT_BLOCK_HC) { + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, val); + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, val); + } else if (!CHIP_IS_E1x(bp)) { + REG_WR(bp, IGU_REG_TRAILING_EDGE_LATCH, val); + REG_WR(bp, IGU_REG_LEADING_EDGE_LATCH, val); + } + + bnx2x_stats_handle(bp, STATS_EVENT_PMF); +} + +/* end of Link */ + +/* slow path */ + +/* + * General service functions + */ + +/* send the MCP a request, block until there is a reply */ +u32 bnx2x_fw_command(struct bnx2x *bp, u32 command, u32 param) +{ + int mb_idx = BP_FW_MB_IDX(bp); + u32 seq; + u32 rc = 0; + u32 cnt = 1; + u8 delay = CHIP_REV_IS_SLOW(bp) ? 100 : 10; + + mutex_lock(&bp->fw_mb_mutex); + seq = ++bp->fw_seq; + SHMEM_WR(bp, func_mb[mb_idx].drv_mb_param, param); + SHMEM_WR(bp, func_mb[mb_idx].drv_mb_header, (command | seq)); + + DP(BNX2X_MSG_MCP, "wrote command (%x) to FW MB param 0x%08x\n", + (command | seq), param); + + do { + /* let the FW do it's magic ... */ + msleep(delay); + + rc = SHMEM_RD(bp, func_mb[mb_idx].fw_mb_header); + + /* Give the FW up to 5 second (500*10ms) */ + } while ((seq != (rc & FW_MSG_SEQ_NUMBER_MASK)) && (cnt++ < 500)); + + DP(BNX2X_MSG_MCP, "[after %d ms] read (%x) seq is (%x) from FW MB\n", + cnt*delay, rc, seq); + + /* is this a reply to our command? */ + if (seq == (rc & FW_MSG_SEQ_NUMBER_MASK)) + rc &= FW_MSG_CODE_MASK; + else { + /* FW BUG! */ + BNX2X_ERR("FW failed to respond!\n"); + bnx2x_fw_dump(bp); + rc = 0; + } + mutex_unlock(&bp->fw_mb_mutex); + + return rc; +} + +static u8 stat_counter_valid(struct bnx2x *bp, struct bnx2x_fastpath *fp) +{ +#ifdef BCM_CNIC + /* Statistics are not supported for CNIC Clients at the moment */ + if (IS_FCOE_FP(fp)) + return false; +#endif + return true; +} + +void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p) +{ + if (CHIP_IS_E1x(bp)) { + struct tstorm_eth_function_common_config tcfg = {0}; + + storm_memset_func_cfg(bp, &tcfg, p->func_id); + } + + /* Enable the function in the FW */ + storm_memset_vf_to_pf(bp, p->func_id, p->pf_id); + storm_memset_func_en(bp, p->func_id, 1); + + /* spq */ + if (p->func_flgs & FUNC_FLG_SPQ) { + storm_memset_spq_addr(bp, p->spq_map, p->func_id); + REG_WR(bp, XSEM_REG_FAST_MEMORY + + XSTORM_SPQ_PROD_OFFSET(p->func_id), p->spq_prod); + } +} + +/** + * bnx2x_get_tx_only_flags - Return common flags + * + * @bp device handle + * @fp queue handle + * @zero_stats TRUE if statistics zeroing is needed + * + * Return the flags that are common for the Tx-only and not normal connections. + */ +static inline unsigned long bnx2x_get_common_flags(struct bnx2x *bp, + struct bnx2x_fastpath *fp, + bool zero_stats) +{ + unsigned long flags = 0; + + /* PF driver will always initialize the Queue to an ACTIVE state */ + __set_bit(BNX2X_Q_FLG_ACTIVE, &flags); + + /* tx only connections collect statistics (on the same index as the + * parent connection). The statistics are zeroed when the parent + * connection is initialized. + */ + if (stat_counter_valid(bp, fp)) { + __set_bit(BNX2X_Q_FLG_STATS, &flags); + if (zero_stats) + __set_bit(BNX2X_Q_FLG_ZERO_STATS, &flags); + } + + return flags; +} + +static inline unsigned long bnx2x_get_q_flags(struct bnx2x *bp, + struct bnx2x_fastpath *fp, + bool leading) +{ + unsigned long flags = 0; + + /* calculate other queue flags */ + if (IS_MF_SD(bp)) + __set_bit(BNX2X_Q_FLG_OV, &flags); + + if (IS_FCOE_FP(fp)) + __set_bit(BNX2X_Q_FLG_FCOE, &flags); + + if (!fp->disable_tpa) { + __set_bit(BNX2X_Q_FLG_TPA, &flags); + __set_bit(BNX2X_Q_FLG_TPA_IPV6, &flags); + } + + if (leading) { + __set_bit(BNX2X_Q_FLG_LEADING_RSS, &flags); + __set_bit(BNX2X_Q_FLG_MCAST, &flags); + } + + /* Always set HW VLAN stripping */ + __set_bit(BNX2X_Q_FLG_VLAN, &flags); + + + return flags | bnx2x_get_common_flags(bp, fp, true); +} + +static void bnx2x_pf_q_prep_general(struct bnx2x *bp, + struct bnx2x_fastpath *fp, struct bnx2x_general_setup_params *gen_init, + u8 cos) +{ + gen_init->stat_id = bnx2x_stats_id(fp); + gen_init->spcl_id = fp->cl_id; + + /* Always use mini-jumbo MTU for FCoE L2 ring */ + if (IS_FCOE_FP(fp)) + gen_init->mtu = BNX2X_FCOE_MINI_JUMBO_MTU; + else + gen_init->mtu = bp->dev->mtu; + + gen_init->cos = cos; +} + +static void bnx2x_pf_rx_q_prep(struct bnx2x *bp, + struct bnx2x_fastpath *fp, struct rxq_pause_params *pause, + struct bnx2x_rxq_setup_params *rxq_init) +{ + u8 max_sge = 0; + u16 sge_sz = 0; + u16 tpa_agg_size = 0; + + if (!fp->disable_tpa) { + pause->sge_th_hi = 250; + pause->sge_th_lo = 150; + tpa_agg_size = min_t(u32, + (min_t(u32, 8, MAX_SKB_FRAGS) * + SGE_PAGE_SIZE * PAGES_PER_SGE), 0xffff); + max_sge = SGE_PAGE_ALIGN(bp->dev->mtu) >> + SGE_PAGE_SHIFT; + max_sge = ((max_sge + PAGES_PER_SGE - 1) & + (~(PAGES_PER_SGE-1))) >> PAGES_PER_SGE_SHIFT; + sge_sz = (u16)min_t(u32, SGE_PAGE_SIZE * PAGES_PER_SGE, + 0xffff); + } + + /* pause - not for e1 */ + if (!CHIP_IS_E1(bp)) { + pause->bd_th_hi = 350; + pause->bd_th_lo = 250; + pause->rcq_th_hi = 350; + pause->rcq_th_lo = 250; + + pause->pri_map = 1; + } + + /* rxq setup */ + rxq_init->dscr_map = fp->rx_desc_mapping; + rxq_init->sge_map = fp->rx_sge_mapping; + rxq_init->rcq_map = fp->rx_comp_mapping; + rxq_init->rcq_np_map = fp->rx_comp_mapping + BCM_PAGE_SIZE; + + /* This should be a maximum number of data bytes that may be + * placed on the BD (not including paddings). + */ + rxq_init->buf_sz = fp->rx_buf_size - BNX2X_FW_RX_ALIGN - + IP_HEADER_ALIGNMENT_PADDING; + + rxq_init->cl_qzone_id = fp->cl_qzone_id; + rxq_init->tpa_agg_sz = tpa_agg_size; + rxq_init->sge_buf_sz = sge_sz; + rxq_init->max_sges_pkt = max_sge; + rxq_init->rss_engine_id = BP_FUNC(bp); + + /* Maximum number or simultaneous TPA aggregation for this Queue. + * + * For PF Clients it should be the maximum avaliable number. + * VF driver(s) may want to define it to a smaller value. + */ + rxq_init->max_tpa_queues = + (CHIP_IS_E1(bp) ? ETH_MAX_AGGREGATION_QUEUES_E1 : + ETH_MAX_AGGREGATION_QUEUES_E1H_E2); + + rxq_init->cache_line_log = BNX2X_RX_ALIGN_SHIFT; + rxq_init->fw_sb_id = fp->fw_sb_id; + + if (IS_FCOE_FP(fp)) + rxq_init->sb_cq_index = HC_SP_INDEX_ETH_FCOE_RX_CQ_CONS; + else + rxq_init->sb_cq_index = HC_INDEX_ETH_RX_CQ_CONS; +} + +static void bnx2x_pf_tx_q_prep(struct bnx2x *bp, + struct bnx2x_fastpath *fp, struct bnx2x_txq_setup_params *txq_init, + u8 cos) +{ + txq_init->dscr_map = fp->txdata[cos].tx_desc_mapping; + txq_init->sb_cq_index = HC_INDEX_ETH_FIRST_TX_CQ_CONS + cos; + txq_init->traffic_type = LLFC_TRAFFIC_TYPE_NW; + txq_init->fw_sb_id = fp->fw_sb_id; + + /* + * set the tss leading client id for TX classfication == + * leading RSS client id + */ + txq_init->tss_leading_cl_id = bnx2x_fp(bp, 0, cl_id); + + if (IS_FCOE_FP(fp)) { + txq_init->sb_cq_index = HC_SP_INDEX_ETH_FCOE_TX_CQ_CONS; + txq_init->traffic_type = LLFC_TRAFFIC_TYPE_FCOE; + } +} + +static void bnx2x_pf_init(struct bnx2x *bp) +{ + struct bnx2x_func_init_params func_init = {0}; + struct event_ring_data eq_data = { {0} }; + u16 flags; + + if (!CHIP_IS_E1x(bp)) { + /* reset IGU PF statistics: MSIX + ATTN */ + /* PF */ + REG_WR(bp, IGU_REG_STATISTIC_NUM_MESSAGE_SENT + + BNX2X_IGU_STAS_MSG_VF_CNT*4 + + (CHIP_MODE_IS_4_PORT(bp) ? + BP_FUNC(bp) : BP_VN(bp))*4, 0); + /* ATTN */ + REG_WR(bp, IGU_REG_STATISTIC_NUM_MESSAGE_SENT + + BNX2X_IGU_STAS_MSG_VF_CNT*4 + + BNX2X_IGU_STAS_MSG_PF_CNT*4 + + (CHIP_MODE_IS_4_PORT(bp) ? + BP_FUNC(bp) : BP_VN(bp))*4, 0); + } + + /* function setup flags */ + flags = (FUNC_FLG_STATS | FUNC_FLG_LEADING | FUNC_FLG_SPQ); + + /* This flag is relevant for E1x only. + * E2 doesn't have a TPA configuration in a function level. + */ + flags |= (bp->flags & TPA_ENABLE_FLAG) ? FUNC_FLG_TPA : 0; + + func_init.func_flgs = flags; + func_init.pf_id = BP_FUNC(bp); + func_init.func_id = BP_FUNC(bp); + func_init.spq_map = bp->spq_mapping; + func_init.spq_prod = bp->spq_prod_idx; + + bnx2x_func_init(bp, &func_init); + + memset(&(bp->cmng), 0, sizeof(struct cmng_struct_per_port)); + + /* + * Congestion management values depend on the link rate + * There is no active link so initial link rate is set to 10 Gbps. + * When the link comes up The congestion management values are + * re-calculated according to the actual link rate. + */ + bp->link_vars.line_speed = SPEED_10000; + bnx2x_cmng_fns_init(bp, true, bnx2x_get_cmng_fns_mode(bp)); + + /* Only the PMF sets the HW */ + if (bp->port.pmf) + storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp)); + + /* init Event Queue */ + eq_data.base_addr.hi = U64_HI(bp->eq_mapping); + eq_data.base_addr.lo = U64_LO(bp->eq_mapping); + eq_data.producer = bp->eq_prod; + eq_data.index_id = HC_SP_INDEX_EQ_CONS; + eq_data.sb_id = DEF_SB_ID; + storm_memset_eq_data(bp, &eq_data, BP_FUNC(bp)); +} + + +static void bnx2x_e1h_disable(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + + bnx2x_tx_disable(bp); + + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0); +} + +static void bnx2x_e1h_enable(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1); + + /* Tx queue should be only reenabled */ + netif_tx_wake_all_queues(bp->dev); + + /* + * Should not call netif_carrier_on since it will be called if the link + * is up when checking for link state + */ +} + +/* called due to MCP event (on pmf): + * reread new bandwidth configuration + * configure FW + * notify others function about the change + */ +static inline void bnx2x_config_mf_bw(struct bnx2x *bp) +{ + if (bp->link_vars.link_up) { + bnx2x_cmng_fns_init(bp, true, CMNG_FNS_MINMAX); + bnx2x_link_sync_notify(bp); + } + storm_memset_cmng(bp, &bp->cmng, BP_PORT(bp)); +} + +static inline void bnx2x_set_mf_bw(struct bnx2x *bp) +{ + bnx2x_config_mf_bw(bp); + bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW_ACK, 0); +} + +static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event) +{ + DP(BNX2X_MSG_MCP, "dcc_event 0x%x\n", dcc_event); + + if (dcc_event & DRV_STATUS_DCC_DISABLE_ENABLE_PF) { + + /* + * This is the only place besides the function initialization + * where the bp->flags can change so it is done without any + * locks + */ + if (bp->mf_config[BP_VN(bp)] & FUNC_MF_CFG_FUNC_DISABLED) { + DP(NETIF_MSG_IFDOWN, "mf_cfg function disabled\n"); + bp->flags |= MF_FUNC_DIS; + + bnx2x_e1h_disable(bp); + } else { + DP(NETIF_MSG_IFUP, "mf_cfg function enabled\n"); + bp->flags &= ~MF_FUNC_DIS; + + bnx2x_e1h_enable(bp); + } + dcc_event &= ~DRV_STATUS_DCC_DISABLE_ENABLE_PF; + } + if (dcc_event & DRV_STATUS_DCC_BANDWIDTH_ALLOCATION) { + bnx2x_config_mf_bw(bp); + dcc_event &= ~DRV_STATUS_DCC_BANDWIDTH_ALLOCATION; + } + + /* Report results to MCP */ + if (dcc_event) + bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_FAILURE, 0); + else + bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK, 0); +} + +/* must be called under the spq lock */ +static inline struct eth_spe *bnx2x_sp_get_next(struct bnx2x *bp) +{ + struct eth_spe *next_spe = bp->spq_prod_bd; + + if (bp->spq_prod_bd == bp->spq_last_bd) { + bp->spq_prod_bd = bp->spq; + bp->spq_prod_idx = 0; + DP(NETIF_MSG_TIMER, "end of spq\n"); + } else { + bp->spq_prod_bd++; + bp->spq_prod_idx++; + } + return next_spe; +} + +/* must be called under the spq lock */ +static inline void bnx2x_sp_prod_update(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + + /* + * Make sure that BD data is updated before writing the producer: + * BD data is written to the memory, the producer is read from the + * memory, thus we need a full memory barrier to ensure the ordering. + */ + mb(); + + REG_WR16(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func), + bp->spq_prod_idx); + mmiowb(); +} + +/** + * bnx2x_is_contextless_ramrod - check if the current command ends on EQ + * + * @cmd: command to check + * @cmd_type: command type + */ +static inline bool bnx2x_is_contextless_ramrod(int cmd, int cmd_type) +{ + if ((cmd_type == NONE_CONNECTION_TYPE) || + (cmd == RAMROD_CMD_ID_ETH_FORWARD_SETUP) || + (cmd == RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES) || + (cmd == RAMROD_CMD_ID_ETH_FILTER_RULES) || + (cmd == RAMROD_CMD_ID_ETH_MULTICAST_RULES) || + (cmd == RAMROD_CMD_ID_ETH_SET_MAC) || + (cmd == RAMROD_CMD_ID_ETH_RSS_UPDATE)) + return true; + else + return false; + +} + + +/** + * bnx2x_sp_post - place a single command on an SP ring + * + * @bp: driver handle + * @command: command to place (e.g. SETUP, FILTER_RULES, etc.) + * @cid: SW CID the command is related to + * @data_hi: command private data address (high 32 bits) + * @data_lo: command private data address (low 32 bits) + * @cmd_type: command type (e.g. NONE, ETH) + * + * SP data is handled as if it's always an address pair, thus data fields are + * not swapped to little endian in upper functions. Instead this function swaps + * data as if it's two u32 fields. + */ +int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, + u32 data_hi, u32 data_lo, int cmd_type) +{ + struct eth_spe *spe; + u16 type; + bool common = bnx2x_is_contextless_ramrod(command, cmd_type); + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return -EIO; +#endif + + spin_lock_bh(&bp->spq_lock); + + if (common) { + if (!atomic_read(&bp->eq_spq_left)) { + BNX2X_ERR("BUG! EQ ring full!\n"); + spin_unlock_bh(&bp->spq_lock); + bnx2x_panic(); + return -EBUSY; + } + } else if (!atomic_read(&bp->cq_spq_left)) { + BNX2X_ERR("BUG! SPQ ring full!\n"); + spin_unlock_bh(&bp->spq_lock); + bnx2x_panic(); + return -EBUSY; + } + + spe = bnx2x_sp_get_next(bp); + + /* CID needs port number to be encoded int it */ + spe->hdr.conn_and_cmd_data = + cpu_to_le32((command << SPE_HDR_CMD_ID_SHIFT) | + HW_CID(bp, cid)); + + type = (cmd_type << SPE_HDR_CONN_TYPE_SHIFT) & SPE_HDR_CONN_TYPE; + + type |= ((BP_FUNC(bp) << SPE_HDR_FUNCTION_ID_SHIFT) & + SPE_HDR_FUNCTION_ID); + + spe->hdr.type = cpu_to_le16(type); + + spe->data.update_data_addr.hi = cpu_to_le32(data_hi); + spe->data.update_data_addr.lo = cpu_to_le32(data_lo); + + /* + * It's ok if the actual decrement is issued towards the memory + * somewhere between the spin_lock and spin_unlock. Thus no + * more explict memory barrier is needed. + */ + if (common) + atomic_dec(&bp->eq_spq_left); + else + atomic_dec(&bp->cq_spq_left); + + + DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/, + "SPQE[%x] (%x:%x) (cmd, common?) (%d,%d) hw_cid %x data (%x:%x) " + "type(0x%x) left (CQ, EQ) (%x,%x)\n", + bp->spq_prod_idx, (u32)U64_HI(bp->spq_mapping), + (u32)(U64_LO(bp->spq_mapping) + + (void *)bp->spq_prod_bd - (void *)bp->spq), command, common, + HW_CID(bp, cid), data_hi, data_lo, type, + atomic_read(&bp->cq_spq_left), atomic_read(&bp->eq_spq_left)); + + bnx2x_sp_prod_update(bp); + spin_unlock_bh(&bp->spq_lock); + return 0; +} + +/* acquire split MCP access lock register */ +static int bnx2x_acquire_alr(struct bnx2x *bp) +{ + u32 j, val; + int rc = 0; + + might_sleep(); + for (j = 0; j < 1000; j++) { + val = (1UL << 31); + REG_WR(bp, GRCBASE_MCP + 0x9c, val); + val = REG_RD(bp, GRCBASE_MCP + 0x9c); + if (val & (1L << 31)) + break; + + msleep(5); + } + if (!(val & (1L << 31))) { + BNX2X_ERR("Cannot acquire MCP access lock register\n"); + rc = -EBUSY; + } + + return rc; +} + +/* release split MCP access lock register */ +static void bnx2x_release_alr(struct bnx2x *bp) +{ + REG_WR(bp, GRCBASE_MCP + 0x9c, 0); +} + +#define BNX2X_DEF_SB_ATT_IDX 0x0001 +#define BNX2X_DEF_SB_IDX 0x0002 + +static inline u16 bnx2x_update_dsb_idx(struct bnx2x *bp) +{ + struct host_sp_status_block *def_sb = bp->def_status_blk; + u16 rc = 0; + + barrier(); /* status block is written to by the chip */ + if (bp->def_att_idx != def_sb->atten_status_block.attn_bits_index) { + bp->def_att_idx = def_sb->atten_status_block.attn_bits_index; + rc |= BNX2X_DEF_SB_ATT_IDX; + } + + if (bp->def_idx != def_sb->sp_sb.running_index) { + bp->def_idx = def_sb->sp_sb.running_index; + rc |= BNX2X_DEF_SB_IDX; + } + + /* Do not reorder: indecies reading should complete before handling */ + barrier(); + return rc; +} + +/* + * slow path service functions + */ + +static void bnx2x_attn_int_asserted(struct bnx2x *bp, u32 asserted) +{ + int port = BP_PORT(bp); + u32 aeu_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : + MISC_REG_AEU_MASK_ATTN_FUNC_0; + u32 nig_int_mask_addr = port ? NIG_REG_MASK_INTERRUPT_PORT1 : + NIG_REG_MASK_INTERRUPT_PORT0; + u32 aeu_mask; + u32 nig_mask = 0; + u32 reg_addr; + + if (bp->attn_state & asserted) + BNX2X_ERR("IGU ERROR\n"); + + bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port); + aeu_mask = REG_RD(bp, aeu_addr); + + DP(NETIF_MSG_HW, "aeu_mask %x newly asserted %x\n", + aeu_mask, asserted); + aeu_mask &= ~(asserted & 0x3ff); + DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask); + + REG_WR(bp, aeu_addr, aeu_mask); + bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port); + + DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state); + bp->attn_state |= asserted; + DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state); + + if (asserted & ATTN_HARD_WIRED_MASK) { + if (asserted & ATTN_NIG_FOR_FUNC) { + + bnx2x_acquire_phy_lock(bp); + + /* save nig interrupt mask */ + nig_mask = REG_RD(bp, nig_int_mask_addr); + + /* If nig_mask is not set, no need to call the update + * function. + */ + if (nig_mask) { + REG_WR(bp, nig_int_mask_addr, 0); + + bnx2x_link_attn(bp); + } + + /* handle unicore attn? */ + } + if (asserted & ATTN_SW_TIMER_4_FUNC) + DP(NETIF_MSG_HW, "ATTN_SW_TIMER_4_FUNC!\n"); + + if (asserted & GPIO_2_FUNC) + DP(NETIF_MSG_HW, "GPIO_2_FUNC!\n"); + + if (asserted & GPIO_3_FUNC) + DP(NETIF_MSG_HW, "GPIO_3_FUNC!\n"); + + if (asserted & GPIO_4_FUNC) + DP(NETIF_MSG_HW, "GPIO_4_FUNC!\n"); + + if (port == 0) { + if (asserted & ATTN_GENERAL_ATTN_1) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_1!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_1, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_2) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_2!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_2, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_3) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_3!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_3, 0x0); + } + } else { + if (asserted & ATTN_GENERAL_ATTN_4) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_4!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_4, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_5) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_5!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_5, 0x0); + } + if (asserted & ATTN_GENERAL_ATTN_6) { + DP(NETIF_MSG_HW, "ATTN_GENERAL_ATTN_6!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_6, 0x0); + } + } + + } /* if hardwired */ + + if (bp->common.int_block == INT_BLOCK_HC) + reg_addr = (HC_REG_COMMAND_REG + port*32 + + COMMAND_REG_ATTN_BITS_SET); + else + reg_addr = (BAR_IGU_INTMEM + IGU_CMD_ATTN_BIT_SET_UPPER*8); + + DP(NETIF_MSG_HW, "about to mask 0x%08x at %s addr 0x%x\n", asserted, + (bp->common.int_block == INT_BLOCK_HC) ? "HC" : "IGU", reg_addr); + REG_WR(bp, reg_addr, asserted); + + /* now set back the mask */ + if (asserted & ATTN_NIG_FOR_FUNC) { + REG_WR(bp, nig_int_mask_addr, nig_mask); + bnx2x_release_phy_lock(bp); + } +} + +static inline void bnx2x_fan_failure(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 ext_phy_config; + /* mark the failure */ + ext_phy_config = + SHMEM_RD(bp, + dev_info.port_hw_config[port].external_phy_config); + + ext_phy_config &= ~PORT_HW_CFG_XGXS_EXT_PHY_TYPE_MASK; + ext_phy_config |= PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE; + SHMEM_WR(bp, dev_info.port_hw_config[port].external_phy_config, + ext_phy_config); + + /* log the failure */ + netdev_err(bp->dev, "Fan Failure on Network Controller has caused" + " the driver to shutdown the card to prevent permanent" + " damage. Please contact OEM Support for assistance\n"); +} + +static inline void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) +{ + int port = BP_PORT(bp); + int reg_offset; + u32 val; + + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + + if (attn & AEU_INPUTS_ATTN_BITS_SPIO5) { + + val = REG_RD(bp, reg_offset); + val &= ~AEU_INPUTS_ATTN_BITS_SPIO5; + REG_WR(bp, reg_offset, val); + + BNX2X_ERR("SPIO5 hw attention\n"); + + /* Fan failure attention */ + bnx2x_hw_reset_phy(&bp->link_params); + bnx2x_fan_failure(bp); + } + + if ((attn & bp->link_vars.aeu_int_mask) && bp->port.pmf) { + bnx2x_acquire_phy_lock(bp); + bnx2x_handle_module_detect_int(&bp->link_params); + bnx2x_release_phy_lock(bp); + } + + if (attn & HW_INTERRUT_ASSERT_SET_0) { + + val = REG_RD(bp, reg_offset); + val &= ~(attn & HW_INTERRUT_ASSERT_SET_0); + REG_WR(bp, reg_offset, val); + + BNX2X_ERR("FATAL HW block attention set0 0x%x\n", + (u32)(attn & HW_INTERRUT_ASSERT_SET_0)); + bnx2x_panic(); + } +} + +static inline void bnx2x_attn_int_deasserted1(struct bnx2x *bp, u32 attn) +{ + u32 val; + + if (attn & AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT) { + + val = REG_RD(bp, DORQ_REG_DORQ_INT_STS_CLR); + BNX2X_ERR("DB hw attention 0x%x\n", val); + /* DORQ discard attention */ + if (val & 0x2) + BNX2X_ERR("FATAL error from DORQ\n"); + } + + if (attn & HW_INTERRUT_ASSERT_SET_1) { + + int port = BP_PORT(bp); + int reg_offset; + + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1); + + val = REG_RD(bp, reg_offset); + val &= ~(attn & HW_INTERRUT_ASSERT_SET_1); + REG_WR(bp, reg_offset, val); + + BNX2X_ERR("FATAL HW block attention set1 0x%x\n", + (u32)(attn & HW_INTERRUT_ASSERT_SET_1)); + bnx2x_panic(); + } +} + +static inline void bnx2x_attn_int_deasserted2(struct bnx2x *bp, u32 attn) +{ + u32 val; + + if (attn & AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT) { + + val = REG_RD(bp, CFC_REG_CFC_INT_STS_CLR); + BNX2X_ERR("CFC hw attention 0x%x\n", val); + /* CFC error attention */ + if (val & 0x2) + BNX2X_ERR("FATAL error from CFC\n"); + } + + if (attn & AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT) { + val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_0); + BNX2X_ERR("PXP hw attention-0 0x%x\n", val); + /* RQ_USDMDP_FIFO_OVERFLOW */ + if (val & 0x18000) + BNX2X_ERR("FATAL error from PXP\n"); + + if (!CHIP_IS_E1x(bp)) { + val = REG_RD(bp, PXP_REG_PXP_INT_STS_CLR_1); + BNX2X_ERR("PXP hw attention-1 0x%x\n", val); + } + } + + if (attn & HW_INTERRUT_ASSERT_SET_2) { + + int port = BP_PORT(bp); + int reg_offset; + + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_2 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_2); + + val = REG_RD(bp, reg_offset); + val &= ~(attn & HW_INTERRUT_ASSERT_SET_2); + REG_WR(bp, reg_offset, val); + + BNX2X_ERR("FATAL HW block attention set2 0x%x\n", + (u32)(attn & HW_INTERRUT_ASSERT_SET_2)); + bnx2x_panic(); + } +} + +static inline void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn) +{ + u32 val; + + if (attn & EVEREST_GEN_ATTN_IN_USE_MASK) { + + if (attn & BNX2X_PMF_LINK_ASSERT) { + int func = BP_FUNC(bp); + + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0); + bp->mf_config[BP_VN(bp)] = MF_CFG_RD(bp, + func_mf_config[BP_ABS_FUNC(bp)].config); + val = SHMEM_RD(bp, + func_mb[BP_FW_MB_IDX(bp)].drv_status); + if (val & DRV_STATUS_DCC_EVENT_MASK) + bnx2x_dcc_event(bp, + (val & DRV_STATUS_DCC_EVENT_MASK)); + + if (val & DRV_STATUS_SET_MF_BW) + bnx2x_set_mf_bw(bp); + + if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF)) + bnx2x_pmf_update(bp); + + if (bp->port.pmf && + (val & DRV_STATUS_DCBX_NEGOTIATION_RESULTS) && + bp->dcbx_enabled > 0) + /* start dcbx state machine */ + bnx2x_dcbx_set_params(bp, + BNX2X_DCBX_STATE_NEG_RECEIVED); + if (bp->link_vars.periodic_flags & + PERIODIC_FLAGS_LINK_EVENT) { + /* sync with link */ + bnx2x_acquire_phy_lock(bp); + bp->link_vars.periodic_flags &= + ~PERIODIC_FLAGS_LINK_EVENT; + bnx2x_release_phy_lock(bp); + if (IS_MF(bp)) + bnx2x_link_sync_notify(bp); + bnx2x_link_report(bp); + } + /* Always call it here: bnx2x_link_report() will + * prevent the link indication duplication. + */ + bnx2x__link_status_update(bp); + } else if (attn & BNX2X_MC_ASSERT_BITS) { + + BNX2X_ERR("MC assert!\n"); + bnx2x_mc_assert(bp); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_10, 0); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_9, 0); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_8, 0); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_7, 0); + bnx2x_panic(); + + } else if (attn & BNX2X_MCP_ASSERT) { + + BNX2X_ERR("MCP assert!\n"); + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_11, 0); + bnx2x_fw_dump(bp); + + } else + BNX2X_ERR("Unknown HW assert! (attn 0x%x)\n", attn); + } + + if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) { + BNX2X_ERR("LATCHED attention 0x%08x (masked)\n", attn); + if (attn & BNX2X_GRC_TIMEOUT) { + val = CHIP_IS_E1(bp) ? 0 : + REG_RD(bp, MISC_REG_GRC_TIMEOUT_ATTN); + BNX2X_ERR("GRC time-out 0x%08x\n", val); + } + if (attn & BNX2X_GRC_RSV) { + val = CHIP_IS_E1(bp) ? 0 : + REG_RD(bp, MISC_REG_GRC_RSV_ATTN); + BNX2X_ERR("GRC reserved 0x%08x\n", val); + } + REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff); + } +} + +/* + * Bits map: + * 0-7 - Engine0 load counter. + * 8-15 - Engine1 load counter. + * 16 - Engine0 RESET_IN_PROGRESS bit. + * 17 - Engine1 RESET_IN_PROGRESS bit. + * 18 - Engine0 ONE_IS_LOADED. Set when there is at least one active function + * on the engine + * 19 - Engine1 ONE_IS_LOADED. + * 20 - Chip reset flow bit. When set none-leader must wait for both engines + * leader to complete (check for both RESET_IN_PROGRESS bits and not for + * just the one belonging to its engine). + * + */ +#define BNX2X_RECOVERY_GLOB_REG MISC_REG_GENERIC_POR_1 + +#define BNX2X_PATH0_LOAD_CNT_MASK 0x000000ff +#define BNX2X_PATH0_LOAD_CNT_SHIFT 0 +#define BNX2X_PATH1_LOAD_CNT_MASK 0x0000ff00 +#define BNX2X_PATH1_LOAD_CNT_SHIFT 8 +#define BNX2X_PATH0_RST_IN_PROG_BIT 0x00010000 +#define BNX2X_PATH1_RST_IN_PROG_BIT 0x00020000 +#define BNX2X_GLOBAL_RESET_BIT 0x00040000 + +/* + * Set the GLOBAL_RESET bit. + * + * Should be run under rtnl lock + */ +void bnx2x_set_reset_global(struct bnx2x *bp) +{ + u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG); + + REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val | BNX2X_GLOBAL_RESET_BIT); + barrier(); + mmiowb(); +} + +/* + * Clear the GLOBAL_RESET bit. + * + * Should be run under rtnl lock + */ +static inline void bnx2x_clear_reset_global(struct bnx2x *bp) +{ + u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG); + + REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val & (~BNX2X_GLOBAL_RESET_BIT)); + barrier(); + mmiowb(); +} + +/* + * Checks the GLOBAL_RESET bit. + * + * should be run under rtnl lock + */ +static inline bool bnx2x_reset_is_global(struct bnx2x *bp) +{ + u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG); + + DP(NETIF_MSG_HW, "GEN_REG_VAL=0x%08x\n", val); + return (val & BNX2X_GLOBAL_RESET_BIT) ? true : false; +} + +/* + * Clear RESET_IN_PROGRESS bit for the current engine. + * + * Should be run under rtnl lock + */ +static inline void bnx2x_set_reset_done(struct bnx2x *bp) +{ + u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG); + u32 bit = BP_PATH(bp) ? + BNX2X_PATH1_RST_IN_PROG_BIT : BNX2X_PATH0_RST_IN_PROG_BIT; + + /* Clear the bit */ + val &= ~bit; + REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val); + barrier(); + mmiowb(); +} + +/* + * Set RESET_IN_PROGRESS for the current engine. + * + * should be run under rtnl lock + */ +void bnx2x_set_reset_in_progress(struct bnx2x *bp) +{ + u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG); + u32 bit = BP_PATH(bp) ? + BNX2X_PATH1_RST_IN_PROG_BIT : BNX2X_PATH0_RST_IN_PROG_BIT; + + /* Set the bit */ + val |= bit; + REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val); + barrier(); + mmiowb(); +} + +/* + * Checks the RESET_IN_PROGRESS bit for the given engine. + * should be run under rtnl lock + */ +bool bnx2x_reset_is_done(struct bnx2x *bp, int engine) +{ + u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG); + u32 bit = engine ? + BNX2X_PATH1_RST_IN_PROG_BIT : BNX2X_PATH0_RST_IN_PROG_BIT; + + /* return false if bit is set */ + return (val & bit) ? false : true; +} + +/* + * Increment the load counter for the current engine. + * + * should be run under rtnl lock + */ +void bnx2x_inc_load_cnt(struct bnx2x *bp) +{ + u32 val1, val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG); + u32 mask = BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_MASK : + BNX2X_PATH0_LOAD_CNT_MASK; + u32 shift = BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_SHIFT : + BNX2X_PATH0_LOAD_CNT_SHIFT; + + DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val); + + /* get the current counter value */ + val1 = (val & mask) >> shift; + + /* increment... */ + val1++; + + /* clear the old value */ + val &= ~mask; + + /* set the new one */ + val |= ((val1 << shift) & mask); + + REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val); + barrier(); + mmiowb(); +} + +/** + * bnx2x_dec_load_cnt - decrement the load counter + * + * @bp: driver handle + * + * Should be run under rtnl lock. + * Decrements the load counter for the current engine. Returns + * the new counter value. + */ +u32 bnx2x_dec_load_cnt(struct bnx2x *bp) +{ + u32 val1, val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG); + u32 mask = BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_MASK : + BNX2X_PATH0_LOAD_CNT_MASK; + u32 shift = BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_SHIFT : + BNX2X_PATH0_LOAD_CNT_SHIFT; + + DP(NETIF_MSG_HW, "Old GEN_REG_VAL=0x%08x\n", val); + + /* get the current counter value */ + val1 = (val & mask) >> shift; + + /* decrement... */ + val1--; + + /* clear the old value */ + val &= ~mask; + + /* set the new one */ + val |= ((val1 << shift) & mask); + + REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val); + barrier(); + mmiowb(); + + return val1; +} + +/* + * Read the load counter for the current engine. + * + * should be run under rtnl lock + */ +static inline u32 bnx2x_get_load_cnt(struct bnx2x *bp, int engine) +{ + u32 mask = (engine ? BNX2X_PATH1_LOAD_CNT_MASK : + BNX2X_PATH0_LOAD_CNT_MASK); + u32 shift = (engine ? BNX2X_PATH1_LOAD_CNT_SHIFT : + BNX2X_PATH0_LOAD_CNT_SHIFT); + u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG); + + DP(NETIF_MSG_HW, "GLOB_REG=0x%08x\n", val); + + val = (val & mask) >> shift; + + DP(NETIF_MSG_HW, "load_cnt for engine %d = %d\n", engine, val); + + return val; +} + +/* + * Reset the load counter for the current engine. + * + * should be run under rtnl lock + */ +static inline void bnx2x_clear_load_cnt(struct bnx2x *bp) +{ + u32 val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG); + u32 mask = (BP_PATH(bp) ? BNX2X_PATH1_LOAD_CNT_MASK : + BNX2X_PATH0_LOAD_CNT_MASK); + + REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val & (~mask)); +} + +static inline void _print_next_block(int idx, const char *blk) +{ + if (idx) + pr_cont(", "); + pr_cont("%s", blk); +} + +static inline int bnx2x_check_blocks_with_parity0(u32 sig, int par_num, + bool print) +{ + int i = 0; + u32 cur_bit = 0; + for (i = 0; sig; i++) { + cur_bit = ((u32)0x1 << i); + if (sig & cur_bit) { + switch (cur_bit) { + case AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "BRB"); + break; + case AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "PARSER"); + break; + case AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "TSDM"); + break; + case AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR: + if (print) + _print_next_block(par_num++, + "SEARCHER"); + break; + case AEU_INPUTS_ATTN_BITS_TCM_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "TCM"); + break; + case AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "TSEMI"); + break; + case AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "XPB"); + break; + } + + /* Clear the bit */ + sig &= ~cur_bit; + } + } + + return par_num; +} + +static inline int bnx2x_check_blocks_with_parity1(u32 sig, int par_num, + bool *global, bool print) +{ + int i = 0; + u32 cur_bit = 0; + for (i = 0; sig; i++) { + cur_bit = ((u32)0x1 << i); + if (sig & cur_bit) { + switch (cur_bit) { + case AEU_INPUTS_ATTN_BITS_PBF_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "PBF"); + break; + case AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "QM"); + break; + case AEU_INPUTS_ATTN_BITS_TIMERS_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "TM"); + break; + case AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "XSDM"); + break; + case AEU_INPUTS_ATTN_BITS_XCM_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "XCM"); + break; + case AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "XSEMI"); + break; + case AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR: + if (print) + _print_next_block(par_num++, + "DOORBELLQ"); + break; + case AEU_INPUTS_ATTN_BITS_NIG_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "NIG"); + break; + case AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR: + if (print) + _print_next_block(par_num++, + "VAUX PCI CORE"); + *global = true; + break; + case AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "DEBUG"); + break; + case AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "USDM"); + break; + case AEU_INPUTS_ATTN_BITS_UCM_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "UCM"); + break; + case AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "USEMI"); + break; + case AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "UPB"); + break; + case AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "CSDM"); + break; + case AEU_INPUTS_ATTN_BITS_CCM_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "CCM"); + break; + } + + /* Clear the bit */ + sig &= ~cur_bit; + } + } + + return par_num; +} + +static inline int bnx2x_check_blocks_with_parity2(u32 sig, int par_num, + bool print) +{ + int i = 0; + u32 cur_bit = 0; + for (i = 0; sig; i++) { + cur_bit = ((u32)0x1 << i); + if (sig & cur_bit) { + switch (cur_bit) { + case AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "CSEMI"); + break; + case AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "PXP"); + break; + case AEU_IN_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR: + if (print) + _print_next_block(par_num++, + "PXPPCICLOCKCLIENT"); + break; + case AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "CFC"); + break; + case AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "CDU"); + break; + case AEU_INPUTS_ATTN_BITS_DMAE_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "DMAE"); + break; + case AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "IGU"); + break; + case AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "MISC"); + break; + } + + /* Clear the bit */ + sig &= ~cur_bit; + } + } + + return par_num; +} + +static inline int bnx2x_check_blocks_with_parity3(u32 sig, int par_num, + bool *global, bool print) +{ + int i = 0; + u32 cur_bit = 0; + for (i = 0; sig; i++) { + cur_bit = ((u32)0x1 << i); + if (sig & cur_bit) { + switch (cur_bit) { + case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY: + if (print) + _print_next_block(par_num++, "MCP ROM"); + *global = true; + break; + case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY: + if (print) + _print_next_block(par_num++, + "MCP UMP RX"); + *global = true; + break; + case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY: + if (print) + _print_next_block(par_num++, + "MCP UMP TX"); + *global = true; + break; + case AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY: + if (print) + _print_next_block(par_num++, + "MCP SCPAD"); + *global = true; + break; + } + + /* Clear the bit */ + sig &= ~cur_bit; + } + } + + return par_num; +} + +static inline int bnx2x_check_blocks_with_parity4(u32 sig, int par_num, + bool print) +{ + int i = 0; + u32 cur_bit = 0; + for (i = 0; sig; i++) { + cur_bit = ((u32)0x1 << i); + if (sig & cur_bit) { + switch (cur_bit) { + case AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "PGLUE_B"); + break; + case AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR: + if (print) + _print_next_block(par_num++, "ATC"); + break; + } + + /* Clear the bit */ + sig &= ~cur_bit; + } + } + + return par_num; +} + +static inline bool bnx2x_parity_attn(struct bnx2x *bp, bool *global, bool print, + u32 *sig) +{ + if ((sig[0] & HW_PRTY_ASSERT_SET_0) || + (sig[1] & HW_PRTY_ASSERT_SET_1) || + (sig[2] & HW_PRTY_ASSERT_SET_2) || + (sig[3] & HW_PRTY_ASSERT_SET_3) || + (sig[4] & HW_PRTY_ASSERT_SET_4)) { + int par_num = 0; + DP(NETIF_MSG_HW, "Was parity error: HW block parity attention: " + "[0]:0x%08x [1]:0x%08x [2]:0x%08x [3]:0x%08x " + "[4]:0x%08x\n", + sig[0] & HW_PRTY_ASSERT_SET_0, + sig[1] & HW_PRTY_ASSERT_SET_1, + sig[2] & HW_PRTY_ASSERT_SET_2, + sig[3] & HW_PRTY_ASSERT_SET_3, + sig[4] & HW_PRTY_ASSERT_SET_4); + if (print) + netdev_err(bp->dev, + "Parity errors detected in blocks: "); + par_num = bnx2x_check_blocks_with_parity0( + sig[0] & HW_PRTY_ASSERT_SET_0, par_num, print); + par_num = bnx2x_check_blocks_with_parity1( + sig[1] & HW_PRTY_ASSERT_SET_1, par_num, global, print); + par_num = bnx2x_check_blocks_with_parity2( + sig[2] & HW_PRTY_ASSERT_SET_2, par_num, print); + par_num = bnx2x_check_blocks_with_parity3( + sig[3] & HW_PRTY_ASSERT_SET_3, par_num, global, print); + par_num = bnx2x_check_blocks_with_parity4( + sig[4] & HW_PRTY_ASSERT_SET_4, par_num, print); + + if (print) + pr_cont("\n"); + + return true; + } else + return false; +} + +/** + * bnx2x_chk_parity_attn - checks for parity attentions. + * + * @bp: driver handle + * @global: true if there was a global attention + * @print: show parity attention in syslog + */ +bool bnx2x_chk_parity_attn(struct bnx2x *bp, bool *global, bool print) +{ + struct attn_route attn = { {0} }; + int port = BP_PORT(bp); + + attn.sig[0] = REG_RD(bp, + MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + + port*4); + attn.sig[1] = REG_RD(bp, + MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + + port*4); + attn.sig[2] = REG_RD(bp, + MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + + port*4); + attn.sig[3] = REG_RD(bp, + MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + + port*4); + + if (!CHIP_IS_E1x(bp)) + attn.sig[4] = REG_RD(bp, + MISC_REG_AEU_AFTER_INVERT_5_FUNC_0 + + port*4); + + return bnx2x_parity_attn(bp, global, print, attn.sig); +} + + +static inline void bnx2x_attn_int_deasserted4(struct bnx2x *bp, u32 attn) +{ + u32 val; + if (attn & AEU_INPUTS_ATTN_BITS_PGLUE_HW_INTERRUPT) { + + val = REG_RD(bp, PGLUE_B_REG_PGLUE_B_INT_STS_CLR); + BNX2X_ERR("PGLUE hw attention 0x%x\n", val); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_ADDRESS_ERROR) + BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_" + "ADDRESS_ERROR\n"); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_INCORRECT_RCV_BEHAVIOR) + BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_" + "INCORRECT_RCV_BEHAVIOR\n"); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN) + BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_" + "WAS_ERROR_ATTN\n"); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_VF_LENGTH_VIOLATION_ATTN) + BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_" + "VF_LENGTH_VIOLATION_ATTN\n"); + if (val & + PGLUE_B_PGLUE_B_INT_STS_REG_VF_GRC_SPACE_VIOLATION_ATTN) + BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_" + "VF_GRC_SPACE_VIOLATION_ATTN\n"); + if (val & + PGLUE_B_PGLUE_B_INT_STS_REG_VF_MSIX_BAR_VIOLATION_ATTN) + BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_" + "VF_MSIX_BAR_VIOLATION_ATTN\n"); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_TCPL_ERROR_ATTN) + BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_" + "TCPL_ERROR_ATTN\n"); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_TCPL_IN_TWO_RCBS_ATTN) + BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_" + "TCPL_IN_TWO_RCBS_ATTN\n"); + if (val & PGLUE_B_PGLUE_B_INT_STS_REG_CSSNOOP_FIFO_OVERFLOW) + BNX2X_ERR("PGLUE_B_PGLUE_B_INT_STS_REG_" + "CSSNOOP_FIFO_OVERFLOW\n"); + } + if (attn & AEU_INPUTS_ATTN_BITS_ATC_HW_INTERRUPT) { + val = REG_RD(bp, ATC_REG_ATC_INT_STS_CLR); + BNX2X_ERR("ATC hw attention 0x%x\n", val); + if (val & ATC_ATC_INT_STS_REG_ADDRESS_ERROR) + BNX2X_ERR("ATC_ATC_INT_STS_REG_ADDRESS_ERROR\n"); + if (val & ATC_ATC_INT_STS_REG_ATC_TCPL_TO_NOT_PEND) + BNX2X_ERR("ATC_ATC_INT_STS_REG" + "_ATC_TCPL_TO_NOT_PEND\n"); + if (val & ATC_ATC_INT_STS_REG_ATC_GPA_MULTIPLE_HITS) + BNX2X_ERR("ATC_ATC_INT_STS_REG_" + "ATC_GPA_MULTIPLE_HITS\n"); + if (val & ATC_ATC_INT_STS_REG_ATC_RCPL_TO_EMPTY_CNT) + BNX2X_ERR("ATC_ATC_INT_STS_REG_" + "ATC_RCPL_TO_EMPTY_CNT\n"); + if (val & ATC_ATC_INT_STS_REG_ATC_TCPL_ERROR) + BNX2X_ERR("ATC_ATC_INT_STS_REG_ATC_TCPL_ERROR\n"); + if (val & ATC_ATC_INT_STS_REG_ATC_IREQ_LESS_THAN_STU) + BNX2X_ERR("ATC_ATC_INT_STS_REG_" + "ATC_IREQ_LESS_THAN_STU\n"); + } + + if (attn & (AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR | + AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR)) { + BNX2X_ERR("FATAL parity attention set4 0x%x\n", + (u32)(attn & (AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR | + AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR))); + } + +} + +static void bnx2x_attn_int_deasserted(struct bnx2x *bp, u32 deasserted) +{ + struct attn_route attn, *group_mask; + int port = BP_PORT(bp); + int index; + u32 reg_addr; + u32 val; + u32 aeu_mask; + bool global = false; + + /* need to take HW lock because MCP or other port might also + try to handle this event */ + bnx2x_acquire_alr(bp); + + if (bnx2x_chk_parity_attn(bp, &global, true)) { +#ifndef BNX2X_STOP_ON_ERROR + bp->recovery_state = BNX2X_RECOVERY_INIT; + schedule_delayed_work(&bp->sp_rtnl_task, 0); + /* Disable HW interrupts */ + bnx2x_int_disable(bp); + /* In case of parity errors don't handle attentions so that + * other function would "see" parity errors. + */ +#else + bnx2x_panic(); +#endif + bnx2x_release_alr(bp); + return; + } + + attn.sig[0] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + port*4); + attn.sig[1] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 + port*4); + attn.sig[2] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 + port*4); + attn.sig[3] = REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 + port*4); + if (!CHIP_IS_E1x(bp)) + attn.sig[4] = + REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_5_FUNC_0 + port*4); + else + attn.sig[4] = 0; + + DP(NETIF_MSG_HW, "attn: %08x %08x %08x %08x %08x\n", + attn.sig[0], attn.sig[1], attn.sig[2], attn.sig[3], attn.sig[4]); + + for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) { + if (deasserted & (1 << index)) { + group_mask = &bp->attn_group[index]; + + DP(NETIF_MSG_HW, "group[%d]: %08x %08x " + "%08x %08x %08x\n", + index, + group_mask->sig[0], group_mask->sig[1], + group_mask->sig[2], group_mask->sig[3], + group_mask->sig[4]); + + bnx2x_attn_int_deasserted4(bp, + attn.sig[4] & group_mask->sig[4]); + bnx2x_attn_int_deasserted3(bp, + attn.sig[3] & group_mask->sig[3]); + bnx2x_attn_int_deasserted1(bp, + attn.sig[1] & group_mask->sig[1]); + bnx2x_attn_int_deasserted2(bp, + attn.sig[2] & group_mask->sig[2]); + bnx2x_attn_int_deasserted0(bp, + attn.sig[0] & group_mask->sig[0]); + } + } + + bnx2x_release_alr(bp); + + if (bp->common.int_block == INT_BLOCK_HC) + reg_addr = (HC_REG_COMMAND_REG + port*32 + + COMMAND_REG_ATTN_BITS_CLR); + else + reg_addr = (BAR_IGU_INTMEM + IGU_CMD_ATTN_BIT_CLR_UPPER*8); + + val = ~deasserted; + DP(NETIF_MSG_HW, "about to mask 0x%08x at %s addr 0x%x\n", val, + (bp->common.int_block == INT_BLOCK_HC) ? "HC" : "IGU", reg_addr); + REG_WR(bp, reg_addr, val); + + if (~bp->attn_state & deasserted) + BNX2X_ERR("IGU ERROR\n"); + + reg_addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : + MISC_REG_AEU_MASK_ATTN_FUNC_0; + + bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port); + aeu_mask = REG_RD(bp, reg_addr); + + DP(NETIF_MSG_HW, "aeu_mask %x newly deasserted %x\n", + aeu_mask, deasserted); + aeu_mask |= (deasserted & 0x3ff); + DP(NETIF_MSG_HW, "new mask %x\n", aeu_mask); + + REG_WR(bp, reg_addr, aeu_mask); + bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_PORT0_ATT_MASK + port); + + DP(NETIF_MSG_HW, "attn_state %x\n", bp->attn_state); + bp->attn_state &= ~deasserted; + DP(NETIF_MSG_HW, "new state %x\n", bp->attn_state); +} + +static void bnx2x_attn_int(struct bnx2x *bp) +{ + /* read local copy of bits */ + u32 attn_bits = le32_to_cpu(bp->def_status_blk->atten_status_block. + attn_bits); + u32 attn_ack = le32_to_cpu(bp->def_status_blk->atten_status_block. + attn_bits_ack); + u32 attn_state = bp->attn_state; + + /* look for changed bits */ + u32 asserted = attn_bits & ~attn_ack & ~attn_state; + u32 deasserted = ~attn_bits & attn_ack & attn_state; + + DP(NETIF_MSG_HW, + "attn_bits %x attn_ack %x asserted %x deasserted %x\n", + attn_bits, attn_ack, asserted, deasserted); + + if (~(attn_bits ^ attn_ack) & (attn_bits ^ attn_state)) + BNX2X_ERR("BAD attention state\n"); + + /* handle bits that were raised */ + if (asserted) + bnx2x_attn_int_asserted(bp, asserted); + + if (deasserted) + bnx2x_attn_int_deasserted(bp, deasserted); +} + +void bnx2x_igu_ack_sb(struct bnx2x *bp, u8 igu_sb_id, u8 segment, + u16 index, u8 op, u8 update) +{ + u32 igu_addr = BAR_IGU_INTMEM + (IGU_CMD_INT_ACK_BASE + igu_sb_id)*8; + + bnx2x_igu_ack_sb_gen(bp, igu_sb_id, segment, index, op, update, + igu_addr); +} + +static inline void bnx2x_update_eq_prod(struct bnx2x *bp, u16 prod) +{ + /* No memory barriers */ + storm_memset_eq_prod(bp, prod, BP_FUNC(bp)); + mmiowb(); /* keep prod updates ordered */ +} + +#ifdef BCM_CNIC +static int bnx2x_cnic_handle_cfc_del(struct bnx2x *bp, u32 cid, + union event_ring_elem *elem) +{ + u8 err = elem->message.error; + + if (!bp->cnic_eth_dev.starting_cid || + (cid < bp->cnic_eth_dev.starting_cid && + cid != bp->cnic_eth_dev.iscsi_l2_cid)) + return 1; + + DP(BNX2X_MSG_SP, "got delete ramrod for CNIC CID %d\n", cid); + + if (unlikely(err)) { + + BNX2X_ERR("got delete ramrod for CNIC CID %d with error!\n", + cid); + bnx2x_panic_dump(bp); + } + bnx2x_cnic_cfc_comp(bp, cid, err); + return 0; +} +#endif + +static inline void bnx2x_handle_mcast_eqe(struct bnx2x *bp) +{ + struct bnx2x_mcast_ramrod_params rparam; + int rc; + + memset(&rparam, 0, sizeof(rparam)); + + rparam.mcast_obj = &bp->mcast_obj; + + netif_addr_lock_bh(bp->dev); + + /* Clear pending state for the last command */ + bp->mcast_obj.raw.clear_pending(&bp->mcast_obj.raw); + + /* If there are pending mcast commands - send them */ + if (bp->mcast_obj.check_pending(&bp->mcast_obj)) { + rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT); + if (rc < 0) + BNX2X_ERR("Failed to send pending mcast commands: %d\n", + rc); + } + + netif_addr_unlock_bh(bp->dev); +} + +static inline void bnx2x_handle_classification_eqe(struct bnx2x *bp, + union event_ring_elem *elem) +{ + unsigned long ramrod_flags = 0; + int rc = 0; + u32 cid = elem->message.data.eth_event.echo & BNX2X_SWCID_MASK; + struct bnx2x_vlan_mac_obj *vlan_mac_obj; + + /* Always push next commands out, don't wait here */ + __set_bit(RAMROD_CONT, &ramrod_flags); + + switch (elem->message.data.eth_event.echo >> BNX2X_SWCID_SHIFT) { + case BNX2X_FILTER_MAC_PENDING: +#ifdef BCM_CNIC + if (cid == BNX2X_ISCSI_ETH_CID) + vlan_mac_obj = &bp->iscsi_l2_mac_obj; + else +#endif + vlan_mac_obj = &bp->fp[cid].mac_obj; + + break; + vlan_mac_obj = &bp->fp[cid].mac_obj; + + case BNX2X_FILTER_MCAST_PENDING: + /* This is only relevant for 57710 where multicast MACs are + * configured as unicast MACs using the same ramrod. + */ + bnx2x_handle_mcast_eqe(bp); + return; + default: + BNX2X_ERR("Unsupported classification command: %d\n", + elem->message.data.eth_event.echo); + return; + } + + rc = vlan_mac_obj->complete(bp, vlan_mac_obj, elem, &ramrod_flags); + + if (rc < 0) + BNX2X_ERR("Failed to schedule new commands: %d\n", rc); + else if (rc > 0) + DP(BNX2X_MSG_SP, "Scheduled next pending commands...\n"); + +} + +#ifdef BCM_CNIC +static void bnx2x_set_iscsi_eth_rx_mode(struct bnx2x *bp, bool start); +#endif + +static inline void bnx2x_handle_rx_mode_eqe(struct bnx2x *bp) +{ + netif_addr_lock_bh(bp->dev); + + clear_bit(BNX2X_FILTER_RX_MODE_PENDING, &bp->sp_state); + + /* Send rx_mode command again if was requested */ + if (test_and_clear_bit(BNX2X_FILTER_RX_MODE_SCHED, &bp->sp_state)) + bnx2x_set_storm_rx_mode(bp); +#ifdef BCM_CNIC + else if (test_and_clear_bit(BNX2X_FILTER_ISCSI_ETH_START_SCHED, + &bp->sp_state)) + bnx2x_set_iscsi_eth_rx_mode(bp, true); + else if (test_and_clear_bit(BNX2X_FILTER_ISCSI_ETH_STOP_SCHED, + &bp->sp_state)) + bnx2x_set_iscsi_eth_rx_mode(bp, false); +#endif + + netif_addr_unlock_bh(bp->dev); +} + +static inline struct bnx2x_queue_sp_obj *bnx2x_cid_to_q_obj( + struct bnx2x *bp, u32 cid) +{ + DP(BNX2X_MSG_SP, "retrieving fp from cid %d", cid); +#ifdef BCM_CNIC + if (cid == BNX2X_FCOE_ETH_CID) + return &bnx2x_fcoe(bp, q_obj); + else +#endif + return &bnx2x_fp(bp, CID_TO_FP(cid), q_obj); +} + +static void bnx2x_eq_int(struct bnx2x *bp) +{ + u16 hw_cons, sw_cons, sw_prod; + union event_ring_elem *elem; + u32 cid; + u8 opcode; + int spqe_cnt = 0; + struct bnx2x_queue_sp_obj *q_obj; + struct bnx2x_func_sp_obj *f_obj = &bp->func_obj; + struct bnx2x_raw_obj *rss_raw = &bp->rss_conf_obj.raw; + + hw_cons = le16_to_cpu(*bp->eq_cons_sb); + + /* The hw_cos range is 1-255, 257 - the sw_cons range is 0-254, 256. + * when we get the the next-page we nned to adjust so the loop + * condition below will be met. The next element is the size of a + * regular element and hence incrementing by 1 + */ + if ((hw_cons & EQ_DESC_MAX_PAGE) == EQ_DESC_MAX_PAGE) + hw_cons++; + + /* This function may never run in parallel with itself for a + * specific bp, thus there is no need in "paired" read memory + * barrier here. + */ + sw_cons = bp->eq_cons; + sw_prod = bp->eq_prod; + + DP(BNX2X_MSG_SP, "EQ: hw_cons %u sw_cons %u bp->eq_spq_left %x\n", + hw_cons, sw_cons, atomic_read(&bp->eq_spq_left)); + + for (; sw_cons != hw_cons; + sw_prod = NEXT_EQ_IDX(sw_prod), sw_cons = NEXT_EQ_IDX(sw_cons)) { + + + elem = &bp->eq_ring[EQ_DESC(sw_cons)]; + + cid = SW_CID(elem->message.data.cfc_del_event.cid); + opcode = elem->message.opcode; + + + /* handle eq element */ + switch (opcode) { + case EVENT_RING_OPCODE_STAT_QUERY: + DP(NETIF_MSG_TIMER, "got statistics comp event %d\n", + bp->stats_comp++); + /* nothing to do with stats comp */ + goto next_spqe; + + case EVENT_RING_OPCODE_CFC_DEL: + /* handle according to cid range */ + /* + * we may want to verify here that the bp state is + * HALTING + */ + DP(BNX2X_MSG_SP, + "got delete ramrod for MULTI[%d]\n", cid); +#ifdef BCM_CNIC + if (!bnx2x_cnic_handle_cfc_del(bp, cid, elem)) + goto next_spqe; +#endif + q_obj = bnx2x_cid_to_q_obj(bp, cid); + + if (q_obj->complete_cmd(bp, q_obj, BNX2X_Q_CMD_CFC_DEL)) + break; + + + + goto next_spqe; + + case EVENT_RING_OPCODE_STOP_TRAFFIC: + DP(BNX2X_MSG_SP, "got STOP TRAFFIC\n"); + if (f_obj->complete_cmd(bp, f_obj, + BNX2X_F_CMD_TX_STOP)) + break; + bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_PAUSED); + goto next_spqe; + + case EVENT_RING_OPCODE_START_TRAFFIC: + DP(BNX2X_MSG_SP, "got START TRAFFIC\n"); + if (f_obj->complete_cmd(bp, f_obj, + BNX2X_F_CMD_TX_START)) + break; + bnx2x_dcbx_set_params(bp, BNX2X_DCBX_STATE_TX_RELEASED); + goto next_spqe; + case EVENT_RING_OPCODE_FUNCTION_START: + DP(BNX2X_MSG_SP, "got FUNC_START ramrod\n"); + if (f_obj->complete_cmd(bp, f_obj, BNX2X_F_CMD_START)) + break; + + goto next_spqe; + + case EVENT_RING_OPCODE_FUNCTION_STOP: + DP(BNX2X_MSG_SP, "got FUNC_STOP ramrod\n"); + if (f_obj->complete_cmd(bp, f_obj, BNX2X_F_CMD_STOP)) + break; + + goto next_spqe; + } + + switch (opcode | bp->state) { + case (EVENT_RING_OPCODE_RSS_UPDATE_RULES | + BNX2X_STATE_OPEN): + case (EVENT_RING_OPCODE_RSS_UPDATE_RULES | + BNX2X_STATE_OPENING_WAIT4_PORT): + cid = elem->message.data.eth_event.echo & + BNX2X_SWCID_MASK; + DP(BNX2X_MSG_SP, "got RSS_UPDATE ramrod. CID %d\n", + cid); + rss_raw->clear_pending(rss_raw); + break; + + case (EVENT_RING_OPCODE_SET_MAC | BNX2X_STATE_OPEN): + case (EVENT_RING_OPCODE_SET_MAC | BNX2X_STATE_DIAG): + case (EVENT_RING_OPCODE_SET_MAC | + BNX2X_STATE_CLOSING_WAIT4_HALT): + case (EVENT_RING_OPCODE_CLASSIFICATION_RULES | + BNX2X_STATE_OPEN): + case (EVENT_RING_OPCODE_CLASSIFICATION_RULES | + BNX2X_STATE_DIAG): + case (EVENT_RING_OPCODE_CLASSIFICATION_RULES | + BNX2X_STATE_CLOSING_WAIT4_HALT): + DP(BNX2X_MSG_SP, "got (un)set mac ramrod\n"); + bnx2x_handle_classification_eqe(bp, elem); + break; + + case (EVENT_RING_OPCODE_MULTICAST_RULES | + BNX2X_STATE_OPEN): + case (EVENT_RING_OPCODE_MULTICAST_RULES | + BNX2X_STATE_DIAG): + case (EVENT_RING_OPCODE_MULTICAST_RULES | + BNX2X_STATE_CLOSING_WAIT4_HALT): + DP(BNX2X_MSG_SP, "got mcast ramrod\n"); + bnx2x_handle_mcast_eqe(bp); + break; + + case (EVENT_RING_OPCODE_FILTERS_RULES | + BNX2X_STATE_OPEN): + case (EVENT_RING_OPCODE_FILTERS_RULES | + BNX2X_STATE_DIAG): + case (EVENT_RING_OPCODE_FILTERS_RULES | + BNX2X_STATE_CLOSING_WAIT4_HALT): + DP(BNX2X_MSG_SP, "got rx_mode ramrod\n"); + bnx2x_handle_rx_mode_eqe(bp); + break; + default: + /* unknown event log error and continue */ + BNX2X_ERR("Unknown EQ event %d, bp->state 0x%x\n", + elem->message.opcode, bp->state); + } +next_spqe: + spqe_cnt++; + } /* for */ + + smp_mb__before_atomic_inc(); + atomic_add(spqe_cnt, &bp->eq_spq_left); + + bp->eq_cons = sw_cons; + bp->eq_prod = sw_prod; + /* Make sure that above mem writes were issued towards the memory */ + smp_wmb(); + + /* update producer */ + bnx2x_update_eq_prod(bp, bp->eq_prod); +} + +static void bnx2x_sp_task(struct work_struct *work) +{ + struct bnx2x *bp = container_of(work, struct bnx2x, sp_task.work); + u16 status; + + status = bnx2x_update_dsb_idx(bp); +/* if (status == 0) */ +/* BNX2X_ERR("spurious slowpath interrupt!\n"); */ + + DP(NETIF_MSG_INTR, "got a slowpath interrupt (status 0x%x)\n", status); + + /* HW attentions */ + if (status & BNX2X_DEF_SB_ATT_IDX) { + bnx2x_attn_int(bp); + status &= ~BNX2X_DEF_SB_ATT_IDX; + } + + /* SP events: STAT_QUERY and others */ + if (status & BNX2X_DEF_SB_IDX) { +#ifdef BCM_CNIC + struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp); + + if ((!NO_FCOE(bp)) && + (bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) { + /* + * Prevent local bottom-halves from running as + * we are going to change the local NAPI list. + */ + local_bh_disable(); + napi_schedule(&bnx2x_fcoe(bp, napi)); + local_bh_enable(); + } +#endif + /* Handle EQ completions */ + bnx2x_eq_int(bp); + + bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID, + le16_to_cpu(bp->def_idx), IGU_INT_NOP, 1); + + status &= ~BNX2X_DEF_SB_IDX; + } + + if (unlikely(status)) + DP(NETIF_MSG_INTR, "got an unknown interrupt! (status 0x%x)\n", + status); + + bnx2x_ack_sb(bp, bp->igu_dsb_id, ATTENTION_ID, + le16_to_cpu(bp->def_att_idx), IGU_INT_ENABLE, 1); +} + +irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance) +{ + struct net_device *dev = dev_instance; + struct bnx2x *bp = netdev_priv(dev); + + bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID, 0, + IGU_INT_DISABLE, 0); + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return IRQ_HANDLED; +#endif + +#ifdef BCM_CNIC + { + struct cnic_ops *c_ops; + + rcu_read_lock(); + c_ops = rcu_dereference(bp->cnic_ops); + if (c_ops) + c_ops->cnic_handler(bp->cnic_data, NULL); + rcu_read_unlock(); + } +#endif + queue_delayed_work(bnx2x_wq, &bp->sp_task, 0); + + return IRQ_HANDLED; +} + +/* end of slow path */ + + +void bnx2x_drv_pulse(struct bnx2x *bp) +{ + SHMEM_WR(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb, + bp->fw_drv_pulse_wr_seq); +} + + +static void bnx2x_timer(unsigned long data) +{ + u8 cos; + struct bnx2x *bp = (struct bnx2x *) data; + + if (!netif_running(bp->dev)) + return; + + if (poll) { + struct bnx2x_fastpath *fp = &bp->fp[0]; + + for_each_cos_in_tx_queue(fp, cos) + bnx2x_tx_int(bp, &fp->txdata[cos]); + bnx2x_rx_int(fp, 1000); + } + + if (!BP_NOMCP(bp)) { + int mb_idx = BP_FW_MB_IDX(bp); + u32 drv_pulse; + u32 mcp_pulse; + + ++bp->fw_drv_pulse_wr_seq; + bp->fw_drv_pulse_wr_seq &= DRV_PULSE_SEQ_MASK; + /* TBD - add SYSTEM_TIME */ + drv_pulse = bp->fw_drv_pulse_wr_seq; + bnx2x_drv_pulse(bp); + + mcp_pulse = (SHMEM_RD(bp, func_mb[mb_idx].mcp_pulse_mb) & + MCP_PULSE_SEQ_MASK); + /* The delta between driver pulse and mcp response + * should be 1 (before mcp response) or 0 (after mcp response) + */ + if ((drv_pulse != mcp_pulse) && + (drv_pulse != ((mcp_pulse + 1) & MCP_PULSE_SEQ_MASK))) { + /* someone lost a heartbeat... */ + BNX2X_ERR("drv_pulse (0x%x) != mcp_pulse (0x%x)\n", + drv_pulse, mcp_pulse); + } + } + + if (bp->state == BNX2X_STATE_OPEN) + bnx2x_stats_handle(bp, STATS_EVENT_UPDATE); + + mod_timer(&bp->timer, jiffies + bp->current_interval); +} + +/* end of Statistics */ + +/* nic init */ + +/* + * nic init service functions + */ + +static inline void bnx2x_fill(struct bnx2x *bp, u32 addr, int fill, u32 len) +{ + u32 i; + if (!(len%4) && !(addr%4)) + for (i = 0; i < len; i += 4) + REG_WR(bp, addr + i, fill); + else + for (i = 0; i < len; i++) + REG_WR8(bp, addr + i, fill); + +} + +/* helper: writes FP SP data to FW - data_size in dwords */ +static inline void bnx2x_wr_fp_sb_data(struct bnx2x *bp, + int fw_sb_id, + u32 *sb_data_p, + u32 data_size) +{ + int index; + for (index = 0; index < data_size; index++) + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_STATUS_BLOCK_DATA_OFFSET(fw_sb_id) + + sizeof(u32)*index, + *(sb_data_p + index)); +} + +static inline void bnx2x_zero_fp_sb(struct bnx2x *bp, int fw_sb_id) +{ + u32 *sb_data_p; + u32 data_size = 0; + struct hc_status_block_data_e2 sb_data_e2; + struct hc_status_block_data_e1x sb_data_e1x; + + /* disable the function first */ + if (!CHIP_IS_E1x(bp)) { + memset(&sb_data_e2, 0, sizeof(struct hc_status_block_data_e2)); + sb_data_e2.common.state = SB_DISABLED; + sb_data_e2.common.p_func.vf_valid = false; + sb_data_p = (u32 *)&sb_data_e2; + data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32); + } else { + memset(&sb_data_e1x, 0, + sizeof(struct hc_status_block_data_e1x)); + sb_data_e1x.common.state = SB_DISABLED; + sb_data_e1x.common.p_func.vf_valid = false; + sb_data_p = (u32 *)&sb_data_e1x; + data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32); + } + bnx2x_wr_fp_sb_data(bp, fw_sb_id, sb_data_p, data_size); + + bnx2x_fill(bp, BAR_CSTRORM_INTMEM + + CSTORM_STATUS_BLOCK_OFFSET(fw_sb_id), 0, + CSTORM_STATUS_BLOCK_SIZE); + bnx2x_fill(bp, BAR_CSTRORM_INTMEM + + CSTORM_SYNC_BLOCK_OFFSET(fw_sb_id), 0, + CSTORM_SYNC_BLOCK_SIZE); +} + +/* helper: writes SP SB data to FW */ +static inline void bnx2x_wr_sp_sb_data(struct bnx2x *bp, + struct hc_sp_status_block_data *sp_sb_data) +{ + int func = BP_FUNC(bp); + int i; + for (i = 0; i < sizeof(struct hc_sp_status_block_data)/sizeof(u32); i++) + REG_WR(bp, BAR_CSTRORM_INTMEM + + CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func) + + i*sizeof(u32), + *((u32 *)sp_sb_data + i)); +} + +static inline void bnx2x_zero_sp_sb(struct bnx2x *bp) +{ + int func = BP_FUNC(bp); + struct hc_sp_status_block_data sp_sb_data; + memset(&sp_sb_data, 0, sizeof(struct hc_sp_status_block_data)); + + sp_sb_data.state = SB_DISABLED; + sp_sb_data.p_func.vf_valid = false; + + bnx2x_wr_sp_sb_data(bp, &sp_sb_data); + + bnx2x_fill(bp, BAR_CSTRORM_INTMEM + + CSTORM_SP_STATUS_BLOCK_OFFSET(func), 0, + CSTORM_SP_STATUS_BLOCK_SIZE); + bnx2x_fill(bp, BAR_CSTRORM_INTMEM + + CSTORM_SP_SYNC_BLOCK_OFFSET(func), 0, + CSTORM_SP_SYNC_BLOCK_SIZE); + +} + + +static inline +void bnx2x_setup_ndsb_state_machine(struct hc_status_block_sm *hc_sm, + int igu_sb_id, int igu_seg_id) +{ + hc_sm->igu_sb_id = igu_sb_id; + hc_sm->igu_seg_id = igu_seg_id; + hc_sm->timer_value = 0xFF; + hc_sm->time_to_expire = 0xFFFFFFFF; +} + +static void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, + u8 vf_valid, int fw_sb_id, int igu_sb_id) +{ + int igu_seg_id; + + 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; + int data_size; + u32 *sb_data_p; + + if (CHIP_INT_MODE_IS_BC(bp)) + igu_seg_id = HC_SEG_ACCESS_NORM; + else + igu_seg_id = IGU_SEG_ACCESS_NORM; + + bnx2x_zero_fp_sb(bp, fw_sb_id); + + if (!CHIP_IS_E1x(bp)) { + memset(&sb_data_e2, 0, sizeof(struct hc_status_block_data_e2)); + sb_data_e2.common.state = SB_ENABLED; + sb_data_e2.common.p_func.pf_id = BP_FUNC(bp); + sb_data_e2.common.p_func.vf_id = vfid; + sb_data_e2.common.p_func.vf_valid = vf_valid; + sb_data_e2.common.p_func.vnic_id = BP_VN(bp); + sb_data_e2.common.same_igu_sb_1b = true; + sb_data_e2.common.host_sb_addr.hi = U64_HI(mapping); + sb_data_e2.common.host_sb_addr.lo = U64_LO(mapping); + hc_sm_p = sb_data_e2.common.state_machine; + sb_data_p = (u32 *)&sb_data_e2; + data_size = sizeof(struct hc_status_block_data_e2)/sizeof(u32); + } else { + memset(&sb_data_e1x, 0, + sizeof(struct hc_status_block_data_e1x)); + sb_data_e1x.common.state = SB_ENABLED; + sb_data_e1x.common.p_func.pf_id = BP_FUNC(bp); + sb_data_e1x.common.p_func.vf_id = 0xff; + sb_data_e1x.common.p_func.vf_valid = false; + sb_data_e1x.common.p_func.vnic_id = BP_VN(bp); + sb_data_e1x.common.same_igu_sb_1b = true; + sb_data_e1x.common.host_sb_addr.hi = U64_HI(mapping); + sb_data_e1x.common.host_sb_addr.lo = U64_LO(mapping); + hc_sm_p = sb_data_e1x.common.state_machine; + sb_data_p = (u32 *)&sb_data_e1x; + data_size = sizeof(struct hc_status_block_data_e1x)/sizeof(u32); + } + + bnx2x_setup_ndsb_state_machine(&hc_sm_p[SM_RX_ID], + igu_sb_id, igu_seg_id); + bnx2x_setup_ndsb_state_machine(&hc_sm_p[SM_TX_ID], + igu_sb_id, igu_seg_id); + + DP(NETIF_MSG_HW, "Init FW SB %d\n", fw_sb_id); + + /* write indecies to HW */ + bnx2x_wr_fp_sb_data(bp, fw_sb_id, sb_data_p, data_size); +} + +static void bnx2x_update_coalesce_sb(struct bnx2x *bp, u8 fw_sb_id, + u16 tx_usec, u16 rx_usec) +{ + bnx2x_update_coalesce_sb_index(bp, fw_sb_id, HC_INDEX_ETH_RX_CQ_CONS, + false, rx_usec); + bnx2x_update_coalesce_sb_index(bp, fw_sb_id, + HC_INDEX_ETH_TX_CQ_CONS_COS0, false, + tx_usec); + bnx2x_update_coalesce_sb_index(bp, fw_sb_id, + HC_INDEX_ETH_TX_CQ_CONS_COS1, false, + tx_usec); + bnx2x_update_coalesce_sb_index(bp, fw_sb_id, + HC_INDEX_ETH_TX_CQ_CONS_COS2, false, + tx_usec); +} + +static void bnx2x_init_def_sb(struct bnx2x *bp) +{ + struct host_sp_status_block *def_sb = bp->def_status_blk; + dma_addr_t mapping = bp->def_status_blk_mapping; + int igu_sp_sb_index; + int igu_seg_id; + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int reg_offset; + u64 section; + int index; + struct hc_sp_status_block_data sp_sb_data; + memset(&sp_sb_data, 0, sizeof(struct hc_sp_status_block_data)); + + if (CHIP_INT_MODE_IS_BC(bp)) { + igu_sp_sb_index = DEF_SB_IGU_ID; + igu_seg_id = HC_SEG_ACCESS_DEF; + } else { + igu_sp_sb_index = bp->igu_dsb_id; + igu_seg_id = IGU_SEG_ACCESS_DEF; + } + + /* ATTN */ + section = ((u64)mapping) + offsetof(struct host_sp_status_block, + atten_status_block); + def_sb->atten_status_block.status_block_id = igu_sp_sb_index; + + bp->attn_state = 0; + + reg_offset = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + for (index = 0; index < MAX_DYNAMIC_ATTN_GRPS; index++) { + int sindex; + /* take care of sig[0]..sig[4] */ + for (sindex = 0; sindex < 4; sindex++) + bp->attn_group[index].sig[sindex] = + REG_RD(bp, reg_offset + sindex*0x4 + 0x10*index); + + if (!CHIP_IS_E1x(bp)) + /* + * enable5 is separate from the rest of the registers, + * and therefore the address skip is 4 + * and not 16 between the different groups + */ + bp->attn_group[index].sig[4] = REG_RD(bp, + reg_offset + 0x10 + 0x4*index); + else + bp->attn_group[index].sig[4] = 0; + } + + if (bp->common.int_block == INT_BLOCK_HC) { + reg_offset = (port ? HC_REG_ATTN_MSG1_ADDR_L : + HC_REG_ATTN_MSG0_ADDR_L); + + REG_WR(bp, reg_offset, U64_LO(section)); + REG_WR(bp, reg_offset + 4, U64_HI(section)); + } else if (!CHIP_IS_E1x(bp)) { + REG_WR(bp, IGU_REG_ATTN_MSG_ADDR_L, U64_LO(section)); + REG_WR(bp, IGU_REG_ATTN_MSG_ADDR_H, U64_HI(section)); + } + + section = ((u64)mapping) + offsetof(struct host_sp_status_block, + sp_sb); + + bnx2x_zero_sp_sb(bp); + + sp_sb_data.state = SB_ENABLED; + sp_sb_data.host_sb_addr.lo = U64_LO(section); + sp_sb_data.host_sb_addr.hi = U64_HI(section); + sp_sb_data.igu_sb_id = igu_sp_sb_index; + sp_sb_data.igu_seg_id = igu_seg_id; + sp_sb_data.p_func.pf_id = func; + sp_sb_data.p_func.vnic_id = BP_VN(bp); + sp_sb_data.p_func.vf_id = 0xff; + + bnx2x_wr_sp_sb_data(bp, &sp_sb_data); + + bnx2x_ack_sb(bp, bp->igu_dsb_id, USTORM_ID, 0, IGU_INT_ENABLE, 0); +} + +void bnx2x_update_coalesce(struct bnx2x *bp) +{ + int i; + + for_each_eth_queue(bp, i) + bnx2x_update_coalesce_sb(bp, bp->fp[i].fw_sb_id, + bp->tx_ticks, bp->rx_ticks); +} + +static void bnx2x_init_sp_ring(struct bnx2x *bp) +{ + spin_lock_init(&bp->spq_lock); + atomic_set(&bp->cq_spq_left, MAX_SPQ_PENDING); + + bp->spq_prod_idx = 0; + bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX; + bp->spq_prod_bd = bp->spq; + bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT; +} + +static void bnx2x_init_eq_ring(struct bnx2x *bp) +{ + int i; + for (i = 1; i <= NUM_EQ_PAGES; i++) { + union event_ring_elem *elem = + &bp->eq_ring[EQ_DESC_CNT_PAGE * i - 1]; + + elem->next_page.addr.hi = + cpu_to_le32(U64_HI(bp->eq_mapping + + BCM_PAGE_SIZE * (i % NUM_EQ_PAGES))); + elem->next_page.addr.lo = + cpu_to_le32(U64_LO(bp->eq_mapping + + BCM_PAGE_SIZE*(i % NUM_EQ_PAGES))); + } + bp->eq_cons = 0; + bp->eq_prod = NUM_EQ_DESC; + bp->eq_cons_sb = BNX2X_EQ_INDEX; + /* we want a warning message before it gets rought... */ + atomic_set(&bp->eq_spq_left, + min_t(int, MAX_SP_DESC_CNT - MAX_SPQ_PENDING, NUM_EQ_DESC) - 1); +} + + +/* called with netif_addr_lock_bh() */ +void bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id, + unsigned long rx_mode_flags, + unsigned long rx_accept_flags, + unsigned long tx_accept_flags, + unsigned long ramrod_flags) +{ + struct bnx2x_rx_mode_ramrod_params ramrod_param; + int rc; + + memset(&ramrod_param, 0, sizeof(ramrod_param)); + + /* Prepare ramrod parameters */ + ramrod_param.cid = 0; + ramrod_param.cl_id = cl_id; + ramrod_param.rx_mode_obj = &bp->rx_mode_obj; + ramrod_param.func_id = BP_FUNC(bp); + + ramrod_param.pstate = &bp->sp_state; + ramrod_param.state = BNX2X_FILTER_RX_MODE_PENDING; + + ramrod_param.rdata = bnx2x_sp(bp, rx_mode_rdata); + ramrod_param.rdata_mapping = bnx2x_sp_mapping(bp, rx_mode_rdata); + + set_bit(BNX2X_FILTER_RX_MODE_PENDING, &bp->sp_state); + + ramrod_param.ramrod_flags = ramrod_flags; + ramrod_param.rx_mode_flags = rx_mode_flags; + + ramrod_param.rx_accept_flags = rx_accept_flags; + ramrod_param.tx_accept_flags = tx_accept_flags; + + rc = bnx2x_config_rx_mode(bp, &ramrod_param); + if (rc < 0) { + BNX2X_ERR("Set rx_mode %d failed\n", bp->rx_mode); + return; + } +} + +/* called with netif_addr_lock_bh() */ +void bnx2x_set_storm_rx_mode(struct bnx2x *bp) +{ + unsigned long rx_mode_flags = 0, ramrod_flags = 0; + unsigned long rx_accept_flags = 0, tx_accept_flags = 0; + +#ifdef BCM_CNIC + if (!NO_FCOE(bp)) + + /* Configure rx_mode of FCoE Queue */ + __set_bit(BNX2X_RX_MODE_FCOE_ETH, &rx_mode_flags); +#endif + + switch (bp->rx_mode) { + case BNX2X_RX_MODE_NONE: + /* + * 'drop all' supersedes any accept flags that may have been + * passed to the function. + */ + break; + case BNX2X_RX_MODE_NORMAL: + __set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags); + __set_bit(BNX2X_ACCEPT_MULTICAST, &rx_accept_flags); + __set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags); + + /* internal switching mode */ + __set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags); + __set_bit(BNX2X_ACCEPT_MULTICAST, &tx_accept_flags); + __set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags); + + break; + case BNX2X_RX_MODE_ALLMULTI: + __set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags); + __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &rx_accept_flags); + __set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags); + + /* internal switching mode */ + __set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags); + __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &tx_accept_flags); + __set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags); + + break; + case BNX2X_RX_MODE_PROMISC: + /* According to deffinition of SI mode, iface in promisc mode + * should receive matched and unmatched (in resolution of port) + * unicast packets. + */ + __set_bit(BNX2X_ACCEPT_UNMATCHED, &rx_accept_flags); + __set_bit(BNX2X_ACCEPT_UNICAST, &rx_accept_flags); + __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &rx_accept_flags); + __set_bit(BNX2X_ACCEPT_BROADCAST, &rx_accept_flags); + + /* internal switching mode */ + __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &tx_accept_flags); + __set_bit(BNX2X_ACCEPT_BROADCAST, &tx_accept_flags); + + if (IS_MF_SI(bp)) + __set_bit(BNX2X_ACCEPT_ALL_UNICAST, &tx_accept_flags); + else + __set_bit(BNX2X_ACCEPT_UNICAST, &tx_accept_flags); + + break; + default: + BNX2X_ERR("Unknown rx_mode: %d\n", bp->rx_mode); + return; + } + + if (bp->rx_mode != BNX2X_RX_MODE_NONE) { + __set_bit(BNX2X_ACCEPT_ANY_VLAN, &rx_accept_flags); + __set_bit(BNX2X_ACCEPT_ANY_VLAN, &tx_accept_flags); + } + + __set_bit(RAMROD_RX, &ramrod_flags); + __set_bit(RAMROD_TX, &ramrod_flags); + + bnx2x_set_q_rx_mode(bp, bp->fp->cl_id, rx_mode_flags, rx_accept_flags, + tx_accept_flags, ramrod_flags); +} + +static void bnx2x_init_internal_common(struct bnx2x *bp) +{ + int i; + + if (IS_MF_SI(bp)) + /* + * In switch independent mode, the TSTORM needs to accept + * packets that failed classification, since approximate match + * mac addresses aren't written to NIG LLH + */ + REG_WR8(bp, BAR_TSTRORM_INTMEM + + TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET, 2); + else if (!CHIP_IS_E1(bp)) /* 57710 doesn't support MF */ + REG_WR8(bp, BAR_TSTRORM_INTMEM + + TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET, 0); + + /* Zero this manually as its initialization is + currently missing in the initTool */ + for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++) + REG_WR(bp, BAR_USTRORM_INTMEM + + USTORM_AGG_DATA_OFFSET + i * 4, 0); + if (!CHIP_IS_E1x(bp)) { + REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_IGU_MODE_OFFSET, + CHIP_INT_MODE_IS_BC(bp) ? + HC_IGU_BC_MODE : HC_IGU_NBC_MODE); + } +} + +static void bnx2x_init_internal(struct bnx2x *bp, u32 load_code) +{ + switch (load_code) { + case FW_MSG_CODE_DRV_LOAD_COMMON: + case FW_MSG_CODE_DRV_LOAD_COMMON_CHIP: + bnx2x_init_internal_common(bp); + /* no break */ + + case FW_MSG_CODE_DRV_LOAD_PORT: + /* nothing to do */ + /* no break */ + + case FW_MSG_CODE_DRV_LOAD_FUNCTION: + /* internal memory per function is + initialized inside bnx2x_pf_init */ + break; + + default: + BNX2X_ERR("Unknown load_code (0x%x) from MCP\n", load_code); + break; + } +} + +static inline u8 bnx2x_fp_igu_sb_id(struct bnx2x_fastpath *fp) +{ + return fp->bp->igu_base_sb + fp->index + CNIC_PRESENT; +} + +static inline u8 bnx2x_fp_fw_sb_id(struct bnx2x_fastpath *fp) +{ + return fp->bp->base_fw_ndsb + fp->index + CNIC_PRESENT; +} + +static inline u8 bnx2x_fp_cl_id(struct bnx2x_fastpath *fp) +{ + if (CHIP_IS_E1x(fp->bp)) + return BP_L_ID(fp->bp) + fp->index; + else /* We want Client ID to be the same as IGU SB ID for 57712 */ + return bnx2x_fp_igu_sb_id(fp); +} + +static void bnx2x_init_eth_fp(struct bnx2x *bp, int fp_idx) +{ + struct bnx2x_fastpath *fp = &bp->fp[fp_idx]; + u8 cos; + unsigned long q_type = 0; + u32 cids[BNX2X_MULTI_TX_COS] = { 0 }; + + fp->cid = fp_idx; + fp->cl_id = bnx2x_fp_cl_id(fp); + fp->fw_sb_id = bnx2x_fp_fw_sb_id(fp); + fp->igu_sb_id = bnx2x_fp_igu_sb_id(fp); + /* qZone id equals to FW (per path) client id */ + fp->cl_qzone_id = bnx2x_fp_qzone_id(fp); + + /* init shortcut */ + fp->ustorm_rx_prods_offset = bnx2x_rx_ustorm_prods_offset(fp); + /* Setup SB indicies */ + fp->rx_cons_sb = BNX2X_RX_SB_INDEX; + + /* Configure Queue State object */ + __set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type); + __set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type); + + BUG_ON(fp->max_cos > BNX2X_MULTI_TX_COS); + + /* init tx data */ + for_each_cos_in_tx_queue(fp, cos) { + bnx2x_init_txdata(bp, &fp->txdata[cos], + CID_COS_TO_TX_ONLY_CID(fp->cid, cos), + FP_COS_TO_TXQ(fp, cos), + BNX2X_TX_SB_INDEX_BASE + cos); + cids[cos] = fp->txdata[cos].cid; + } + + bnx2x_init_queue_obj(bp, &fp->q_obj, fp->cl_id, cids, fp->max_cos, + BP_FUNC(bp), bnx2x_sp(bp, q_rdata), + bnx2x_sp_mapping(bp, q_rdata), q_type); + + /** + * Configure classification DBs: Always enable Tx switching + */ + bnx2x_init_vlan_mac_fp_objs(fp, BNX2X_OBJ_TYPE_RX_TX); + + DP(NETIF_MSG_IFUP, "queue[%d]: bnx2x_init_sb(%p,%p) " + "cl_id %d fw_sb %d igu_sb %d\n", + fp_idx, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id, + fp->igu_sb_id); + bnx2x_init_sb(bp, fp->status_blk_mapping, BNX2X_VF_ID_INVALID, false, + fp->fw_sb_id, fp->igu_sb_id); + + bnx2x_update_fpsb_idx(fp); +} + +void bnx2x_nic_init(struct bnx2x *bp, u32 load_code) +{ + int i; + + for_each_eth_queue(bp, i) + bnx2x_init_eth_fp(bp, i); +#ifdef BCM_CNIC + if (!NO_FCOE(bp)) + bnx2x_init_fcoe_fp(bp); + + bnx2x_init_sb(bp, bp->cnic_sb_mapping, + BNX2X_VF_ID_INVALID, false, + bnx2x_cnic_fw_sb_id(bp), bnx2x_cnic_igu_sb_id(bp)); + +#endif + + /* Initialize MOD_ABS interrupts */ + bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id, + bp->common.shmem_base, bp->common.shmem2_base, + BP_PORT(bp)); + /* ensure status block indices were read */ + rmb(); + + bnx2x_init_def_sb(bp); + bnx2x_update_dsb_idx(bp); + bnx2x_init_rx_rings(bp); + bnx2x_init_tx_rings(bp); + bnx2x_init_sp_ring(bp); + bnx2x_init_eq_ring(bp); + bnx2x_init_internal(bp, load_code); + bnx2x_pf_init(bp); + bnx2x_stats_init(bp); + + /* flush all before enabling interrupts */ + mb(); + mmiowb(); + + bnx2x_int_enable(bp); + + /* Check for SPIO5 */ + bnx2x_attn_int_deasserted0(bp, + REG_RD(bp, MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 + BP_PORT(bp)*4) & + AEU_INPUTS_ATTN_BITS_SPIO5); +} + +/* end of nic init */ + +/* + * gzip service functions + */ + +static int bnx2x_gunzip_init(struct bnx2x *bp) +{ + bp->gunzip_buf = dma_alloc_coherent(&bp->pdev->dev, FW_BUF_SIZE, + &bp->gunzip_mapping, GFP_KERNEL); + if (bp->gunzip_buf == NULL) + goto gunzip_nomem1; + + bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL); + if (bp->strm == NULL) + goto gunzip_nomem2; + + bp->strm->workspace = vmalloc(zlib_inflate_workspacesize()); + if (bp->strm->workspace == NULL) + goto gunzip_nomem3; + + return 0; + +gunzip_nomem3: + kfree(bp->strm); + bp->strm = NULL; + +gunzip_nomem2: + dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf, + bp->gunzip_mapping); + bp->gunzip_buf = NULL; + +gunzip_nomem1: + netdev_err(bp->dev, "Cannot allocate firmware buffer for" + " un-compression\n"); + return -ENOMEM; +} + +static void bnx2x_gunzip_end(struct bnx2x *bp) +{ + if (bp->strm) { + vfree(bp->strm->workspace); + kfree(bp->strm); + bp->strm = NULL; + } + + if (bp->gunzip_buf) { + dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf, + bp->gunzip_mapping); + bp->gunzip_buf = NULL; + } +} + +static int bnx2x_gunzip(struct bnx2x *bp, const u8 *zbuf, int len) +{ + int n, rc; + + /* check gzip header */ + if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED)) { + BNX2X_ERR("Bad gzip header\n"); + return -EINVAL; + } + + n = 10; + +#define FNAME 0x8 + + if (zbuf[3] & FNAME) + while ((zbuf[n++] != 0) && (n < len)); + + bp->strm->next_in = (typeof(bp->strm->next_in))zbuf + n; + bp->strm->avail_in = len - n; + bp->strm->next_out = bp->gunzip_buf; + bp->strm->avail_out = FW_BUF_SIZE; + + rc = zlib_inflateInit2(bp->strm, -MAX_WBITS); + if (rc != Z_OK) + return rc; + + rc = zlib_inflate(bp->strm, Z_FINISH); + if ((rc != Z_OK) && (rc != Z_STREAM_END)) + netdev_err(bp->dev, "Firmware decompression error: %s\n", + bp->strm->msg); + + bp->gunzip_outlen = (FW_BUF_SIZE - bp->strm->avail_out); + if (bp->gunzip_outlen & 0x3) + netdev_err(bp->dev, "Firmware decompression error:" + " gunzip_outlen (%d) not aligned\n", + bp->gunzip_outlen); + bp->gunzip_outlen >>= 2; + + zlib_inflateEnd(bp->strm); + + if (rc == Z_STREAM_END) + return 0; + + return rc; +} + +/* nic load/unload */ + +/* + * General service functions + */ + +/* send a NIG loopback debug packet */ +static void bnx2x_lb_pckt(struct bnx2x *bp) +{ + u32 wb_write[3]; + + /* Ethernet source and destination addresses */ + wb_write[0] = 0x55555555; + wb_write[1] = 0x55555555; + wb_write[2] = 0x20; /* SOP */ + REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3); + + /* NON-IP protocol */ + wb_write[0] = 0x09000000; + wb_write[1] = 0x55555555; + wb_write[2] = 0x10; /* EOP, eop_bvalid = 0 */ + REG_WR_DMAE(bp, NIG_REG_DEBUG_PACKET_LB, wb_write, 3); +} + +/* some of the internal memories + * are not directly readable from the driver + * to test them we send debug packets + */ +static int bnx2x_int_mem_test(struct bnx2x *bp) +{ + int factor; + int count, i; + u32 val = 0; + + if (CHIP_REV_IS_FPGA(bp)) + factor = 120; + else if (CHIP_REV_IS_EMUL(bp)) + factor = 200; + else + factor = 1; + + /* Disable inputs of parser neighbor blocks */ + REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0); + REG_WR(bp, TCM_REG_PRS_IFEN, 0x0); + REG_WR(bp, CFC_REG_DEBUG0, 0x1); + REG_WR(bp, NIG_REG_PRS_REQ_IN_EN, 0x0); + + /* Write 0 to parser credits for CFC search request */ + REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0); + + /* send Ethernet packet */ + bnx2x_lb_pckt(bp); + + /* TODO do i reset NIG statistic? */ + /* Wait until NIG register shows 1 packet of size 0x10 */ + count = 1000 * factor; + while (count) { + + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); + val = *bnx2x_sp(bp, wb_data[0]); + if (val == 0x10) + break; + + msleep(10); + count--; + } + if (val != 0x10) { + BNX2X_ERR("NIG timeout val = 0x%x\n", val); + return -1; + } + + /* Wait until PRS register shows 1 packet */ + count = 1000 * factor; + while (count) { + val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); + if (val == 1) + break; + + msleep(10); + count--; + } + if (val != 0x1) { + BNX2X_ERR("PRS timeout val = 0x%x\n", val); + return -2; + } + + /* Reset and init BRB, PRS */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03); + msleep(50); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03); + msleep(50); + bnx2x_init_block(bp, BLOCK_BRB1, PHASE_COMMON); + bnx2x_init_block(bp, BLOCK_PRS, PHASE_COMMON); + + DP(NETIF_MSG_HW, "part2\n"); + + /* Disable inputs of parser neighbor blocks */ + REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x0); + REG_WR(bp, TCM_REG_PRS_IFEN, 0x0); + REG_WR(bp, CFC_REG_DEBUG0, 0x1); + REG_WR(bp, NIG_REG_PRS_REQ_IN_EN, 0x0); + + /* Write 0 to parser credits for CFC search request */ + REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x0); + + /* send 10 Ethernet packets */ + for (i = 0; i < 10; i++) + bnx2x_lb_pckt(bp); + + /* Wait until NIG register shows 10 + 1 + packets of size 11*0x10 = 0xb0 */ + count = 1000 * factor; + while (count) { + + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); + val = *bnx2x_sp(bp, wb_data[0]); + if (val == 0xb0) + break; + + msleep(10); + count--; + } + if (val != 0xb0) { + BNX2X_ERR("NIG timeout val = 0x%x\n", val); + return -3; + } + + /* Wait until PRS register shows 2 packets */ + val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); + if (val != 2) + BNX2X_ERR("PRS timeout val = 0x%x\n", val); + + /* Write 1 to parser credits for CFC search request */ + REG_WR(bp, PRS_REG_CFC_SEARCH_INITIAL_CREDIT, 0x1); + + /* Wait until PRS register shows 3 packets */ + msleep(10 * factor); + /* Wait until NIG register shows 1 packet of size 0x10 */ + val = REG_RD(bp, PRS_REG_NUM_OF_PACKETS); + if (val != 3) + BNX2X_ERR("PRS timeout val = 0x%x\n", val); + + /* clear NIG EOP FIFO */ + for (i = 0; i < 11; i++) + REG_RD(bp, NIG_REG_INGRESS_EOP_LB_FIFO); + val = REG_RD(bp, NIG_REG_INGRESS_EOP_LB_EMPTY); + if (val != 1) { + BNX2X_ERR("clear of NIG failed\n"); + return -4; + } + + /* Reset and init BRB, PRS, NIG */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, 0x03); + msleep(50); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0x03); + msleep(50); + bnx2x_init_block(bp, BLOCK_BRB1, PHASE_COMMON); + bnx2x_init_block(bp, BLOCK_PRS, PHASE_COMMON); +#ifndef BCM_CNIC + /* set NIC mode */ + REG_WR(bp, PRS_REG_NIC_MODE, 1); +#endif + + /* Enable inputs of parser neighbor blocks */ + REG_WR(bp, TSDM_REG_ENABLE_IN1, 0x7fffffff); + REG_WR(bp, TCM_REG_PRS_IFEN, 0x1); + REG_WR(bp, CFC_REG_DEBUG0, 0x0); + REG_WR(bp, NIG_REG_PRS_REQ_IN_EN, 0x1); + + DP(NETIF_MSG_HW, "done\n"); + + return 0; /* OK */ +} + +static void bnx2x_enable_blocks_attention(struct bnx2x *bp) +{ + REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0); + if (!CHIP_IS_E1x(bp)) + REG_WR(bp, PXP_REG_PXP_INT_MASK_1, 0x40); + else + REG_WR(bp, PXP_REG_PXP_INT_MASK_1, 0); + REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0); + REG_WR(bp, CFC_REG_CFC_INT_MASK, 0); + /* + * mask read length error interrupts in brb for parser + * (parsing unit and 'checksum and crc' unit) + * these errors are legal (PU reads fixed length and CAC can cause + * read length error on truncated packets) + */ + REG_WR(bp, BRB1_REG_BRB1_INT_MASK, 0xFC00); + REG_WR(bp, QM_REG_QM_INT_MASK, 0); + REG_WR(bp, TM_REG_TM_INT_MASK, 0); + REG_WR(bp, XSDM_REG_XSDM_INT_MASK_0, 0); + REG_WR(bp, XSDM_REG_XSDM_INT_MASK_1, 0); + REG_WR(bp, XCM_REG_XCM_INT_MASK, 0); +/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_0, 0); */ +/* REG_WR(bp, XSEM_REG_XSEM_INT_MASK_1, 0); */ + REG_WR(bp, USDM_REG_USDM_INT_MASK_0, 0); + REG_WR(bp, USDM_REG_USDM_INT_MASK_1, 0); + REG_WR(bp, UCM_REG_UCM_INT_MASK, 0); +/* REG_WR(bp, USEM_REG_USEM_INT_MASK_0, 0); */ +/* REG_WR(bp, USEM_REG_USEM_INT_MASK_1, 0); */ + REG_WR(bp, GRCBASE_UPB + PB_REG_PB_INT_MASK, 0); + REG_WR(bp, CSDM_REG_CSDM_INT_MASK_0, 0); + REG_WR(bp, CSDM_REG_CSDM_INT_MASK_1, 0); + REG_WR(bp, CCM_REG_CCM_INT_MASK, 0); +/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_0, 0); */ +/* REG_WR(bp, CSEM_REG_CSEM_INT_MASK_1, 0); */ + + if (CHIP_REV_IS_FPGA(bp)) + REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x580000); + else if (!CHIP_IS_E1x(bp)) + REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, + (PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_OF + | PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_AFT + | PXP2_PXP2_INT_MASK_0_REG_PGL_PCIE_ATTN + | PXP2_PXP2_INT_MASK_0_REG_PGL_READ_BLOCKED + | PXP2_PXP2_INT_MASK_0_REG_PGL_WRITE_BLOCKED)); + else + REG_WR(bp, PXP2_REG_PXP2_INT_MASK_0, 0x480000); + REG_WR(bp, TSDM_REG_TSDM_INT_MASK_0, 0); + REG_WR(bp, TSDM_REG_TSDM_INT_MASK_1, 0); + REG_WR(bp, TCM_REG_TCM_INT_MASK, 0); +/* REG_WR(bp, TSEM_REG_TSEM_INT_MASK_0, 0); */ + + if (!CHIP_IS_E1x(bp)) + /* enable VFC attentions: bits 11 and 12, bits 31:13 reserved */ + REG_WR(bp, TSEM_REG_TSEM_INT_MASK_1, 0x07ff); + + REG_WR(bp, CDU_REG_CDU_INT_MASK, 0); + REG_WR(bp, DMAE_REG_DMAE_INT_MASK, 0); +/* REG_WR(bp, MISC_REG_MISC_INT_MASK, 0); */ + REG_WR(bp, PBF_REG_PBF_INT_MASK, 0x18); /* bit 3,4 masked */ +} + +static void bnx2x_reset_common(struct bnx2x *bp) +{ + u32 val = 0x1400; + + /* reset_common */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + 0xd3ffff7f); + + if (CHIP_IS_E3(bp)) { + val |= MISC_REGISTERS_RESET_REG_2_MSTAT0; + val |= MISC_REGISTERS_RESET_REG_2_MSTAT1; + } + + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, val); +} + +static void bnx2x_setup_dmae(struct bnx2x *bp) +{ + bp->dmae_ready = 0; + spin_lock_init(&bp->dmae_lock); +} + +static void bnx2x_init_pxp(struct bnx2x *bp) +{ + u16 devctl; + int r_order, w_order; + + pci_read_config_word(bp->pdev, + pci_pcie_cap(bp->pdev) + PCI_EXP_DEVCTL, &devctl); + DP(NETIF_MSG_HW, "read 0x%x from devctl\n", devctl); + w_order = ((devctl & PCI_EXP_DEVCTL_PAYLOAD) >> 5); + if (bp->mrrs == -1) + r_order = ((devctl & PCI_EXP_DEVCTL_READRQ) >> 12); + else { + DP(NETIF_MSG_HW, "force read order to %d\n", bp->mrrs); + r_order = bp->mrrs; + } + + bnx2x_init_pxp_arb(bp, r_order, w_order); +} + +static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp) +{ + int is_required; + u32 val; + int port; + + if (BP_NOMCP(bp)) + return; + + is_required = 0; + val = SHMEM_RD(bp, dev_info.shared_hw_config.config2) & + SHARED_HW_CFG_FAN_FAILURE_MASK; + + if (val == SHARED_HW_CFG_FAN_FAILURE_ENABLED) + is_required = 1; + + /* + * The fan failure mechanism is usually related to the PHY type since + * the power consumption of the board is affected by the PHY. Currently, + * fan is required for most designs with SFX7101, BCM8727 and BCM8481. + */ + else if (val == SHARED_HW_CFG_FAN_FAILURE_PHY_TYPE) + for (port = PORT_0; port < PORT_MAX; port++) { + is_required |= + bnx2x_fan_failure_det_req( + bp, + bp->common.shmem_base, + bp->common.shmem2_base, + port); + } + + DP(NETIF_MSG_HW, "fan detection setting: %d\n", is_required); + + if (is_required == 0) + return; + + /* Fan failure is indicated by SPIO 5 */ + bnx2x_set_spio(bp, MISC_REGISTERS_SPIO_5, + MISC_REGISTERS_SPIO_INPUT_HI_Z); + + /* set to active low mode */ + val = REG_RD(bp, MISC_REG_SPIO_INT); + val |= ((1 << MISC_REGISTERS_SPIO_5) << + MISC_REGISTERS_SPIO_INT_OLD_SET_POS); + REG_WR(bp, MISC_REG_SPIO_INT, val); + + /* enable interrupt to signal the IGU */ + val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN); + val |= (1 << MISC_REGISTERS_SPIO_5); + REG_WR(bp, MISC_REG_SPIO_EVENT_EN, val); +} + +static void bnx2x_pretend_func(struct bnx2x *bp, u8 pretend_func_num) +{ + u32 offset = 0; + + if (CHIP_IS_E1(bp)) + return; + if (CHIP_IS_E1H(bp) && (pretend_func_num >= E1H_FUNC_MAX)) + return; + + switch (BP_ABS_FUNC(bp)) { + case 0: + offset = PXP2_REG_PGL_PRETEND_FUNC_F0; + break; + case 1: + offset = PXP2_REG_PGL_PRETEND_FUNC_F1; + break; + case 2: + offset = PXP2_REG_PGL_PRETEND_FUNC_F2; + break; + case 3: + offset = PXP2_REG_PGL_PRETEND_FUNC_F3; + break; + case 4: + offset = PXP2_REG_PGL_PRETEND_FUNC_F4; + break; + case 5: + offset = PXP2_REG_PGL_PRETEND_FUNC_F5; + break; + case 6: + offset = PXP2_REG_PGL_PRETEND_FUNC_F6; + break; + case 7: + offset = PXP2_REG_PGL_PRETEND_FUNC_F7; + break; + default: + return; + } + + REG_WR(bp, offset, pretend_func_num); + REG_RD(bp, offset); + DP(NETIF_MSG_HW, "Pretending to func %d\n", pretend_func_num); +} + +void bnx2x_pf_disable(struct bnx2x *bp) +{ + u32 val = REG_RD(bp, IGU_REG_PF_CONFIGURATION); + val &= ~IGU_PF_CONF_FUNC_EN; + + REG_WR(bp, IGU_REG_PF_CONFIGURATION, val); + REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, 0); + REG_WR(bp, CFC_REG_WEAK_ENABLE_PF, 0); +} + +static inline void bnx2x__common_init_phy(struct bnx2x *bp) +{ + u32 shmem_base[2], shmem2_base[2]; + shmem_base[0] = bp->common.shmem_base; + shmem2_base[0] = bp->common.shmem2_base; + if (!CHIP_IS_E1x(bp)) { + shmem_base[1] = + SHMEM2_RD(bp, other_shmem_base_addr); + shmem2_base[1] = + SHMEM2_RD(bp, other_shmem2_base_addr); + } + bnx2x_acquire_phy_lock(bp); + bnx2x_common_init_phy(bp, shmem_base, shmem2_base, + bp->common.chip_id); + bnx2x_release_phy_lock(bp); +} + +/** + * bnx2x_init_hw_common - initialize the HW at the COMMON phase. + * + * @bp: driver handle + */ +static int bnx2x_init_hw_common(struct bnx2x *bp) +{ + u32 val; + + DP(BNX2X_MSG_MCP, "starting common init func %d\n", BP_ABS_FUNC(bp)); + + bnx2x_reset_common(bp); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, 0xffffffff); + + val = 0xfffc; + if (CHIP_IS_E3(bp)) { + val |= MISC_REGISTERS_RESET_REG_2_MSTAT0; + val |= MISC_REGISTERS_RESET_REG_2_MSTAT1; + } + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, val); + + bnx2x_init_block(bp, BLOCK_MISC, PHASE_COMMON); + + if (!CHIP_IS_E1x(bp)) { + u8 abs_func_id; + + /** + * 4-port mode or 2-port mode we need to turn of master-enable + * for everyone, after that, turn it back on for self. + * so, we disregard multi-function or not, and always disable + * for all functions on the given path, this means 0,2,4,6 for + * path 0 and 1,3,5,7 for path 1 + */ + for (abs_func_id = BP_PATH(bp); + abs_func_id < E2_FUNC_MAX*2; abs_func_id += 2) { + if (abs_func_id == BP_ABS_FUNC(bp)) { + REG_WR(bp, + PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, + 1); + continue; + } + + bnx2x_pretend_func(bp, abs_func_id); + /* clear pf enable */ + bnx2x_pf_disable(bp); + bnx2x_pretend_func(bp, BP_ABS_FUNC(bp)); + } + } + + bnx2x_init_block(bp, BLOCK_PXP, PHASE_COMMON); + if (CHIP_IS_E1(bp)) { + /* enable HW interrupt from PXP on USDM overflow + bit 16 on INT_MASK_0 */ + REG_WR(bp, PXP_REG_PXP_INT_MASK_0, 0); + } + + bnx2x_init_block(bp, BLOCK_PXP2, PHASE_COMMON); + bnx2x_init_pxp(bp); + +#ifdef __BIG_ENDIAN + REG_WR(bp, PXP2_REG_RQ_QM_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_TM_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_SRC_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_CDU_ENDIAN_M, 1); + REG_WR(bp, PXP2_REG_RQ_DBG_ENDIAN_M, 1); + /* make sure this value is 0 */ + REG_WR(bp, PXP2_REG_RQ_HC_ENDIAN_M, 0); + +/* REG_WR(bp, PXP2_REG_RD_PBF_SWAP_MODE, 1); */ + REG_WR(bp, PXP2_REG_RD_QM_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_TM_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_SRC_SWAP_MODE, 1); + REG_WR(bp, PXP2_REG_RD_CDURD_SWAP_MODE, 1); +#endif + + bnx2x_ilt_init_page_size(bp, INITOP_SET); + + if (CHIP_REV_IS_FPGA(bp) && CHIP_IS_E1H(bp)) + REG_WR(bp, PXP2_REG_PGL_TAGS_LIMIT, 0x1); + + /* let the HW do it's magic ... */ + msleep(100); + /* finish PXP init */ + val = REG_RD(bp, PXP2_REG_RQ_CFG_DONE); + if (val != 1) { + BNX2X_ERR("PXP2 CFG failed\n"); + return -EBUSY; + } + val = REG_RD(bp, PXP2_REG_RD_INIT_DONE); + if (val != 1) { + BNX2X_ERR("PXP2 RD_INIT failed\n"); + return -EBUSY; + } + + /* Timers bug workaround E2 only. We need to set the entire ILT to + * have entries with value "0" and valid bit on. + * This needs to be done by the first PF that is loaded in a path + * (i.e. common phase) + */ + if (!CHIP_IS_E1x(bp)) { +/* In E2 there is a bug in the timers block that can cause function 6 / 7 + * (i.e. vnic3) to start even if it is marked as "scan-off". + * This occurs when a different function (func2,3) is being marked + * as "scan-off". Real-life scenario for example: if a driver is being + * load-unloaded while func6,7 are down. This will cause the timer to access + * the ilt, translate to a logical address and send a request to read/write. + * Since the ilt for the function that is down is not valid, this will cause + * a translation error which is unrecoverable. + * The Workaround is intended to make sure that when this happens nothing fatal + * will occur. The workaround: + * 1. First PF driver which loads on a path will: + * a. After taking the chip out of reset, by using pretend, + * it will write "0" to the following registers of + * the other vnics. + * REG_WR(pdev, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, 0); + * REG_WR(pdev, CFC_REG_WEAK_ENABLE_PF,0); + * REG_WR(pdev, CFC_REG_STRONG_ENABLE_PF,0); + * And for itself it will write '1' to + * PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER to enable + * dmae-operations (writing to pram for example.) + * note: can be done for only function 6,7 but cleaner this + * way. + * b. Write zero+valid to the entire ILT. + * c. Init the first_timers_ilt_entry, last_timers_ilt_entry of + * VNIC3 (of that port). The range allocated will be the + * entire ILT. This is needed to prevent ILT range error. + * 2. Any PF driver load flow: + * a. ILT update with the physical addresses of the allocated + * logical pages. + * b. Wait 20msec. - note that this timeout is needed to make + * sure there are no requests in one of the PXP internal + * queues with "old" ILT addresses. + * c. PF enable in the PGLC. + * d. Clear the was_error of the PF in the PGLC. (could have + * occured while driver was down) + * e. PF enable in the CFC (WEAK + STRONG) + * f. Timers scan enable + * 3. PF driver unload flow: + * a. Clear the Timers scan_en. + * b. Polling for scan_on=0 for that PF. + * c. Clear the PF enable bit in the PXP. + * d. Clear the PF enable in the CFC (WEAK + STRONG) + * e. Write zero+valid to all ILT entries (The valid bit must + * stay set) + * f. If this is VNIC 3 of a port then also init + * first_timers_ilt_entry to zero and last_timers_ilt_entry + * to the last enrty in the ILT. + * + * Notes: + * Currently the PF error in the PGLC is non recoverable. + * In the future the there will be a recovery routine for this error. + * Currently attention is masked. + * Having an MCP lock on the load/unload process does not guarantee that + * there is no Timer disable during Func6/7 enable. This is because the + * Timers scan is currently being cleared by the MCP on FLR. + * Step 2.d can be done only for PF6/7 and the driver can also check if + * there is error before clearing it. But the flow above is simpler and + * more general. + * All ILT entries are written by zero+valid and not just PF6/7 + * ILT entries since in the future the ILT entries allocation for + * PF-s might be dynamic. + */ + struct ilt_client_info ilt_cli; + struct bnx2x_ilt ilt; + memset(&ilt_cli, 0, sizeof(struct ilt_client_info)); + memset(&ilt, 0, sizeof(struct bnx2x_ilt)); + + /* initialize dummy TM client */ + ilt_cli.start = 0; + ilt_cli.end = ILT_NUM_PAGE_ENTRIES - 1; + ilt_cli.client_num = ILT_CLIENT_TM; + + /* Step 1: set zeroes to all ilt page entries with valid bit on + * Step 2: set the timers first/last ilt entry to point + * to the entire range to prevent ILT range error for 3rd/4th + * vnic (this code assumes existance of the vnic) + * + * both steps performed by call to bnx2x_ilt_client_init_op() + * with dummy TM client + * + * we must use pretend since PXP2_REG_RQ_##blk##_FIRST_ILT + * and his brother are split registers + */ + bnx2x_pretend_func(bp, (BP_PATH(bp) + 6)); + bnx2x_ilt_client_init_op_ilt(bp, &ilt, &ilt_cli, INITOP_CLEAR); + bnx2x_pretend_func(bp, BP_ABS_FUNC(bp)); + + REG_WR(bp, PXP2_REG_RQ_DRAM_ALIGN, BNX2X_PXP_DRAM_ALIGN); + REG_WR(bp, PXP2_REG_RQ_DRAM_ALIGN_RD, BNX2X_PXP_DRAM_ALIGN); + REG_WR(bp, PXP2_REG_RQ_DRAM_ALIGN_SEL, 1); + } + + + REG_WR(bp, PXP2_REG_RQ_DISABLE_INPUTS, 0); + REG_WR(bp, PXP2_REG_RD_DISABLE_INPUTS, 0); + + if (!CHIP_IS_E1x(bp)) { + int factor = CHIP_REV_IS_EMUL(bp) ? 1000 : + (CHIP_REV_IS_FPGA(bp) ? 400 : 0); + bnx2x_init_block(bp, BLOCK_PGLUE_B, PHASE_COMMON); + + bnx2x_init_block(bp, BLOCK_ATC, PHASE_COMMON); + + /* let the HW do it's magic ... */ + do { + msleep(200); + val = REG_RD(bp, ATC_REG_ATC_INIT_DONE); + } while (factor-- && (val != 1)); + + if (val != 1) { + BNX2X_ERR("ATC_INIT failed\n"); + return -EBUSY; + } + } + + bnx2x_init_block(bp, BLOCK_DMAE, PHASE_COMMON); + + /* clean the DMAE memory */ + bp->dmae_ready = 1; + bnx2x_init_fill(bp, TSEM_REG_PRAM, 0, 8, 1); + + bnx2x_init_block(bp, BLOCK_TCM, PHASE_COMMON); + + bnx2x_init_block(bp, BLOCK_UCM, PHASE_COMMON); + + bnx2x_init_block(bp, BLOCK_CCM, PHASE_COMMON); + + bnx2x_init_block(bp, BLOCK_XCM, PHASE_COMMON); + + bnx2x_read_dmae(bp, XSEM_REG_PASSIVE_BUFFER, 3); + bnx2x_read_dmae(bp, CSEM_REG_PASSIVE_BUFFER, 3); + bnx2x_read_dmae(bp, TSEM_REG_PASSIVE_BUFFER, 3); + bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3); + + bnx2x_init_block(bp, BLOCK_QM, PHASE_COMMON); + + + /* QM queues pointers table */ + bnx2x_qm_init_ptr_table(bp, bp->qm_cid_count, INITOP_SET); + + /* soft reset pulse */ + REG_WR(bp, QM_REG_SOFT_RESET, 1); + REG_WR(bp, QM_REG_SOFT_RESET, 0); + +#ifdef BCM_CNIC + bnx2x_init_block(bp, BLOCK_TM, PHASE_COMMON); +#endif + + bnx2x_init_block(bp, BLOCK_DORQ, PHASE_COMMON); + REG_WR(bp, DORQ_REG_DPM_CID_OFST, BNX2X_DB_SHIFT); + if (!CHIP_REV_IS_SLOW(bp)) + /* enable hw interrupt from doorbell Q */ + REG_WR(bp, DORQ_REG_DORQ_INT_MASK, 0); + + bnx2x_init_block(bp, BLOCK_BRB1, PHASE_COMMON); + + bnx2x_init_block(bp, BLOCK_PRS, PHASE_COMMON); + REG_WR(bp, PRS_REG_A_PRSU_20, 0xf); + + if (!CHIP_IS_E1(bp)) + REG_WR(bp, PRS_REG_E1HOV_MODE, bp->path_has_ovlan); + + if (!CHIP_IS_E1x(bp) && !CHIP_IS_E3B0(bp)) + /* Bit-map indicating which L2 hdrs may appear + * after the basic Ethernet header + */ + REG_WR(bp, PRS_REG_HDRS_AFTER_BASIC, + bp->path_has_ovlan ? 7 : 6); + + bnx2x_init_block(bp, BLOCK_TSDM, PHASE_COMMON); + bnx2x_init_block(bp, BLOCK_CSDM, PHASE_COMMON); + bnx2x_init_block(bp, BLOCK_USDM, PHASE_COMMON); + bnx2x_init_block(bp, BLOCK_XSDM, PHASE_COMMON); + + if (!CHIP_IS_E1x(bp)) { + /* reset VFC memories */ + REG_WR(bp, TSEM_REG_FAST_MEMORY + VFC_REG_MEMORIES_RST, + VFC_MEMORIES_RST_REG_CAM_RST | + VFC_MEMORIES_RST_REG_RAM_RST); + REG_WR(bp, XSEM_REG_FAST_MEMORY + VFC_REG_MEMORIES_RST, + VFC_MEMORIES_RST_REG_CAM_RST | + VFC_MEMORIES_RST_REG_RAM_RST); + + msleep(20); + } + + bnx2x_init_block(bp, BLOCK_TSEM, PHASE_COMMON); + bnx2x_init_block(bp, BLOCK_USEM, PHASE_COMMON); + bnx2x_init_block(bp, BLOCK_CSEM, PHASE_COMMON); + bnx2x_init_block(bp, BLOCK_XSEM, PHASE_COMMON); + + /* sync semi rtc */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + 0x80000000); + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, + 0x80000000); + + bnx2x_init_block(bp, BLOCK_UPB, PHASE_COMMON); + bnx2x_init_block(bp, BLOCK_XPB, PHASE_COMMON); + bnx2x_init_block(bp, BLOCK_PBF, PHASE_COMMON); + + if (!CHIP_IS_E1x(bp)) + REG_WR(bp, PBF_REG_HDRS_AFTER_BASIC, + bp->path_has_ovlan ? 7 : 6); + + REG_WR(bp, SRC_REG_SOFT_RST, 1); + + bnx2x_init_block(bp, BLOCK_SRC, PHASE_COMMON); + +#ifdef BCM_CNIC + REG_WR(bp, SRC_REG_KEYSEARCH_0, 0x63285672); + REG_WR(bp, SRC_REG_KEYSEARCH_1, 0x24b8f2cc); + REG_WR(bp, SRC_REG_KEYSEARCH_2, 0x223aef9b); + REG_WR(bp, SRC_REG_KEYSEARCH_3, 0x26001e3a); + REG_WR(bp, SRC_REG_KEYSEARCH_4, 0x7ae91116); + REG_WR(bp, SRC_REG_KEYSEARCH_5, 0x5ce5230b); + REG_WR(bp, SRC_REG_KEYSEARCH_6, 0x298d8adf); + REG_WR(bp, SRC_REG_KEYSEARCH_7, 0x6eb0ff09); + REG_WR(bp, SRC_REG_KEYSEARCH_8, 0x1830f82f); + REG_WR(bp, SRC_REG_KEYSEARCH_9, 0x01e46be7); +#endif + REG_WR(bp, SRC_REG_SOFT_RST, 0); + + if (sizeof(union cdu_context) != 1024) + /* we currently assume that a context is 1024 bytes */ + dev_alert(&bp->pdev->dev, "please adjust the size " + "of cdu_context(%ld)\n", + (long)sizeof(union cdu_context)); + + bnx2x_init_block(bp, BLOCK_CDU, PHASE_COMMON); + val = (4 << 24) + (0 << 12) + 1024; + REG_WR(bp, CDU_REG_CDU_GLOBAL_PARAMS, val); + + bnx2x_init_block(bp, BLOCK_CFC, PHASE_COMMON); + REG_WR(bp, CFC_REG_INIT_REG, 0x7FF); + /* enable context validation interrupt from CFC */ + REG_WR(bp, CFC_REG_CFC_INT_MASK, 0); + + /* set the thresholds to prevent CFC/CDU race */ + REG_WR(bp, CFC_REG_DEBUG0, 0x20020000); + + bnx2x_init_block(bp, BLOCK_HC, PHASE_COMMON); + + if (!CHIP_IS_E1x(bp) && BP_NOMCP(bp)) + REG_WR(bp, IGU_REG_RESET_MEMORIES, 0x36); + + bnx2x_init_block(bp, BLOCK_IGU, PHASE_COMMON); + bnx2x_init_block(bp, BLOCK_MISC_AEU, PHASE_COMMON); + + /* Reset PCIE errors for debug */ + REG_WR(bp, 0x2814, 0xffffffff); + REG_WR(bp, 0x3820, 0xffffffff); + + if (!CHIP_IS_E1x(bp)) { + REG_WR(bp, PCICFG_OFFSET + PXPCS_TL_CONTROL_5, + (PXPCS_TL_CONTROL_5_ERR_UNSPPORT1 | + PXPCS_TL_CONTROL_5_ERR_UNSPPORT)); + REG_WR(bp, PCICFG_OFFSET + PXPCS_TL_FUNC345_STAT, + (PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT4 | + PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT3 | + PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT2)); + REG_WR(bp, PCICFG_OFFSET + PXPCS_TL_FUNC678_STAT, + (PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT7 | + PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT6 | + PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT5)); + } + + bnx2x_init_block(bp, BLOCK_NIG, PHASE_COMMON); + if (!CHIP_IS_E1(bp)) { + /* in E3 this done in per-port section */ + if (!CHIP_IS_E3(bp)) + REG_WR(bp, NIG_REG_LLH_MF_MODE, IS_MF(bp)); + } + if (CHIP_IS_E1H(bp)) + /* not applicable for E2 (and above ...) */ + REG_WR(bp, NIG_REG_LLH_E1HOV_MODE, IS_MF_SD(bp)); + + if (CHIP_REV_IS_SLOW(bp)) + msleep(200); + + /* finish CFC init */ + val = reg_poll(bp, CFC_REG_LL_INIT_DONE, 1, 100, 10); + if (val != 1) { + BNX2X_ERR("CFC LL_INIT failed\n"); + return -EBUSY; + } + val = reg_poll(bp, CFC_REG_AC_INIT_DONE, 1, 100, 10); + if (val != 1) { + BNX2X_ERR("CFC AC_INIT failed\n"); + return -EBUSY; + } + val = reg_poll(bp, CFC_REG_CAM_INIT_DONE, 1, 100, 10); + if (val != 1) { + BNX2X_ERR("CFC CAM_INIT failed\n"); + return -EBUSY; + } + REG_WR(bp, CFC_REG_DEBUG0, 0); + + if (CHIP_IS_E1(bp)) { + /* read NIG statistic + to see if this is our first up since powerup */ + bnx2x_read_dmae(bp, NIG_REG_STAT2_BRB_OCTET, 2); + val = *bnx2x_sp(bp, wb_data[0]); + + /* do internal memory self test */ + if ((val == 0) && bnx2x_int_mem_test(bp)) { + BNX2X_ERR("internal mem self test failed\n"); + return -EBUSY; + } + } + + bnx2x_setup_fan_failure_detection(bp); + + /* clear PXP2 attentions */ + REG_RD(bp, PXP2_REG_PXP2_INT_STS_CLR_0); + + bnx2x_enable_blocks_attention(bp); + bnx2x_enable_blocks_parity(bp); + + if (!BP_NOMCP(bp)) { + if (CHIP_IS_E1x(bp)) + bnx2x__common_init_phy(bp); + } else + BNX2X_ERR("Bootcode is missing - can not initialize link\n"); + + return 0; +} + +/** + * bnx2x_init_hw_common_chip - init HW at the COMMON_CHIP phase. + * + * @bp: driver handle + */ +static int bnx2x_init_hw_common_chip(struct bnx2x *bp) +{ + int rc = bnx2x_init_hw_common(bp); + + if (rc) + return rc; + + /* In E2 2-PORT mode, same ext phy is used for the two paths */ + if (!BP_NOMCP(bp)) + bnx2x__common_init_phy(bp); + + return 0; +} + +static int bnx2x_init_hw_port(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int init_phase = port ? PHASE_PORT1 : PHASE_PORT0; + u32 low, high; + u32 val; + + bnx2x__link_reset(bp); + + DP(BNX2X_MSG_MCP, "starting port init port %d\n", port); + + REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0); + + bnx2x_init_block(bp, BLOCK_MISC, init_phase); + bnx2x_init_block(bp, BLOCK_PXP, init_phase); + bnx2x_init_block(bp, BLOCK_PXP2, init_phase); + + /* Timers bug workaround: disables the pf_master bit in pglue at + * common phase, we need to enable it here before any dmae access are + * attempted. Therefore we manually added the enable-master to the + * port phase (it also happens in the function phase) + */ + if (!CHIP_IS_E1x(bp)) + REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER, 1); + + bnx2x_init_block(bp, BLOCK_ATC, init_phase); + bnx2x_init_block(bp, BLOCK_DMAE, init_phase); + bnx2x_init_block(bp, BLOCK_PGLUE_B, init_phase); + bnx2x_init_block(bp, BLOCK_QM, init_phase); + + bnx2x_init_block(bp, BLOCK_TCM, init_phase); + bnx2x_init_block(bp, BLOCK_UCM, init_phase); + bnx2x_init_block(bp, BLOCK_CCM, init_phase); + bnx2x_init_block(bp, BLOCK_XCM, init_phase); + + /* QM cid (connection) count */ + bnx2x_qm_init_cid_count(bp, bp->qm_cid_count, INITOP_SET); + +#ifdef BCM_CNIC + bnx2x_init_block(bp, BLOCK_TM, init_phase); + REG_WR(bp, TM_REG_LIN0_SCAN_TIME + port*4, 20); + REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + port*4, 31); +#endif + + bnx2x_init_block(bp, BLOCK_DORQ, init_phase); + + if (CHIP_IS_E1(bp) || CHIP_IS_E1H(bp)) { + bnx2x_init_block(bp, BLOCK_BRB1, init_phase); + + if (IS_MF(bp)) + low = ((bp->flags & ONE_PORT_FLAG) ? 160 : 246); + else if (bp->dev->mtu > 4096) { + if (bp->flags & ONE_PORT_FLAG) + low = 160; + else { + val = bp->dev->mtu; + /* (24*1024 + val*4)/256 */ + low = 96 + (val/64) + + ((val % 64) ? 1 : 0); + } + } else + low = ((bp->flags & ONE_PORT_FLAG) ? 80 : 160); + high = low + 56; /* 14*1024/256 */ + REG_WR(bp, BRB1_REG_PAUSE_LOW_THRESHOLD_0 + port*4, low); + REG_WR(bp, BRB1_REG_PAUSE_HIGH_THRESHOLD_0 + port*4, high); + } + + if (CHIP_MODE_IS_4_PORT(bp)) + REG_WR(bp, (BP_PORT(bp) ? + BRB1_REG_MAC_GUARANTIED_1 : + BRB1_REG_MAC_GUARANTIED_0), 40); + + + bnx2x_init_block(bp, BLOCK_PRS, init_phase); + if (CHIP_IS_E3B0(bp)) + /* Ovlan exists only if we are in multi-function + + * switch-dependent mode, in switch-independent there + * is no ovlan headers + */ + REG_WR(bp, BP_PORT(bp) ? + PRS_REG_HDRS_AFTER_BASIC_PORT_1 : + PRS_REG_HDRS_AFTER_BASIC_PORT_0, + (bp->path_has_ovlan ? 7 : 6)); + + bnx2x_init_block(bp, BLOCK_TSDM, init_phase); + bnx2x_init_block(bp, BLOCK_CSDM, init_phase); + bnx2x_init_block(bp, BLOCK_USDM, init_phase); + bnx2x_init_block(bp, BLOCK_XSDM, init_phase); + + bnx2x_init_block(bp, BLOCK_TSEM, init_phase); + bnx2x_init_block(bp, BLOCK_USEM, init_phase); + bnx2x_init_block(bp, BLOCK_CSEM, init_phase); + bnx2x_init_block(bp, BLOCK_XSEM, init_phase); + + bnx2x_init_block(bp, BLOCK_UPB, init_phase); + bnx2x_init_block(bp, BLOCK_XPB, init_phase); + + bnx2x_init_block(bp, BLOCK_PBF, init_phase); + + if (CHIP_IS_E1x(bp)) { + /* configure PBF to work without PAUSE mtu 9000 */ + REG_WR(bp, PBF_REG_P0_PAUSE_ENABLE + port*4, 0); + + /* update threshold */ + REG_WR(bp, PBF_REG_P0_ARB_THRSH + port*4, (9040/16)); + /* update init credit */ + REG_WR(bp, PBF_REG_P0_INIT_CRD + port*4, (9040/16) + 553 - 22); + + /* probe changes */ + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 1); + udelay(50); + REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0); + } + +#ifdef BCM_CNIC + bnx2x_init_block(bp, BLOCK_SRC, init_phase); +#endif + bnx2x_init_block(bp, BLOCK_CDU, init_phase); + bnx2x_init_block(bp, BLOCK_CFC, init_phase); + + if (CHIP_IS_E1(bp)) { + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0); + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0); + } + bnx2x_init_block(bp, BLOCK_HC, init_phase); + + bnx2x_init_block(bp, BLOCK_IGU, init_phase); + + bnx2x_init_block(bp, BLOCK_MISC_AEU, init_phase); + /* init aeu_mask_attn_func_0/1: + * - SF mode: bits 3-7 are masked. only bits 0-2 are in use + * - MF mode: bit 3 is masked. bits 0-2 are in use as in SF + * bits 4-7 are used for "per vn group attention" */ + val = IS_MF(bp) ? 0xF7 : 0x7; + /* Enable DCBX attention for all but E1 */ + val |= CHIP_IS_E1(bp) ? 0 : 0x10; + REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, val); + + bnx2x_init_block(bp, BLOCK_NIG, init_phase); + + if (!CHIP_IS_E1x(bp)) { + /* Bit-map indicating which L2 hdrs may appear after the + * basic Ethernet header + */ + REG_WR(bp, BP_PORT(bp) ? + NIG_REG_P1_HDRS_AFTER_BASIC : + NIG_REG_P0_HDRS_AFTER_BASIC, + IS_MF_SD(bp) ? 7 : 6); + + if (CHIP_IS_E3(bp)) + REG_WR(bp, BP_PORT(bp) ? + NIG_REG_LLH1_MF_MODE : + NIG_REG_LLH_MF_MODE, IS_MF(bp)); + } + if (!CHIP_IS_E3(bp)) + REG_WR(bp, NIG_REG_XGXS_SERDES0_MODE_SEL + port*4, 1); + + if (!CHIP_IS_E1(bp)) { + /* 0x2 disable mf_ov, 0x1 enable */ + REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK_MF + port*4, + (IS_MF_SD(bp) ? 0x1 : 0x2)); + + if (!CHIP_IS_E1x(bp)) { + val = 0; + switch (bp->mf_mode) { + case MULTI_FUNCTION_SD: + val = 1; + break; + case MULTI_FUNCTION_SI: + val = 2; + break; + } + + REG_WR(bp, (BP_PORT(bp) ? NIG_REG_LLH1_CLS_TYPE : + NIG_REG_LLH0_CLS_TYPE), val); + } + { + REG_WR(bp, NIG_REG_LLFC_ENABLE_0 + port*4, 0); + REG_WR(bp, NIG_REG_LLFC_OUT_EN_0 + port*4, 0); + REG_WR(bp, NIG_REG_PAUSE_ENABLE_0 + port*4, 1); + } + } + + + /* If SPIO5 is set to generate interrupts, enable it for this port */ + val = REG_RD(bp, MISC_REG_SPIO_EVENT_EN); + if (val & (1 << MISC_REGISTERS_SPIO_5)) { + u32 reg_addr = (port ? MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 : + MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0); + val = REG_RD(bp, reg_addr); + val |= AEU_INPUTS_ATTN_BITS_SPIO5; + REG_WR(bp, reg_addr, val); + } + + return 0; +} + +static void bnx2x_ilt_wr(struct bnx2x *bp, u32 index, dma_addr_t addr) +{ + int reg; + + if (CHIP_IS_E1(bp)) + reg = PXP2_REG_RQ_ONCHIP_AT + index*8; + else + reg = PXP2_REG_RQ_ONCHIP_AT_B0 + index*8; + + bnx2x_wb_wr(bp, reg, ONCHIP_ADDR1(addr), ONCHIP_ADDR2(addr)); +} + +static inline void bnx2x_igu_clear_sb(struct bnx2x *bp, u8 idu_sb_id) +{ + bnx2x_igu_clear_sb_gen(bp, BP_FUNC(bp), idu_sb_id, true /*PF*/); +} + +static inline void bnx2x_clear_func_ilt(struct bnx2x *bp, u32 func) +{ + u32 i, base = FUNC_ILT_BASE(func); + for (i = base; i < base + ILT_PER_FUNC; i++) + bnx2x_ilt_wr(bp, i, 0); +} + +static int bnx2x_init_hw_func(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int init_phase = PHASE_PF0 + func; + struct bnx2x_ilt *ilt = BP_ILT(bp); + u16 cdu_ilt_start; + u32 addr, val; + u32 main_mem_base, main_mem_size, main_mem_prty_clr; + int i, main_mem_width; + + DP(BNX2X_MSG_MCP, "starting func init func %d\n", func); + + /* FLR cleanup - hmmm */ + if (!CHIP_IS_E1x(bp)) + bnx2x_pf_flr_clnup(bp); + + /* set MSI reconfigure capability */ + if (bp->common.int_block == INT_BLOCK_HC) { + addr = (port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0); + val = REG_RD(bp, addr); + val |= HC_CONFIG_0_REG_MSI_ATTN_EN_0; + REG_WR(bp, addr, val); + } + + bnx2x_init_block(bp, BLOCK_PXP, init_phase); + bnx2x_init_block(bp, BLOCK_PXP2, init_phase); + + ilt = BP_ILT(bp); + cdu_ilt_start = ilt->clients[ILT_CLIENT_CDU].start; + + for (i = 0; i < L2_ILT_LINES(bp); i++) { + ilt->lines[cdu_ilt_start + i].page = + bp->context.vcxt + (ILT_PAGE_CIDS * i); + ilt->lines[cdu_ilt_start + i].page_mapping = + bp->context.cxt_mapping + (CDU_ILT_PAGE_SZ * i); + /* cdu ilt pages are allocated manually so there's no need to + set the size */ + } + bnx2x_ilt_init_op(bp, INITOP_SET); + +#ifdef BCM_CNIC + bnx2x_src_init_t2(bp, bp->t2, bp->t2_mapping, SRC_CONN_NUM); + + /* T1 hash bits value determines the T1 number of entries */ + REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + port*4, SRC_HASH_BITS); +#endif + +#ifndef BCM_CNIC + /* set NIC mode */ + REG_WR(bp, PRS_REG_NIC_MODE, 1); +#endif /* BCM_CNIC */ + + if (!CHIP_IS_E1x(bp)) { + u32 pf_conf = IGU_PF_CONF_FUNC_EN; + + /* Turn on a single ISR mode in IGU if driver is going to use + * INT#x or MSI + */ + if (!(bp->flags & USING_MSIX_FLAG)) + pf_conf |= IGU_PF_CONF_SINGLE_ISR_EN; + /* + * Timers workaround bug: function init part. + * Need to wait 20msec after initializing ILT, + * needed to make sure there are no requests in + * one of the PXP internal queues with "old" ILT addresses + */ + msleep(20); + /* + * 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); + /* Enable the function in IGU */ + REG_WR(bp, IGU_REG_PF_CONFIGURATION, pf_conf); + } + + bp->dmae_ready = 1; + + bnx2x_init_block(bp, BLOCK_PGLUE_B, init_phase); + + if (!CHIP_IS_E1x(bp)) + REG_WR(bp, PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR, func); + + bnx2x_init_block(bp, BLOCK_ATC, init_phase); + bnx2x_init_block(bp, BLOCK_DMAE, init_phase); + bnx2x_init_block(bp, BLOCK_NIG, init_phase); + bnx2x_init_block(bp, BLOCK_SRC, init_phase); + bnx2x_init_block(bp, BLOCK_MISC, init_phase); + bnx2x_init_block(bp, BLOCK_TCM, init_phase); + bnx2x_init_block(bp, BLOCK_UCM, init_phase); + bnx2x_init_block(bp, BLOCK_CCM, init_phase); + bnx2x_init_block(bp, BLOCK_XCM, init_phase); + bnx2x_init_block(bp, BLOCK_TSEM, init_phase); + bnx2x_init_block(bp, BLOCK_USEM, init_phase); + bnx2x_init_block(bp, BLOCK_CSEM, init_phase); + bnx2x_init_block(bp, BLOCK_XSEM, init_phase); + + if (!CHIP_IS_E1x(bp)) + REG_WR(bp, QM_REG_PF_EN, 1); + + if (!CHIP_IS_E1x(bp)) { + REG_WR(bp, TSEM_REG_VFPF_ERR_NUM, BNX2X_MAX_NUM_OF_VFS + func); + REG_WR(bp, USEM_REG_VFPF_ERR_NUM, BNX2X_MAX_NUM_OF_VFS + func); + REG_WR(bp, CSEM_REG_VFPF_ERR_NUM, BNX2X_MAX_NUM_OF_VFS + func); + REG_WR(bp, XSEM_REG_VFPF_ERR_NUM, BNX2X_MAX_NUM_OF_VFS + func); + } + bnx2x_init_block(bp, BLOCK_QM, init_phase); + + bnx2x_init_block(bp, BLOCK_TM, init_phase); + bnx2x_init_block(bp, BLOCK_DORQ, init_phase); + bnx2x_init_block(bp, BLOCK_BRB1, init_phase); + bnx2x_init_block(bp, BLOCK_PRS, init_phase); + bnx2x_init_block(bp, BLOCK_TSDM, init_phase); + bnx2x_init_block(bp, BLOCK_CSDM, init_phase); + bnx2x_init_block(bp, BLOCK_USDM, init_phase); + bnx2x_init_block(bp, BLOCK_XSDM, init_phase); + bnx2x_init_block(bp, BLOCK_UPB, init_phase); + bnx2x_init_block(bp, BLOCK_XPB, init_phase); + bnx2x_init_block(bp, BLOCK_PBF, init_phase); + if (!CHIP_IS_E1x(bp)) + REG_WR(bp, PBF_REG_DISABLE_PF, 0); + + bnx2x_init_block(bp, BLOCK_CDU, init_phase); + + bnx2x_init_block(bp, BLOCK_CFC, init_phase); + + if (!CHIP_IS_E1x(bp)) + REG_WR(bp, CFC_REG_WEAK_ENABLE_PF, 1); + + if (IS_MF(bp)) { + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1); + REG_WR(bp, NIG_REG_LLH0_FUNC_VLAN_ID + port*8, bp->mf_ov); + } + + bnx2x_init_block(bp, BLOCK_MISC_AEU, init_phase); + + /* HC init per function */ + if (bp->common.int_block == INT_BLOCK_HC) { + if (CHIP_IS_E1H(bp)) { + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0); + + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0); + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0); + } + bnx2x_init_block(bp, BLOCK_HC, init_phase); + + } else { + int num_segs, sb_idx, prod_offset; + + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0); + + if (!CHIP_IS_E1x(bp)) { + REG_WR(bp, IGU_REG_LEADING_EDGE_LATCH, 0); + REG_WR(bp, IGU_REG_TRAILING_EDGE_LATCH, 0); + } + + bnx2x_init_block(bp, BLOCK_IGU, init_phase); + + if (!CHIP_IS_E1x(bp)) { + int dsb_idx = 0; + /** + * Producer memory: + * E2 mode: address 0-135 match to the mapping memory; + * 136 - PF0 default prod; 137 - PF1 default prod; + * 138 - PF2 default prod; 139 - PF3 default prod; + * 140 - PF0 attn prod; 141 - PF1 attn prod; + * 142 - PF2 attn prod; 143 - PF3 attn prod; + * 144-147 reserved. + * + * E1.5 mode - In backward compatible mode; + * for non default SB; each even line in the memory + * holds the U producer and each odd line hold + * the C producer. The first 128 producers are for + * NDSB (PF0 - 0-31; PF1 - 32-63 and so on). The last 20 + * producers are for the DSB for each PF. + * Each PF has five segments: (the order inside each + * segment is PF0; PF1; PF2; PF3) - 128-131 U prods; + * 132-135 C prods; 136-139 X prods; 140-143 T prods; + * 144-147 attn prods; + */ + /* non-default-status-blocks */ + num_segs = CHIP_INT_MODE_IS_BC(bp) ? + IGU_BC_NDSB_NUM_SEGS : IGU_NORM_NDSB_NUM_SEGS; + for (sb_idx = 0; sb_idx < bp->igu_sb_cnt; sb_idx++) { + prod_offset = (bp->igu_base_sb + sb_idx) * + num_segs; + + for (i = 0; i < num_segs; i++) { + addr = IGU_REG_PROD_CONS_MEMORY + + (prod_offset + i) * 4; + REG_WR(bp, addr, 0); + } + /* send consumer update with value 0 */ + bnx2x_ack_sb(bp, bp->igu_base_sb + sb_idx, + USTORM_ID, 0, IGU_INT_NOP, 1); + bnx2x_igu_clear_sb(bp, + bp->igu_base_sb + sb_idx); + } + + /* default-status-blocks */ + num_segs = CHIP_INT_MODE_IS_BC(bp) ? + IGU_BC_DSB_NUM_SEGS : IGU_NORM_DSB_NUM_SEGS; + + if (CHIP_MODE_IS_4_PORT(bp)) + dsb_idx = BP_FUNC(bp); + else + dsb_idx = BP_E1HVN(bp); + + prod_offset = (CHIP_INT_MODE_IS_BC(bp) ? + IGU_BC_BASE_DSB_PROD + dsb_idx : + IGU_NORM_BASE_DSB_PROD + dsb_idx); + + for (i = 0; i < (num_segs * E1HVN_MAX); + i += E1HVN_MAX) { + addr = IGU_REG_PROD_CONS_MEMORY + + (prod_offset + i)*4; + REG_WR(bp, addr, 0); + } + /* send consumer update with 0 */ + if (CHIP_INT_MODE_IS_BC(bp)) { + bnx2x_ack_sb(bp, bp->igu_dsb_id, + USTORM_ID, 0, IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, bp->igu_dsb_id, + CSTORM_ID, 0, IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, bp->igu_dsb_id, + XSTORM_ID, 0, IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, bp->igu_dsb_id, + TSTORM_ID, 0, IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, bp->igu_dsb_id, + ATTENTION_ID, 0, IGU_INT_NOP, 1); + } else { + bnx2x_ack_sb(bp, bp->igu_dsb_id, + USTORM_ID, 0, IGU_INT_NOP, 1); + bnx2x_ack_sb(bp, bp->igu_dsb_id, + ATTENTION_ID, 0, IGU_INT_NOP, 1); + } + bnx2x_igu_clear_sb(bp, bp->igu_dsb_id); + + /* !!! these should become driver const once + rf-tool supports split-68 const */ + REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_LSB, 0); + REG_WR(bp, IGU_REG_SB_INT_BEFORE_MASK_MSB, 0); + REG_WR(bp, IGU_REG_SB_MASK_LSB, 0); + REG_WR(bp, IGU_REG_SB_MASK_MSB, 0); + REG_WR(bp, IGU_REG_PBA_STATUS_LSB, 0); + REG_WR(bp, IGU_REG_PBA_STATUS_MSB, 0); + } + } + + /* Reset PCIE errors for debug */ + REG_WR(bp, 0x2114, 0xffffffff); + REG_WR(bp, 0x2120, 0xffffffff); + + if (CHIP_IS_E1x(bp)) { + main_mem_size = HC_REG_MAIN_MEMORY_SIZE / 2; /*dwords*/ + main_mem_base = HC_REG_MAIN_MEMORY + + BP_PORT(bp) * (main_mem_size * 4); + main_mem_prty_clr = HC_REG_HC_PRTY_STS_CLR; + main_mem_width = 8; + + val = REG_RD(bp, main_mem_prty_clr); + if (val) + DP(BNX2X_MSG_MCP, "Hmmm... Parity errors in HC " + "block during " + "function init (0x%x)!\n", val); + + /* Clear "false" parity errors in MSI-X table */ + for (i = main_mem_base; + i < main_mem_base + main_mem_size * 4; + i += main_mem_width) { + bnx2x_read_dmae(bp, i, main_mem_width / 4); + bnx2x_write_dmae(bp, bnx2x_sp_mapping(bp, wb_data), + i, main_mem_width / 4); + } + /* Clear HC parity attention */ + REG_RD(bp, main_mem_prty_clr); + } + +#ifdef BNX2X_STOP_ON_ERROR + /* Enable STORMs SP logging */ + REG_WR8(bp, BAR_USTRORM_INTMEM + + USTORM_RECORD_SLOW_PATH_OFFSET(BP_FUNC(bp)), 1); + REG_WR8(bp, BAR_TSTRORM_INTMEM + + TSTORM_RECORD_SLOW_PATH_OFFSET(BP_FUNC(bp)), 1); + REG_WR8(bp, BAR_CSTRORM_INTMEM + + CSTORM_RECORD_SLOW_PATH_OFFSET(BP_FUNC(bp)), 1); + REG_WR8(bp, BAR_XSTRORM_INTMEM + + XSTORM_RECORD_SLOW_PATH_OFFSET(BP_FUNC(bp)), 1); +#endif + + bnx2x_phy_probe(&bp->link_params); + + return 0; +} + + +void bnx2x_free_mem(struct bnx2x *bp) +{ + /* fastpath */ + bnx2x_free_fp_mem(bp); + /* end of fastpath */ + + BNX2X_PCI_FREE(bp->def_status_blk, bp->def_status_blk_mapping, + sizeof(struct host_sp_status_block)); + + BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping, + bp->fw_stats_data_sz + bp->fw_stats_req_sz); + + BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping, + sizeof(struct bnx2x_slowpath)); + + BNX2X_PCI_FREE(bp->context.vcxt, bp->context.cxt_mapping, + bp->context.size); + + bnx2x_ilt_mem_op(bp, ILT_MEMOP_FREE); + + BNX2X_FREE(bp->ilt->lines); + +#ifdef BCM_CNIC + if (!CHIP_IS_E1x(bp)) + BNX2X_PCI_FREE(bp->cnic_sb.e2_sb, bp->cnic_sb_mapping, + sizeof(struct host_hc_status_block_e2)); + else + BNX2X_PCI_FREE(bp->cnic_sb.e1x_sb, bp->cnic_sb_mapping, + sizeof(struct host_hc_status_block_e1x)); + + BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, SRC_T2_SZ); +#endif + + BNX2X_PCI_FREE(bp->spq, bp->spq_mapping, BCM_PAGE_SIZE); + + BNX2X_PCI_FREE(bp->eq_ring, bp->eq_mapping, + BCM_PAGE_SIZE * NUM_EQ_PAGES); +} + +static inline int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp) +{ + int num_groups; + + /* number of eth_queues */ + u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp); + + /* Total number of FW statistics requests = + * 1 for port stats + 1 for PF stats + num_eth_queues */ + bp->fw_stats_num = 2 + num_queue_stats; + + + /* Request is built from stats_query_header and an array of + * stats_query_cmd_group each of which contains + * STATS_QUERY_CMD_COUNT rules. The real number or requests is + * configured in the stats_query_header. + */ + num_groups = (2 + num_queue_stats) / STATS_QUERY_CMD_COUNT + + (((2 + num_queue_stats) % STATS_QUERY_CMD_COUNT) ? 1 : 0); + + bp->fw_stats_req_sz = sizeof(struct stats_query_header) + + num_groups * sizeof(struct stats_query_cmd_group); + + /* Data for statistics requests + stats_conter + * + * stats_counter holds per-STORM counters that are incremented + * when STORM has finished with the current request. + */ + bp->fw_stats_data_sz = sizeof(struct per_port_stats) + + sizeof(struct per_pf_stats) + + sizeof(struct per_queue_stats) * num_queue_stats + + sizeof(struct stats_counter); + + BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping, + bp->fw_stats_data_sz + bp->fw_stats_req_sz); + + /* Set shortcuts */ + bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats; + bp->fw_stats_req_mapping = bp->fw_stats_mapping; + + bp->fw_stats_data = (struct bnx2x_fw_stats_data *) + ((u8 *)bp->fw_stats + bp->fw_stats_req_sz); + + bp->fw_stats_data_mapping = bp->fw_stats_mapping + + bp->fw_stats_req_sz; + return 0; + +alloc_mem_err: + BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping, + bp->fw_stats_data_sz + bp->fw_stats_req_sz); + return -ENOMEM; +} + + +int bnx2x_alloc_mem(struct bnx2x *bp) +{ +#ifdef BCM_CNIC + if (!CHIP_IS_E1x(bp)) + /* size = the status block + ramrod buffers */ + BNX2X_PCI_ALLOC(bp->cnic_sb.e2_sb, &bp->cnic_sb_mapping, + sizeof(struct host_hc_status_block_e2)); + else + BNX2X_PCI_ALLOC(bp->cnic_sb.e1x_sb, &bp->cnic_sb_mapping, + sizeof(struct host_hc_status_block_e1x)); + + /* allocate searcher T2 table */ + BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ); +#endif + + + BNX2X_PCI_ALLOC(bp->def_status_blk, &bp->def_status_blk_mapping, + sizeof(struct host_sp_status_block)); + + BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping, + sizeof(struct bnx2x_slowpath)); + + /* Allocated memory for FW statistics */ + if (bnx2x_alloc_fw_stats_mem(bp)) + goto alloc_mem_err; + + bp->context.size = sizeof(union cdu_context) * BNX2X_L2_CID_COUNT(bp); + + BNX2X_PCI_ALLOC(bp->context.vcxt, &bp->context.cxt_mapping, + bp->context.size); + + BNX2X_ALLOC(bp->ilt->lines, sizeof(struct ilt_line) * ILT_MAX_LINES); + + if (bnx2x_ilt_mem_op(bp, ILT_MEMOP_ALLOC)) + goto alloc_mem_err; + + /* Slow path ring */ + BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE); + + /* EQ */ + BNX2X_PCI_ALLOC(bp->eq_ring, &bp->eq_mapping, + BCM_PAGE_SIZE * NUM_EQ_PAGES); + + + /* fastpath */ + /* need to be done at the end, since it's self adjusting to amount + * of memory available for RSS queues + */ + if (bnx2x_alloc_fp_mem(bp)) + goto alloc_mem_err; + return 0; + +alloc_mem_err: + bnx2x_free_mem(bp); + return -ENOMEM; +} + +/* + * Init service functions + */ + +int bnx2x_set_mac_one(struct bnx2x *bp, u8 *mac, + struct bnx2x_vlan_mac_obj *obj, bool set, + int mac_type, unsigned long *ramrod_flags) +{ + int rc; + struct bnx2x_vlan_mac_ramrod_params ramrod_param; + + memset(&ramrod_param, 0, sizeof(ramrod_param)); + + /* Fill general parameters */ + ramrod_param.vlan_mac_obj = obj; + ramrod_param.ramrod_flags = *ramrod_flags; + + /* Fill a user request section if needed */ + if (!test_bit(RAMROD_CONT, ramrod_flags)) { + memcpy(ramrod_param.user_req.u.mac.mac, mac, ETH_ALEN); + + __set_bit(mac_type, &ramrod_param.user_req.vlan_mac_flags); + + /* Set the command: ADD or DEL */ + if (set) + ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_ADD; + else + ramrod_param.user_req.cmd = BNX2X_VLAN_MAC_DEL; + } + + rc = bnx2x_config_vlan_mac(bp, &ramrod_param); + if (rc < 0) + BNX2X_ERR("%s MAC failed\n", (set ? "Set" : "Del")); + return rc; +} + +int bnx2x_del_all_macs(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *mac_obj, + int mac_type, bool wait_for_comp) +{ + int rc; + unsigned long ramrod_flags = 0, vlan_mac_flags = 0; + + /* Wait for completion of requested */ + if (wait_for_comp) + __set_bit(RAMROD_COMP_WAIT, &ramrod_flags); + + /* Set the mac type of addresses we want to clear */ + __set_bit(mac_type, &vlan_mac_flags); + + rc = mac_obj->delete_all(bp, mac_obj, &vlan_mac_flags, &ramrod_flags); + if (rc < 0) + BNX2X_ERR("Failed to delete MACs: %d\n", rc); + + return rc; +} + +int bnx2x_set_eth_mac(struct bnx2x *bp, bool set) +{ + unsigned long ramrod_flags = 0; + + DP(NETIF_MSG_IFUP, "Adding Eth MAC\n"); + + __set_bit(RAMROD_COMP_WAIT, &ramrod_flags); + /* Eth MAC is set on RSS leading client (fp[0]) */ + return bnx2x_set_mac_one(bp, bp->dev->dev_addr, &bp->fp->mac_obj, set, + BNX2X_ETH_MAC, &ramrod_flags); +} + +int bnx2x_setup_leading(struct bnx2x *bp) +{ + return bnx2x_setup_queue(bp, &bp->fp[0], 1); +} + +/** + * bnx2x_set_int_mode - configure interrupt mode + * + * @bp: driver handle + * + * In case of MSI-X it will also try to enable MSI-X. + */ +static void __devinit bnx2x_set_int_mode(struct bnx2x *bp) +{ + switch (int_mode) { + case INT_MODE_MSI: + bnx2x_enable_msi(bp); + /* falling through... */ + case INT_MODE_INTx: + bp->num_queues = 1 + NON_ETH_CONTEXT_USE; + DP(NETIF_MSG_IFUP, "set number of queues to 1\n"); + break; + default: + /* Set number of queues according to bp->multi_mode value */ + bnx2x_set_num_queues(bp); + + DP(NETIF_MSG_IFUP, "set number of queues to %d\n", + bp->num_queues); + + /* if we can't use MSI-X we only need one fp, + * so try to enable MSI-X with the requested number of fp's + * and fallback to MSI or legacy INTx with one fp + */ + if (bnx2x_enable_msix(bp)) { + /* failed to enable MSI-X */ + if (bp->multi_mode) + DP(NETIF_MSG_IFUP, + "Multi requested but failed to " + "enable MSI-X (%d), " + "set number of queues to %d\n", + bp->num_queues, + 1 + NON_ETH_CONTEXT_USE); + bp->num_queues = 1 + NON_ETH_CONTEXT_USE; + + /* Try to enable MSI */ + if (!(bp->flags & DISABLE_MSI_FLAG)) + bnx2x_enable_msi(bp); + } + break; + } +} + +/* must be called prioir to any HW initializations */ +static inline u16 bnx2x_cid_ilt_lines(struct bnx2x *bp) +{ + return L2_ILT_LINES(bp); +} + +void bnx2x_ilt_set_info(struct bnx2x *bp) +{ + struct ilt_client_info *ilt_client; + struct bnx2x_ilt *ilt = BP_ILT(bp); + u16 line = 0; + + ilt->start_line = FUNC_ILT_BASE(BP_FUNC(bp)); + DP(BNX2X_MSG_SP, "ilt starts at line %d\n", ilt->start_line); + + /* CDU */ + ilt_client = &ilt->clients[ILT_CLIENT_CDU]; + ilt_client->client_num = ILT_CLIENT_CDU; + ilt_client->page_size = CDU_ILT_PAGE_SZ; + ilt_client->flags = ILT_CLIENT_SKIP_MEM; + ilt_client->start = line; + line += bnx2x_cid_ilt_lines(bp); +#ifdef BCM_CNIC + line += CNIC_ILT_LINES; +#endif + ilt_client->end = line - 1; + + DP(BNX2X_MSG_SP, "ilt client[CDU]: start %d, end %d, psz 0x%x, " + "flags 0x%x, hw psz %d\n", + ilt_client->start, + ilt_client->end, + ilt_client->page_size, + ilt_client->flags, + ilog2(ilt_client->page_size >> 12)); + + /* QM */ + if (QM_INIT(bp->qm_cid_count)) { + ilt_client = &ilt->clients[ILT_CLIENT_QM]; + ilt_client->client_num = ILT_CLIENT_QM; + ilt_client->page_size = QM_ILT_PAGE_SZ; + ilt_client->flags = 0; + ilt_client->start = line; + + /* 4 bytes for each cid */ + line += DIV_ROUND_UP(bp->qm_cid_count * QM_QUEUES_PER_FUNC * 4, + QM_ILT_PAGE_SZ); + + ilt_client->end = line - 1; + + DP(BNX2X_MSG_SP, "ilt client[QM]: start %d, end %d, psz 0x%x, " + "flags 0x%x, hw psz %d\n", + ilt_client->start, + ilt_client->end, + ilt_client->page_size, + ilt_client->flags, + ilog2(ilt_client->page_size >> 12)); + + } + /* SRC */ + ilt_client = &ilt->clients[ILT_CLIENT_SRC]; +#ifdef BCM_CNIC + ilt_client->client_num = ILT_CLIENT_SRC; + ilt_client->page_size = SRC_ILT_PAGE_SZ; + ilt_client->flags = 0; + ilt_client->start = line; + line += SRC_ILT_LINES; + ilt_client->end = line - 1; + + DP(BNX2X_MSG_SP, "ilt client[SRC]: start %d, end %d, psz 0x%x, " + "flags 0x%x, hw psz %d\n", + ilt_client->start, + ilt_client->end, + ilt_client->page_size, + ilt_client->flags, + ilog2(ilt_client->page_size >> 12)); + +#else + ilt_client->flags = (ILT_CLIENT_SKIP_INIT | ILT_CLIENT_SKIP_MEM); +#endif + + /* TM */ + ilt_client = &ilt->clients[ILT_CLIENT_TM]; +#ifdef BCM_CNIC + ilt_client->client_num = ILT_CLIENT_TM; + ilt_client->page_size = TM_ILT_PAGE_SZ; + ilt_client->flags = 0; + ilt_client->start = line; + line += TM_ILT_LINES; + ilt_client->end = line - 1; + + DP(BNX2X_MSG_SP, "ilt client[TM]: start %d, end %d, psz 0x%x, " + "flags 0x%x, hw psz %d\n", + ilt_client->start, + ilt_client->end, + ilt_client->page_size, + ilt_client->flags, + ilog2(ilt_client->page_size >> 12)); + +#else + ilt_client->flags = (ILT_CLIENT_SKIP_INIT | ILT_CLIENT_SKIP_MEM); +#endif + BUG_ON(line > ILT_MAX_LINES); +} + +/** + * bnx2x_pf_q_prep_init - prepare INIT transition parameters + * + * @bp: driver handle + * @fp: pointer to fastpath + * @init_params: pointer to parameters structure + * + * parameters configured: + * - HC configuration + * - Queue's CDU context + */ +static inline void bnx2x_pf_q_prep_init(struct bnx2x *bp, + struct bnx2x_fastpath *fp, struct bnx2x_queue_init_params *init_params) +{ + + u8 cos; + /* FCoE Queue uses Default SB, thus has no HC capabilities */ + if (!IS_FCOE_FP(fp)) { + __set_bit(BNX2X_Q_FLG_HC, &init_params->rx.flags); + __set_bit(BNX2X_Q_FLG_HC, &init_params->tx.flags); + + /* If HC is supporterd, enable host coalescing in the transition + * to INIT state. + */ + __set_bit(BNX2X_Q_FLG_HC_EN, &init_params->rx.flags); + __set_bit(BNX2X_Q_FLG_HC_EN, &init_params->tx.flags); + + /* HC rate */ + init_params->rx.hc_rate = bp->rx_ticks ? + (1000000 / bp->rx_ticks) : 0; + init_params->tx.hc_rate = bp->tx_ticks ? + (1000000 / bp->tx_ticks) : 0; + + /* FW SB ID */ + init_params->rx.fw_sb_id = init_params->tx.fw_sb_id = + fp->fw_sb_id; + + /* + * CQ index among the SB indices: FCoE clients uses the default + * SB, therefore it's different. + */ + init_params->rx.sb_cq_index = HC_INDEX_ETH_RX_CQ_CONS; + init_params->tx.sb_cq_index = HC_INDEX_ETH_FIRST_TX_CQ_CONS; + } + + /* set maximum number of COSs supported by this queue */ + init_params->max_cos = fp->max_cos; + + DP(BNX2X_MSG_SP, "fp: %d setting queue params max cos to: %d", + fp->index, init_params->max_cos); + + /* set the context pointers queue object */ + for (cos = FIRST_TX_COS_INDEX; cos < init_params->max_cos; cos++) + init_params->cxts[cos] = + &bp->context.vcxt[fp->txdata[cos].cid].eth; +} + +int bnx2x_setup_tx_only(struct bnx2x *bp, struct bnx2x_fastpath *fp, + struct bnx2x_queue_state_params *q_params, + struct bnx2x_queue_setup_tx_only_params *tx_only_params, + int tx_index, bool leading) +{ + memset(tx_only_params, 0, sizeof(*tx_only_params)); + + /* Set the command */ + q_params->cmd = BNX2X_Q_CMD_SETUP_TX_ONLY; + + /* Set tx-only QUEUE flags: don't zero statistics */ + tx_only_params->flags = bnx2x_get_common_flags(bp, fp, false); + + /* choose the index of the cid to send the slow path on */ + tx_only_params->cid_index = tx_index; + + /* Set general TX_ONLY_SETUP parameters */ + bnx2x_pf_q_prep_general(bp, fp, &tx_only_params->gen_params, tx_index); + + /* Set Tx TX_ONLY_SETUP parameters */ + bnx2x_pf_tx_q_prep(bp, fp, &tx_only_params->txq_params, tx_index); + + DP(BNX2X_MSG_SP, "preparing to send tx-only ramrod for connection:" + "cos %d, primary cid %d, cid %d, " + "client id %d, sp-client id %d, flags %lx", + tx_index, q_params->q_obj->cids[FIRST_TX_COS_INDEX], + q_params->q_obj->cids[tx_index], q_params->q_obj->cl_id, + tx_only_params->gen_params.spcl_id, tx_only_params->flags); + + /* send the ramrod */ + return bnx2x_queue_state_change(bp, q_params); +} + + +/** + * bnx2x_setup_queue - setup queue + * + * @bp: driver handle + * @fp: pointer to fastpath + * @leading: is leading + * + * This function performs 2 steps in a Queue state machine + * actually: 1) RESET->INIT 2) INIT->SETUP + */ + +int bnx2x_setup_queue(struct bnx2x *bp, struct bnx2x_fastpath *fp, + bool leading) +{ + struct bnx2x_queue_state_params q_params = {0}; + struct bnx2x_queue_setup_params *setup_params = + &q_params.params.setup; + struct bnx2x_queue_setup_tx_only_params *tx_only_params = + &q_params.params.tx_only; + int rc; + u8 tx_index; + + DP(BNX2X_MSG_SP, "setting up queue %d", fp->index); + + /* reset IGU state skip FCoE L2 queue */ + if (!IS_FCOE_FP(fp)) + bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0, + IGU_INT_ENABLE, 0); + + q_params.q_obj = &fp->q_obj; + /* We want to wait for completion in this context */ + __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags); + + /* Prepare the INIT parameters */ + bnx2x_pf_q_prep_init(bp, fp, &q_params.params.init); + + /* Set the command */ + q_params.cmd = BNX2X_Q_CMD_INIT; + + /* Change the state to INIT */ + rc = bnx2x_queue_state_change(bp, &q_params); + if (rc) { + BNX2X_ERR("Queue(%d) INIT failed\n", fp->index); + return rc; + } + + DP(BNX2X_MSG_SP, "init complete"); + + + /* Now move the Queue to the SETUP state... */ + memset(setup_params, 0, sizeof(*setup_params)); + + /* Set QUEUE flags */ + setup_params->flags = bnx2x_get_q_flags(bp, fp, leading); + + /* Set general SETUP parameters */ + bnx2x_pf_q_prep_general(bp, fp, &setup_params->gen_params, + FIRST_TX_COS_INDEX); + + bnx2x_pf_rx_q_prep(bp, fp, &setup_params->pause_params, + &setup_params->rxq_params); + + bnx2x_pf_tx_q_prep(bp, fp, &setup_params->txq_params, + FIRST_TX_COS_INDEX); + + /* Set the command */ + q_params.cmd = BNX2X_Q_CMD_SETUP; + + /* Change the state to SETUP */ + rc = bnx2x_queue_state_change(bp, &q_params); + if (rc) { + BNX2X_ERR("Queue(%d) SETUP failed\n", fp->index); + return rc; + } + + /* loop through the relevant tx-only indices */ + for (tx_index = FIRST_TX_ONLY_COS_INDEX; + tx_index < fp->max_cos; + tx_index++) { + + /* prepare and send tx-only ramrod*/ + rc = bnx2x_setup_tx_only(bp, fp, &q_params, + tx_only_params, tx_index, leading); + if (rc) { + BNX2X_ERR("Queue(%d.%d) TX_ONLY_SETUP failed\n", + fp->index, tx_index); + return rc; + } + } + + return rc; +} + +static int bnx2x_stop_queue(struct bnx2x *bp, int index) +{ + struct bnx2x_fastpath *fp = &bp->fp[index]; + struct bnx2x_fp_txdata *txdata; + struct bnx2x_queue_state_params q_params = {0}; + int rc, tx_index; + + DP(BNX2X_MSG_SP, "stopping queue %d cid %d", index, fp->cid); + + q_params.q_obj = &fp->q_obj; + /* We want to wait for completion in this context */ + __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags); + + + /* close tx-only connections */ + for (tx_index = FIRST_TX_ONLY_COS_INDEX; + tx_index < fp->max_cos; + tx_index++){ + + /* ascertain this is a normal queue*/ + txdata = &fp->txdata[tx_index]; + + DP(BNX2X_MSG_SP, "stopping tx-only queue %d", + txdata->txq_index); + + /* send halt terminate on tx-only connection */ + q_params.cmd = BNX2X_Q_CMD_TERMINATE; + memset(&q_params.params.terminate, 0, + sizeof(q_params.params.terminate)); + q_params.params.terminate.cid_index = tx_index; + + rc = bnx2x_queue_state_change(bp, &q_params); + if (rc) + return rc; + + /* send halt terminate on tx-only connection */ + q_params.cmd = BNX2X_Q_CMD_CFC_DEL; + memset(&q_params.params.cfc_del, 0, + sizeof(q_params.params.cfc_del)); + q_params.params.cfc_del.cid_index = tx_index; + rc = bnx2x_queue_state_change(bp, &q_params); + if (rc) + return rc; + } + /* Stop the primary connection: */ + /* ...halt the connection */ + q_params.cmd = BNX2X_Q_CMD_HALT; + rc = bnx2x_queue_state_change(bp, &q_params); + if (rc) + return rc; + + /* ...terminate the connection */ + q_params.cmd = BNX2X_Q_CMD_TERMINATE; + memset(&q_params.params.terminate, 0, + sizeof(q_params.params.terminate)); + q_params.params.terminate.cid_index = FIRST_TX_COS_INDEX; + rc = bnx2x_queue_state_change(bp, &q_params); + if (rc) + return rc; + /* ...delete cfc entry */ + q_params.cmd = BNX2X_Q_CMD_CFC_DEL; + memset(&q_params.params.cfc_del, 0, + sizeof(q_params.params.cfc_del)); + q_params.params.cfc_del.cid_index = FIRST_TX_COS_INDEX; + return bnx2x_queue_state_change(bp, &q_params); +} + + +static void bnx2x_reset_func(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int func = BP_FUNC(bp); + int i; + + /* Disable the function in the FW */ + REG_WR8(bp, BAR_XSTRORM_INTMEM + XSTORM_FUNC_EN_OFFSET(func), 0); + REG_WR8(bp, BAR_CSTRORM_INTMEM + CSTORM_FUNC_EN_OFFSET(func), 0); + REG_WR8(bp, BAR_TSTRORM_INTMEM + TSTORM_FUNC_EN_OFFSET(func), 0); + REG_WR8(bp, BAR_USTRORM_INTMEM + USTORM_FUNC_EN_OFFSET(func), 0); + + /* FP SBs */ + for_each_eth_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + REG_WR8(bp, BAR_CSTRORM_INTMEM + + CSTORM_STATUS_BLOCK_DATA_STATE_OFFSET(fp->fw_sb_id), + SB_DISABLED); + } + +#ifdef BCM_CNIC + /* CNIC SB */ + REG_WR8(bp, BAR_CSTRORM_INTMEM + + CSTORM_STATUS_BLOCK_DATA_STATE_OFFSET(bnx2x_cnic_fw_sb_id(bp)), + SB_DISABLED); +#endif + /* SP SB */ + REG_WR8(bp, BAR_CSTRORM_INTMEM + + CSTORM_SP_STATUS_BLOCK_DATA_STATE_OFFSET(func), + SB_DISABLED); + + for (i = 0; i < XSTORM_SPQ_DATA_SIZE / 4; i++) + REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_DATA_OFFSET(func), + 0); + + /* Configure IGU */ + if (bp->common.int_block == INT_BLOCK_HC) { + REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0); + REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0); + } else { + REG_WR(bp, IGU_REG_LEADING_EDGE_LATCH, 0); + REG_WR(bp, IGU_REG_TRAILING_EDGE_LATCH, 0); + } + +#ifdef BCM_CNIC + /* Disable Timer scan */ + REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 0); + /* + * Wait for at least 10ms and up to 2 second for the timers scan to + * complete + */ + for (i = 0; i < 200; i++) { + msleep(10); + if (!REG_RD(bp, TM_REG_LIN0_SCAN_ON + port*4)) + break; + } +#endif + /* Clear ILT */ + bnx2x_clear_func_ilt(bp, func); + + /* Timers workaround bug for E2: if this is vnic-3, + * we need to set the entire ilt range for this timers. + */ + if (!CHIP_IS_E1x(bp) && BP_VN(bp) == 3) { + struct ilt_client_info ilt_cli; + /* use dummy TM client */ + memset(&ilt_cli, 0, sizeof(struct ilt_client_info)); + ilt_cli.start = 0; + ilt_cli.end = ILT_NUM_PAGE_ENTRIES - 1; + ilt_cli.client_num = ILT_CLIENT_TM; + + bnx2x_ilt_boundry_init_op(bp, &ilt_cli, 0, INITOP_CLEAR); + } + + /* this assumes that reset_port() called before reset_func()*/ + if (!CHIP_IS_E1x(bp)) + bnx2x_pf_disable(bp); + + bp->dmae_ready = 0; +} + +static void bnx2x_reset_port(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 val; + + /* Reset physical Link */ + bnx2x__link_reset(bp); + + REG_WR(bp, NIG_REG_MASK_INTERRUPT_PORT0 + port*4, 0); + + /* Do not rcv packets to BRB */ + REG_WR(bp, NIG_REG_LLH0_BRB1_DRV_MASK + port*4, 0x0); + /* Do not direct rcv packets that are not for MCP to the BRB */ + REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP : + NIG_REG_LLH0_BRB1_NOT_MCP), 0x0); + + /* Configure AEU */ + REG_WR(bp, MISC_REG_AEU_MASK_ATTN_FUNC_0 + port*4, 0); + + msleep(100); + /* Check for BRB port occupancy */ + val = REG_RD(bp, BRB1_REG_PORT_NUM_OCC_BLOCKS_0 + port*4); + if (val) + DP(NETIF_MSG_IFDOWN, + "BRB1 is not empty %d blocks are occupied\n", val); + + /* TODO: Close Doorbell port? */ +} + +static inline int bnx2x_reset_hw(struct bnx2x *bp, u32 load_code) +{ + struct bnx2x_func_state_params func_params = {0}; + + /* Prepare parameters for function state transitions */ + __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags); + + func_params.f_obj = &bp->func_obj; + func_params.cmd = BNX2X_F_CMD_HW_RESET; + + func_params.params.hw_init.load_phase = load_code; + + return bnx2x_func_state_change(bp, &func_params); +} + +static inline int bnx2x_func_stop(struct bnx2x *bp) +{ + struct bnx2x_func_state_params func_params = {0}; + int rc; + + /* Prepare parameters for function state transitions */ + __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags); + func_params.f_obj = &bp->func_obj; + func_params.cmd = BNX2X_F_CMD_STOP; + + /* + * Try to stop the function the 'good way'. If fails (in case + * of a parity error during bnx2x_chip_cleanup()) and we are + * not in a debug mode, perform a state transaction in order to + * enable further HW_RESET transaction. + */ + rc = bnx2x_func_state_change(bp, &func_params); + if (rc) { +#ifdef BNX2X_STOP_ON_ERROR + return rc; +#else + BNX2X_ERR("FUNC_STOP ramrod failed. Running a dry " + "transaction\n"); + __set_bit(RAMROD_DRV_CLR_ONLY, &func_params.ramrod_flags); + return bnx2x_func_state_change(bp, &func_params); +#endif + } + + return 0; +} + +/** + * bnx2x_send_unload_req - request unload mode from the MCP. + * + * @bp: driver handle + * @unload_mode: requested function's unload mode + * + * Return unload mode returned by the MCP: COMMON, PORT or FUNC. + */ +u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode) +{ + u32 reset_code = 0; + int port = BP_PORT(bp); + + /* Select the UNLOAD request mode */ + if (unload_mode == UNLOAD_NORMAL) + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; + + else if (bp->flags & NO_WOL_FLAG) + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP; + + else if (bp->wol) { + u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; + u8 *mac_addr = bp->dev->dev_addr; + u32 val; + /* The mac address is written to entries 1-4 to + preserve entry 0 which is used by the PMF */ + u8 entry = (BP_E1HVN(bp) + 1)*8; + + val = (mac_addr[0] << 8) | mac_addr[1]; + EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry, val); + + val = (mac_addr[2] << 24) | (mac_addr[3] << 16) | + (mac_addr[4] << 8) | mac_addr[5]; + EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + entry + 4, val); + + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_EN; + + } else + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; + + /* Send the request to the MCP */ + if (!BP_NOMCP(bp)) + reset_code = bnx2x_fw_command(bp, reset_code, 0); + else { + int path = BP_PATH(bp); + + DP(NETIF_MSG_IFDOWN, "NO MCP - load counts[%d] " + "%d, %d, %d\n", + path, load_count[path][0], load_count[path][1], + load_count[path][2]); + load_count[path][0]--; + load_count[path][1 + port]--; + DP(NETIF_MSG_IFDOWN, "NO MCP - new load counts[%d] " + "%d, %d, %d\n", + path, load_count[path][0], load_count[path][1], + load_count[path][2]); + if (load_count[path][0] == 0) + reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON; + else if (load_count[path][1 + port] == 0) + reset_code = FW_MSG_CODE_DRV_UNLOAD_PORT; + else + reset_code = FW_MSG_CODE_DRV_UNLOAD_FUNCTION; + } + + return reset_code; +} + +/** + * bnx2x_send_unload_done - send UNLOAD_DONE command to the MCP. + * + * @bp: driver handle + */ +void bnx2x_send_unload_done(struct bnx2x *bp) +{ + /* Report UNLOAD_DONE to MCP */ + if (!BP_NOMCP(bp)) + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0); +} + +static inline int bnx2x_func_wait_started(struct bnx2x *bp) +{ + int tout = 50; + int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0; + + if (!bp->port.pmf) + return 0; + + /* + * (assumption: No Attention from MCP at this stage) + * PMF probably in the middle of TXdisable/enable transaction + * 1. Sync IRS for default SB + * 2. Sync SP queue - this guarantes us that attention handling started + * 3. Wait, that TXdisable/enable transaction completes + * + * 1+2 guranty that if DCBx attention was scheduled it already changed + * pending bit of transaction from STARTED-->TX_STOPPED, if we alredy + * received complettion for the transaction the state is TX_STOPPED. + * State will return to STARTED after completion of TX_STOPPED-->STARTED + * transaction. + */ + + /* make sure default SB ISR is done */ + if (msix) + synchronize_irq(bp->msix_table[0].vector); + else + synchronize_irq(bp->pdev->irq); + + flush_workqueue(bnx2x_wq); + + while (bnx2x_func_get_state(bp, &bp->func_obj) != + BNX2X_F_STATE_STARTED && tout--) + msleep(20); + + if (bnx2x_func_get_state(bp, &bp->func_obj) != + BNX2X_F_STATE_STARTED) { +#ifdef BNX2X_STOP_ON_ERROR + return -EBUSY; +#else + /* + * Failed to complete the transaction in a "good way" + * Force both transactions with CLR bit + */ + struct bnx2x_func_state_params func_params = {0}; + + DP(BNX2X_MSG_SP, "Hmmm... unexpected function state! " + "Forcing STARTED-->TX_ST0PPED-->STARTED\n"); + + func_params.f_obj = &bp->func_obj; + __set_bit(RAMROD_DRV_CLR_ONLY, + &func_params.ramrod_flags); + + /* STARTED-->TX_ST0PPED */ + func_params.cmd = BNX2X_F_CMD_TX_STOP; + bnx2x_func_state_change(bp, &func_params); + + /* TX_ST0PPED-->STARTED */ + func_params.cmd = BNX2X_F_CMD_TX_START; + return bnx2x_func_state_change(bp, &func_params); +#endif + } + + return 0; +} + +void bnx2x_chip_cleanup(struct bnx2x *bp, int unload_mode) +{ + int port = BP_PORT(bp); + int i, rc = 0; + u8 cos; + struct bnx2x_mcast_ramrod_params rparam = {0}; + u32 reset_code; + + /* Wait until tx fastpath tasks complete */ + for_each_tx_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + for_each_cos_in_tx_queue(fp, cos) + rc = bnx2x_clean_tx_queue(bp, &fp->txdata[cos]); +#ifdef BNX2X_STOP_ON_ERROR + if (rc) + return; +#endif + } + + /* Give HW time to discard old tx messages */ + usleep_range(1000, 1000); + + /* Clean all ETH MACs */ + rc = bnx2x_del_all_macs(bp, &bp->fp[0].mac_obj, BNX2X_ETH_MAC, false); + if (rc < 0) + BNX2X_ERR("Failed to delete all ETH macs: %d\n", rc); + + /* Clean up UC list */ + rc = bnx2x_del_all_macs(bp, &bp->fp[0].mac_obj, BNX2X_UC_LIST_MAC, + true); + if (rc < 0) + BNX2X_ERR("Failed to schedule DEL commands for UC MACs list: " + "%d\n", rc); + + /* Disable LLH */ + if (!CHIP_IS_E1(bp)) + REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0); + + /* Set "drop all" (stop Rx). + * We need to take a netif_addr_lock() here in order to prevent + * a race between the completion code and this code. + */ + netif_addr_lock_bh(bp->dev); + /* Schedule the rx_mode command */ + if (test_bit(BNX2X_FILTER_RX_MODE_PENDING, &bp->sp_state)) + set_bit(BNX2X_FILTER_RX_MODE_SCHED, &bp->sp_state); + else + bnx2x_set_storm_rx_mode(bp); + + /* Cleanup multicast configuration */ + rparam.mcast_obj = &bp->mcast_obj; + rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL); + if (rc < 0) + BNX2X_ERR("Failed to send DEL multicast command: %d\n", rc); + + netif_addr_unlock_bh(bp->dev); + + + + /* + * Send the UNLOAD_REQUEST to the MCP. This will return if + * this function should perform FUNC, PORT or COMMON HW + * reset. + */ + reset_code = bnx2x_send_unload_req(bp, unload_mode); + + /* + * (assumption: No Attention from MCP at this stage) + * PMF probably in the middle of TXdisable/enable transaction + */ + rc = bnx2x_func_wait_started(bp); + if (rc) { + BNX2X_ERR("bnx2x_func_wait_started failed\n"); +#ifdef BNX2X_STOP_ON_ERROR + return; +#endif + } + + /* Close multi and leading connections + * Completions for ramrods are collected in a synchronous way + */ + for_each_queue(bp, i) + if (bnx2x_stop_queue(bp, i)) +#ifdef BNX2X_STOP_ON_ERROR + return; +#else + goto unload_error; +#endif + /* If SP settings didn't get completed so far - something + * very wrong has happen. + */ + if (!bnx2x_wait_sp_comp(bp, ~0x0UL)) + BNX2X_ERR("Hmmm... Common slow path ramrods got stuck!\n"); + +#ifndef BNX2X_STOP_ON_ERROR +unload_error: +#endif + rc = bnx2x_func_stop(bp); + if (rc) { + BNX2X_ERR("Function stop failed!\n"); +#ifdef BNX2X_STOP_ON_ERROR + return; +#endif + } + + /* Disable HW interrupts, NAPI */ + bnx2x_netif_stop(bp, 1); + + /* Release IRQs */ + bnx2x_free_irq(bp); + + /* Reset the chip */ + rc = bnx2x_reset_hw(bp, reset_code); + if (rc) + BNX2X_ERR("HW_RESET failed\n"); + + + /* Report UNLOAD_DONE to MCP */ + bnx2x_send_unload_done(bp); +} + +void bnx2x_disable_close_the_gate(struct bnx2x *bp) +{ + u32 val; + + DP(NETIF_MSG_HW, "Disabling \"close the gates\"\n"); + + if (CHIP_IS_E1(bp)) { + int port = BP_PORT(bp); + u32 addr = port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : + MISC_REG_AEU_MASK_ATTN_FUNC_0; + + val = REG_RD(bp, addr); + val &= ~(0x300); + REG_WR(bp, addr, val); + } else { + val = REG_RD(bp, MISC_REG_AEU_GENERAL_MASK); + val &= ~(MISC_AEU_GENERAL_MASK_REG_AEU_PXP_CLOSE_MASK | + MISC_AEU_GENERAL_MASK_REG_AEU_NIG_CLOSE_MASK); + REG_WR(bp, MISC_REG_AEU_GENERAL_MASK, val); + } +} + +/* Close gates #2, #3 and #4: */ +static void bnx2x_set_234_gates(struct bnx2x *bp, bool close) +{ + u32 val; + + /* Gates #2 and #4a are closed/opened for "not E1" only */ + if (!CHIP_IS_E1(bp)) { + /* #4 */ + REG_WR(bp, PXP_REG_HST_DISCARD_DOORBELLS, !!close); + /* #2 */ + REG_WR(bp, PXP_REG_HST_DISCARD_INTERNAL_WRITES, !!close); + } + + /* #3 */ + if (CHIP_IS_E1x(bp)) { + /* Prevent interrupts from HC on both ports */ + val = REG_RD(bp, HC_REG_CONFIG_1); + REG_WR(bp, HC_REG_CONFIG_1, + (!close) ? (val | HC_CONFIG_1_REG_BLOCK_DISABLE_1) : + (val & ~(u32)HC_CONFIG_1_REG_BLOCK_DISABLE_1)); + + val = REG_RD(bp, HC_REG_CONFIG_0); + REG_WR(bp, HC_REG_CONFIG_0, + (!close) ? (val | HC_CONFIG_0_REG_BLOCK_DISABLE_0) : + (val & ~(u32)HC_CONFIG_0_REG_BLOCK_DISABLE_0)); + } else { + /* Prevent incomming interrupts in IGU */ + val = REG_RD(bp, IGU_REG_BLOCK_CONFIGURATION); + + REG_WR(bp, IGU_REG_BLOCK_CONFIGURATION, + (!close) ? + (val | IGU_BLOCK_CONFIGURATION_REG_BLOCK_ENABLE) : + (val & ~(u32)IGU_BLOCK_CONFIGURATION_REG_BLOCK_ENABLE)); + } + + DP(NETIF_MSG_HW, "%s gates #2, #3 and #4\n", + close ? "closing" : "opening"); + mmiowb(); +} + +#define SHARED_MF_CLP_MAGIC 0x80000000 /* `magic' bit */ + +static void bnx2x_clp_reset_prep(struct bnx2x *bp, u32 *magic_val) +{ + /* Do some magic... */ + u32 val = MF_CFG_RD(bp, shared_mf_config.clp_mb); + *magic_val = val & SHARED_MF_CLP_MAGIC; + MF_CFG_WR(bp, shared_mf_config.clp_mb, val | SHARED_MF_CLP_MAGIC); +} + +/** + * bnx2x_clp_reset_done - restore the value of the `magic' bit. + * + * @bp: driver handle + * @magic_val: old value of the `magic' bit. + */ +static void bnx2x_clp_reset_done(struct bnx2x *bp, u32 magic_val) +{ + /* Restore the `magic' bit value... */ + u32 val = MF_CFG_RD(bp, shared_mf_config.clp_mb); + MF_CFG_WR(bp, shared_mf_config.clp_mb, + (val & (~SHARED_MF_CLP_MAGIC)) | magic_val); +} + +/** + * bnx2x_reset_mcp_prep - prepare for MCP reset. + * + * @bp: driver handle + * @magic_val: old value of 'magic' bit. + * + * Takes care of CLP configurations. + */ +static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val) +{ + u32 shmem; + u32 validity_offset; + + DP(NETIF_MSG_HW, "Starting\n"); + + /* Set `magic' bit in order to save MF config */ + if (!CHIP_IS_E1(bp)) + bnx2x_clp_reset_prep(bp, magic_val); + + /* Get shmem offset */ + shmem = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); + validity_offset = offsetof(struct shmem_region, validity_map[0]); + + /* Clear validity map flags */ + if (shmem > 0) + REG_WR(bp, shmem + validity_offset, 0); +} + +#define MCP_TIMEOUT 5000 /* 5 seconds (in ms) */ +#define MCP_ONE_TIMEOUT 100 /* 100 ms */ + +/** + * bnx2x_mcp_wait_one - wait for MCP_ONE_TIMEOUT + * + * @bp: driver handle + */ +static inline void bnx2x_mcp_wait_one(struct bnx2x *bp) +{ + /* special handling for emulation and FPGA, + wait 10 times longer */ + if (CHIP_REV_IS_SLOW(bp)) + msleep(MCP_ONE_TIMEOUT*10); + else + msleep(MCP_ONE_TIMEOUT); +} + +/* + * initializes bp->common.shmem_base and waits for validity signature to appear + */ +static int bnx2x_init_shmem(struct bnx2x *bp) +{ + int cnt = 0; + u32 val = 0; + + do { + bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); + if (bp->common.shmem_base) { + val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]); + if (val & SHR_MEM_VALIDITY_MB) + return 0; + } + + bnx2x_mcp_wait_one(bp); + + } while (cnt++ < (MCP_TIMEOUT / MCP_ONE_TIMEOUT)); + + BNX2X_ERR("BAD MCP validity signature\n"); + + return -ENODEV; +} + +static int bnx2x_reset_mcp_comp(struct bnx2x *bp, u32 magic_val) +{ + int rc = bnx2x_init_shmem(bp); + + /* Restore the `magic' bit value */ + if (!CHIP_IS_E1(bp)) + bnx2x_clp_reset_done(bp, magic_val); + + return rc; +} + +static void bnx2x_pxp_prep(struct bnx2x *bp) +{ + if (!CHIP_IS_E1(bp)) { + REG_WR(bp, PXP2_REG_RD_START_INIT, 0); + REG_WR(bp, PXP2_REG_RQ_RBC_DONE, 0); + mmiowb(); + } +} + +/* + * Reset the whole chip except for: + * - PCIE core + * - PCI Glue, PSWHST, PXP/PXP2 RF (all controlled by + * one reset bit) + * - IGU + * - MISC (including AEU) + * - GRC + * - RBCN, RBCP + */ +static void bnx2x_process_kill_chip_reset(struct bnx2x *bp, bool global) +{ + u32 not_reset_mask1, reset_mask1, not_reset_mask2, reset_mask2; + u32 global_bits2, stay_reset2; + + /* + * Bits that have to be set in reset_mask2 if we want to reset 'global' + * (per chip) blocks. + */ + global_bits2 = + MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CPU | + MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CORE; + + /* Don't reset the following blocks */ + not_reset_mask1 = + MISC_REGISTERS_RESET_REG_1_RST_HC | + MISC_REGISTERS_RESET_REG_1_RST_PXPV | + MISC_REGISTERS_RESET_REG_1_RST_PXP; + + not_reset_mask2 = + MISC_REGISTERS_RESET_REG_2_RST_PCI_MDIO | + MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE | + MISC_REGISTERS_RESET_REG_2_RST_EMAC1_HARD_CORE | + MISC_REGISTERS_RESET_REG_2_RST_MISC_CORE | + MISC_REGISTERS_RESET_REG_2_RST_RBCN | + MISC_REGISTERS_RESET_REG_2_RST_GRC | + MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_REG_HARD_CORE | + MISC_REGISTERS_RESET_REG_2_RST_MCP_N_HARD_CORE_RST_B | + MISC_REGISTERS_RESET_REG_2_RST_ATC | + MISC_REGISTERS_RESET_REG_2_PGLC; + + /* + * Keep the following blocks in reset: + * - all xxMACs are handled by the bnx2x_link code. + */ + stay_reset2 = + MISC_REGISTERS_RESET_REG_2_RST_BMAC0 | + MISC_REGISTERS_RESET_REG_2_RST_BMAC1 | + MISC_REGISTERS_RESET_REG_2_RST_EMAC0 | + MISC_REGISTERS_RESET_REG_2_RST_EMAC1 | + MISC_REGISTERS_RESET_REG_2_UMAC0 | + MISC_REGISTERS_RESET_REG_2_UMAC1 | + MISC_REGISTERS_RESET_REG_2_XMAC | + MISC_REGISTERS_RESET_REG_2_XMAC_SOFT; + + /* Full reset masks according to the chip */ + reset_mask1 = 0xffffffff; + + if (CHIP_IS_E1(bp)) + reset_mask2 = 0xffff; + else if (CHIP_IS_E1H(bp)) + reset_mask2 = 0x1ffff; + else if (CHIP_IS_E2(bp)) + reset_mask2 = 0xfffff; + else /* CHIP_IS_E3 */ + reset_mask2 = 0x3ffffff; + + /* Don't reset global blocks unless we need to */ + if (!global) + reset_mask2 &= ~global_bits2; + + /* + * In case of attention in the QM, we need to reset PXP + * (MISC_REGISTERS_RESET_REG_2_RST_PXP_RQ_RD_WR) before QM + * because otherwise QM reset would release 'close the gates' shortly + * before resetting the PXP, then the PSWRQ would send a write + * request to PGLUE. Then when PXP is reset, PGLUE would try to + * read the payload data from PSWWR, but PSWWR would not + * respond. The write queue in PGLUE would stuck, dmae commands + * would not return. Therefore it's important to reset the second + * reset register (containing the + * MISC_REGISTERS_RESET_REG_2_RST_PXP_RQ_RD_WR bit) before the + * first one (containing the MISC_REGISTERS_RESET_REG_1_RST_QM + * bit). + */ + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + reset_mask2 & (~not_reset_mask2)); + + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + reset_mask1 & (~not_reset_mask1)); + + barrier(); + mmiowb(); + + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_SET, + reset_mask2 & (~stay_reset2)); + + barrier(); + mmiowb(); + + REG_WR(bp, GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, reset_mask1); + mmiowb(); +} + +/** + * bnx2x_er_poll_igu_vq - poll for pending writes bit. + * It should get cleared in no more than 1s. + * + * @bp: driver handle + * + * It should get cleared in no more than 1s. Returns 0 if + * pending writes bit gets cleared. + */ +static int bnx2x_er_poll_igu_vq(struct bnx2x *bp) +{ + u32 cnt = 1000; + u32 pend_bits = 0; + + do { + pend_bits = REG_RD(bp, IGU_REG_PENDING_BITS_STATUS); + + if (pend_bits == 0) + break; + + usleep_range(1000, 1000); + } while (cnt-- > 0); + + if (cnt <= 0) { + BNX2X_ERR("Still pending IGU requests pend_bits=%x!\n", + pend_bits); + return -EBUSY; + } + + return 0; +} + +static int bnx2x_process_kill(struct bnx2x *bp, bool global) +{ + int cnt = 1000; + u32 val = 0; + u32 sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1, pgl_exp_rom2; + + + /* Empty the Tetris buffer, wait for 1s */ + do { + sr_cnt = REG_RD(bp, PXP2_REG_RD_SR_CNT); + blk_cnt = REG_RD(bp, PXP2_REG_RD_BLK_CNT); + port_is_idle_0 = REG_RD(bp, PXP2_REG_RD_PORT_IS_IDLE_0); + port_is_idle_1 = REG_RD(bp, PXP2_REG_RD_PORT_IS_IDLE_1); + pgl_exp_rom2 = REG_RD(bp, PXP2_REG_PGL_EXP_ROM2); + if ((sr_cnt == 0x7e) && (blk_cnt == 0xa0) && + ((port_is_idle_0 & 0x1) == 0x1) && + ((port_is_idle_1 & 0x1) == 0x1) && + (pgl_exp_rom2 == 0xffffffff)) + break; + usleep_range(1000, 1000); + } while (cnt-- > 0); + + if (cnt <= 0) { + DP(NETIF_MSG_HW, "Tetris buffer didn't get empty or there" + " are still" + " outstanding read requests after 1s!\n"); + DP(NETIF_MSG_HW, "sr_cnt=0x%08x, blk_cnt=0x%08x," + " port_is_idle_0=0x%08x," + " port_is_idle_1=0x%08x, pgl_exp_rom2=0x%08x\n", + sr_cnt, blk_cnt, port_is_idle_0, port_is_idle_1, + pgl_exp_rom2); + return -EAGAIN; + } + + barrier(); + + /* Close gates #2, #3 and #4 */ + bnx2x_set_234_gates(bp, true); + + /* Poll for IGU VQs for 57712 and newer chips */ + if (!CHIP_IS_E1x(bp) && bnx2x_er_poll_igu_vq(bp)) + return -EAGAIN; + + + /* TBD: Indicate that "process kill" is in progress to MCP */ + + /* Clear "unprepared" bit */ + REG_WR(bp, MISC_REG_UNPREPARED, 0); + barrier(); + + /* Make sure all is written to the chip before the reset */ + mmiowb(); + + /* Wait for 1ms to empty GLUE and PCI-E core queues, + * PSWHST, GRC and PSWRD Tetris buffer. + */ + usleep_range(1000, 1000); + + /* Prepare to chip reset: */ + /* MCP */ + if (global) + bnx2x_reset_mcp_prep(bp, &val); + + /* PXP */ + bnx2x_pxp_prep(bp); + barrier(); + + /* reset the chip */ + bnx2x_process_kill_chip_reset(bp, global); + barrier(); + + /* Recover after reset: */ + /* MCP */ + if (global && bnx2x_reset_mcp_comp(bp, val)) + return -EAGAIN; + + /* TBD: Add resetting the NO_MCP mode DB here */ + + /* PXP */ + bnx2x_pxp_prep(bp); + + /* Open the gates #2, #3 and #4 */ + bnx2x_set_234_gates(bp, false); + + /* TBD: IGU/AEU preparation bring back the AEU/IGU to a + * reset state, re-enable attentions. */ + + return 0; +} + +int bnx2x_leader_reset(struct bnx2x *bp) +{ + int rc = 0; + bool global = bnx2x_reset_is_global(bp); + + /* Try to recover after the failure */ + if (bnx2x_process_kill(bp, global)) { + netdev_err(bp->dev, "Something bad had happen on engine %d! " + "Aii!\n", BP_PATH(bp)); + rc = -EAGAIN; + goto exit_leader_reset; + } + + /* + * Clear RESET_IN_PROGRES and RESET_GLOBAL bits and update the driver + * state. + */ + bnx2x_set_reset_done(bp); + if (global) + bnx2x_clear_reset_global(bp); + +exit_leader_reset: + bp->is_leader = 0; + bnx2x_release_leader_lock(bp); + smp_mb(); + return rc; +} + +static inline void bnx2x_recovery_failed(struct bnx2x *bp) +{ + netdev_err(bp->dev, "Recovery has failed. Power cycle is needed.\n"); + + /* Disconnect this device */ + netif_device_detach(bp->dev); + + /* + * Block ifup for all function on this engine until "process kill" + * or power cycle. + */ + bnx2x_set_reset_in_progress(bp); + + /* Shut down the power */ + bnx2x_set_power_state(bp, PCI_D3hot); + + bp->recovery_state = BNX2X_RECOVERY_FAILED; + + smp_mb(); +} + +/* + * Assumption: runs under rtnl lock. This together with the fact + * that it's called only from bnx2x_sp_rtnl() ensure that it + * will never be called when netif_running(bp->dev) is false. + */ +static void bnx2x_parity_recover(struct bnx2x *bp) +{ + bool global = false; + + DP(NETIF_MSG_HW, "Handling parity\n"); + while (1) { + switch (bp->recovery_state) { + case BNX2X_RECOVERY_INIT: + DP(NETIF_MSG_HW, "State is BNX2X_RECOVERY_INIT\n"); + bnx2x_chk_parity_attn(bp, &global, false); + + /* Try to get a LEADER_LOCK HW lock */ + if (bnx2x_trylock_leader_lock(bp)) { + bnx2x_set_reset_in_progress(bp); + /* + * Check if there is a global attention and if + * there was a global attention, set the global + * reset bit. + */ + + if (global) + bnx2x_set_reset_global(bp); + + bp->is_leader = 1; + } + + /* Stop the driver */ + /* If interface has been removed - break */ + if (bnx2x_nic_unload(bp, UNLOAD_RECOVERY)) + return; + + bp->recovery_state = BNX2X_RECOVERY_WAIT; + + /* + * Reset MCP command sequence number and MCP mail box + * sequence as we are going to reset the MCP. + */ + if (global) { + bp->fw_seq = 0; + bp->fw_drv_pulse_wr_seq = 0; + } + + /* Ensure "is_leader", MCP command sequence and + * "recovery_state" update values are seen on other + * CPUs. + */ + smp_mb(); + break; + + case BNX2X_RECOVERY_WAIT: + DP(NETIF_MSG_HW, "State is BNX2X_RECOVERY_WAIT\n"); + if (bp->is_leader) { + int other_engine = BP_PATH(bp) ? 0 : 1; + u32 other_load_counter = + bnx2x_get_load_cnt(bp, other_engine); + u32 load_counter = + bnx2x_get_load_cnt(bp, BP_PATH(bp)); + global = bnx2x_reset_is_global(bp); + + /* + * In case of a parity in a global block, let + * the first leader that performs a + * leader_reset() reset the global blocks in + * order to clear global attentions. Otherwise + * the the gates will remain closed for that + * engine. + */ + if (load_counter || + (global && other_load_counter)) { + /* Wait until all other functions get + * down. + */ + schedule_delayed_work(&bp->sp_rtnl_task, + HZ/10); + return; + } else { + /* If all other functions got down - + * try to bring the chip back to + * normal. In any case it's an exit + * point for a leader. + */ + if (bnx2x_leader_reset(bp)) { + bnx2x_recovery_failed(bp); + return; + } + + /* If we are here, means that the + * leader has succeeded and doesn't + * want to be a leader any more. Try + * to continue as a none-leader. + */ + break; + } + } else { /* non-leader */ + if (!bnx2x_reset_is_done(bp, BP_PATH(bp))) { + /* Try to get a LEADER_LOCK HW lock as + * long as a former leader may have + * been unloaded by the user or + * released a leadership by another + * reason. + */ + if (bnx2x_trylock_leader_lock(bp)) { + /* I'm a leader now! Restart a + * switch case. + */ + bp->is_leader = 1; + break; + } + + schedule_delayed_work(&bp->sp_rtnl_task, + HZ/10); + return; + + } else { + /* + * If there was a global attention, wait + * for it to be cleared. + */ + if (bnx2x_reset_is_global(bp)) { + schedule_delayed_work( + &bp->sp_rtnl_task, + HZ/10); + return; + } + + if (bnx2x_nic_load(bp, LOAD_NORMAL)) + bnx2x_recovery_failed(bp); + else { + bp->recovery_state = + BNX2X_RECOVERY_DONE; + smp_mb(); + } + + return; + } + } + default: + return; + } + } +} + +/* bnx2x_nic_unload() flushes the bnx2x_wq, thus reset task is + * scheduled on a general queue in order to prevent a dead lock. + */ +static void bnx2x_sp_rtnl_task(struct work_struct *work) +{ + struct bnx2x *bp = container_of(work, struct bnx2x, sp_rtnl_task.work); + + rtnl_lock(); + + if (!netif_running(bp->dev)) + goto sp_rtnl_exit; + + /* if stop on error is defined no recovery flows should be executed */ +#ifdef BNX2X_STOP_ON_ERROR + BNX2X_ERR("recovery flow called but STOP_ON_ERROR defined " + "so reset not done to allow debug dump,\n" + "you will need to reboot when done\n"); + goto sp_rtnl_not_reset; +#endif + + if (unlikely(bp->recovery_state != BNX2X_RECOVERY_DONE)) { + /* + * Clear all pending SP commands as we are going to reset the + * function anyway. + */ + bp->sp_rtnl_state = 0; + smp_mb(); + + bnx2x_parity_recover(bp); + + goto sp_rtnl_exit; + } + + if (test_and_clear_bit(BNX2X_SP_RTNL_TX_TIMEOUT, &bp->sp_rtnl_state)) { + /* + * Clear all pending SP commands as we are going to reset the + * function anyway. + */ + bp->sp_rtnl_state = 0; + smp_mb(); + + bnx2x_nic_unload(bp, UNLOAD_NORMAL); + bnx2x_nic_load(bp, LOAD_NORMAL); + + goto sp_rtnl_exit; + } +#ifdef BNX2X_STOP_ON_ERROR +sp_rtnl_not_reset: +#endif + if (test_and_clear_bit(BNX2X_SP_RTNL_SETUP_TC, &bp->sp_rtnl_state)) + bnx2x_setup_tc(bp->dev, bp->dcbx_port_params.ets.num_of_cos); + +sp_rtnl_exit: + rtnl_unlock(); +} + +/* end of nic load/unload */ + +static void bnx2x_period_task(struct work_struct *work) +{ + struct bnx2x *bp = container_of(work, struct bnx2x, period_task.work); + + if (!netif_running(bp->dev)) + goto period_task_exit; + + if (CHIP_REV_IS_SLOW(bp)) { + BNX2X_ERR("period task called on emulation, ignoring\n"); + goto period_task_exit; + } + + bnx2x_acquire_phy_lock(bp); + /* + * The barrier is needed to ensure the ordering between the writing to + * the bp->port.pmf in the bnx2x_nic_load() or bnx2x_pmf_update() and + * the reading here. + */ + smp_mb(); + if (bp->port.pmf) { + bnx2x_period_func(&bp->link_params, &bp->link_vars); + + /* Re-queue task in 1 sec */ + queue_delayed_work(bnx2x_wq, &bp->period_task, 1*HZ); + } + + bnx2x_release_phy_lock(bp); +period_task_exit: + return; +} + +/* + * Init service functions + */ + +static u32 bnx2x_get_pretend_reg(struct bnx2x *bp) +{ + u32 base = PXP2_REG_PGL_PRETEND_FUNC_F0; + u32 stride = PXP2_REG_PGL_PRETEND_FUNC_F1 - base; + return base + (BP_ABS_FUNC(bp)) * stride; +} + +static void bnx2x_undi_int_disable_e1h(struct bnx2x *bp) +{ + u32 reg = bnx2x_get_pretend_reg(bp); + + /* Flush all outstanding writes */ + mmiowb(); + + /* Pretend to be function 0 */ + REG_WR(bp, reg, 0); + REG_RD(bp, reg); /* Flush the GRC transaction (in the chip) */ + + /* From now we are in the "like-E1" mode */ + bnx2x_int_disable(bp); + + /* Flush all outstanding writes */ + mmiowb(); + + /* Restore the original function */ + REG_WR(bp, reg, BP_ABS_FUNC(bp)); + REG_RD(bp, reg); +} + +static inline void bnx2x_undi_int_disable(struct bnx2x *bp) +{ + if (CHIP_IS_E1(bp)) + bnx2x_int_disable(bp); + else + bnx2x_undi_int_disable_e1h(bp); +} + +static void __devinit bnx2x_undi_unload(struct bnx2x *bp) +{ + u32 val; + + /* Check if there is any driver already loaded */ + val = REG_RD(bp, MISC_REG_UNPREPARED); + if (val == 0x1) { + /* Check if it is the UNDI driver + * UNDI driver initializes CID offset for normal bell to 0x7 + */ + bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); + val = REG_RD(bp, DORQ_REG_NORM_CID_OFST); + if (val == 0x7) { + u32 reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; + /* save our pf_num */ + int orig_pf_num = bp->pf_num; + int port; + u32 swap_en, swap_val, value; + + /* clear the UNDI indication */ + REG_WR(bp, DORQ_REG_NORM_CID_OFST, 0); + + BNX2X_DEV_INFO("UNDI is active! reset device\n"); + + /* try unload UNDI on port 0 */ + bp->pf_num = 0; + bp->fw_seq = + (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + reset_code = bnx2x_fw_command(bp, reset_code, 0); + + /* if UNDI is loaded on the other port */ + if (reset_code != FW_MSG_CODE_DRV_UNLOAD_COMMON) { + + /* send "DONE" for previous unload */ + bnx2x_fw_command(bp, + DRV_MSG_CODE_UNLOAD_DONE, 0); + + /* unload UNDI on port 1 */ + bp->pf_num = 1; + bp->fw_seq = + (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS; + + bnx2x_fw_command(bp, reset_code, 0); + } + + /* now it's safe to release the lock */ + bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); + + bnx2x_undi_int_disable(bp); + port = BP_PORT(bp); + + /* close input traffic and wait for it */ + /* Do not rcv packets to BRB */ + REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_DRV_MASK : + NIG_REG_LLH0_BRB1_DRV_MASK), 0x0); + /* Do not direct rcv packets that are not for MCP to + * the BRB */ + REG_WR(bp, (port ? NIG_REG_LLH1_BRB1_NOT_MCP : + NIG_REG_LLH0_BRB1_NOT_MCP), 0x0); + /* clear AEU */ + REG_WR(bp, (port ? MISC_REG_AEU_MASK_ATTN_FUNC_1 : + MISC_REG_AEU_MASK_ATTN_FUNC_0), 0); + msleep(10); + + /* save NIG port swap info */ + swap_val = REG_RD(bp, NIG_REG_PORT_SWAP); + swap_en = REG_RD(bp, NIG_REG_STRAP_OVERRIDE); + /* reset device */ + REG_WR(bp, + GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_CLEAR, + 0xd3ffffff); + + value = 0x1400; + if (CHIP_IS_E3(bp)) { + value |= MISC_REGISTERS_RESET_REG_2_MSTAT0; + value |= MISC_REGISTERS_RESET_REG_2_MSTAT1; + } + + REG_WR(bp, + GRCBASE_MISC + MISC_REGISTERS_RESET_REG_2_CLEAR, + value); + + /* take the NIG out of reset and restore swap values */ + REG_WR(bp, + GRCBASE_MISC + MISC_REGISTERS_RESET_REG_1_SET, + MISC_REGISTERS_RESET_REG_1_RST_NIG); + REG_WR(bp, NIG_REG_PORT_SWAP, swap_val); + REG_WR(bp, NIG_REG_STRAP_OVERRIDE, swap_en); + + /* send unload done to the MCP */ + bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0); + + /* restore our func and fw_seq */ + bp->pf_num = orig_pf_num; + bp->fw_seq = + (SHMEM_RD(bp, func_mb[bp->pf_num].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + } else + bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_UNDI); + } +} + +static void __devinit bnx2x_get_common_hwinfo(struct bnx2x *bp) +{ + u32 val, val2, val3, val4, id; + u16 pmc; + + /* Get the chip revision id and number. */ + /* chip num:16-31, rev:12-15, metal:4-11, bond_id:0-3 */ + val = REG_RD(bp, MISC_REG_CHIP_NUM); + id = ((val & 0xffff) << 16); + val = REG_RD(bp, MISC_REG_CHIP_REV); + id |= ((val & 0xf) << 12); + val = REG_RD(bp, MISC_REG_CHIP_METAL); + id |= ((val & 0xff) << 4); + val = REG_RD(bp, MISC_REG_BOND_ID); + id |= (val & 0xf); + bp->common.chip_id = id; + + /* Set doorbell size */ + bp->db_size = (1 << BNX2X_DB_SHIFT); + + if (!CHIP_IS_E1x(bp)) { + val = REG_RD(bp, MISC_REG_PORT4MODE_EN_OVWR); + if ((val & 1) == 0) + val = REG_RD(bp, MISC_REG_PORT4MODE_EN); + else + val = (val >> 1) & 1; + BNX2X_DEV_INFO("chip is in %s\n", val ? "4_PORT_MODE" : + "2_PORT_MODE"); + bp->common.chip_port_mode = val ? CHIP_4_PORT_MODE : + CHIP_2_PORT_MODE; + + if (CHIP_MODE_IS_4_PORT(bp)) + bp->pfid = (bp->pf_num >> 1); /* 0..3 */ + else + bp->pfid = (bp->pf_num & 0x6); /* 0, 2, 4, 6 */ + } else { + bp->common.chip_port_mode = CHIP_PORT_MODE_NONE; /* N/A */ + bp->pfid = bp->pf_num; /* 0..7 */ + } + + bp->link_params.chip_id = bp->common.chip_id; + BNX2X_DEV_INFO("chip ID is 0x%x\n", id); + + val = (REG_RD(bp, 0x2874) & 0x55); + if ((bp->common.chip_id & 0x1) || + (CHIP_IS_E1(bp) && val) || (CHIP_IS_E1H(bp) && (val == 0x55))) { + bp->flags |= ONE_PORT_FLAG; + BNX2X_DEV_INFO("single port device\n"); + } + + val = REG_RD(bp, MCP_REG_MCPR_NVM_CFG4); + bp->common.flash_size = (BNX2X_NVRAM_1MB_SIZE << + (val & MCPR_NVM_CFG4_FLASH_SIZE)); + BNX2X_DEV_INFO("flash_size 0x%x (%d)\n", + bp->common.flash_size, bp->common.flash_size); + + bnx2x_init_shmem(bp); + + + + bp->common.shmem2_base = REG_RD(bp, (BP_PATH(bp) ? + MISC_REG_GENERIC_CR_1 : + MISC_REG_GENERIC_CR_0)); + + bp->link_params.shmem_base = bp->common.shmem_base; + bp->link_params.shmem2_base = bp->common.shmem2_base; + BNX2X_DEV_INFO("shmem offset 0x%x shmem2 offset 0x%x\n", + bp->common.shmem_base, bp->common.shmem2_base); + + if (!bp->common.shmem_base) { + BNX2X_DEV_INFO("MCP not active\n"); + bp->flags |= NO_MCP_FLAG; + return; + } + + bp->common.hw_config = SHMEM_RD(bp, dev_info.shared_hw_config.config); + BNX2X_DEV_INFO("hw_config 0x%08x\n", bp->common.hw_config); + + bp->link_params.hw_led_mode = ((bp->common.hw_config & + SHARED_HW_CFG_LED_MODE_MASK) >> + SHARED_HW_CFG_LED_MODE_SHIFT); + + bp->link_params.feature_config_flags = 0; + val = SHMEM_RD(bp, dev_info.shared_feature_config.config); + if (val & SHARED_FEAT_CFG_OVERRIDE_PREEMPHASIS_CFG_ENABLED) + bp->link_params.feature_config_flags |= + FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED; + else + bp->link_params.feature_config_flags &= + ~FEATURE_CONFIG_OVERRIDE_PREEMPHASIS_ENABLED; + + val = SHMEM_RD(bp, dev_info.bc_rev) >> 8; + bp->common.bc_ver = val; + BNX2X_DEV_INFO("bc_ver %X\n", val); + if (val < BNX2X_BC_VER) { + /* for now only warn + * later we might need to enforce this */ + BNX2X_ERR("This driver needs bc_ver %X but found %X, " + "please upgrade BC\n", BNX2X_BC_VER, val); + } + bp->link_params.feature_config_flags |= + (val >= REQ_BC_VER_4_VRFY_FIRST_PHY_OPT_MDL) ? + FEATURE_CONFIG_BC_SUPPORTS_OPT_MDL_VRFY : 0; + + bp->link_params.feature_config_flags |= + (val >= REQ_BC_VER_4_VRFY_SPECIFIC_PHY_OPT_MDL) ? + FEATURE_CONFIG_BC_SUPPORTS_DUAL_PHY_OPT_MDL_VRFY : 0; + + bp->link_params.feature_config_flags |= + (val >= REQ_BC_VER_4_SFP_TX_DISABLE_SUPPORTED) ? + FEATURE_CONFIG_BC_SUPPORTS_SFP_TX_DISABLED : 0; + + pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_PMC, &pmc); + bp->flags |= (pmc & PCI_PM_CAP_PME_D3cold) ? 0 : NO_WOL_FLAG; + + BNX2X_DEV_INFO("%sWoL capable\n", + (bp->flags & NO_WOL_FLAG) ? "not " : ""); + + val = SHMEM_RD(bp, dev_info.shared_hw_config.part_num); + val2 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[4]); + val3 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[8]); + val4 = SHMEM_RD(bp, dev_info.shared_hw_config.part_num[12]); + + dev_info(&bp->pdev->dev, "part number %X-%X-%X-%X\n", + val, val2, val3, val4); +} + +#define IGU_FID(val) GET_FIELD((val), IGU_REG_MAPPING_MEMORY_FID) +#define IGU_VEC(val) GET_FIELD((val), IGU_REG_MAPPING_MEMORY_VECTOR) + +static void __devinit bnx2x_get_igu_cam_info(struct bnx2x *bp) +{ + int pfid = BP_FUNC(bp); + int vn = BP_E1HVN(bp); + int igu_sb_id; + u32 val; + u8 fid, igu_sb_cnt = 0; + + bp->igu_base_sb = 0xff; + if (CHIP_INT_MODE_IS_BC(bp)) { + igu_sb_cnt = bp->igu_sb_cnt; + bp->igu_base_sb = (CHIP_MODE_IS_4_PORT(bp) ? pfid : vn) * + FP_SB_MAX_E1x; + + bp->igu_dsb_id = E1HVN_MAX * FP_SB_MAX_E1x + + (CHIP_MODE_IS_4_PORT(bp) ? pfid : vn); + + return; + } + + /* IGU in normal mode - read CAM */ + for (igu_sb_id = 0; igu_sb_id < IGU_REG_MAPPING_MEMORY_SIZE; + igu_sb_id++) { + val = REG_RD(bp, IGU_REG_MAPPING_MEMORY + igu_sb_id * 4); + if (!(val & IGU_REG_MAPPING_MEMORY_VALID)) + continue; + fid = IGU_FID(val); + if ((fid & IGU_FID_ENCODE_IS_PF)) { + if ((fid & IGU_FID_PF_NUM_MASK) != pfid) + continue; + if (IGU_VEC(val) == 0) + /* default status block */ + bp->igu_dsb_id = igu_sb_id; + else { + if (bp->igu_base_sb == 0xff) + bp->igu_base_sb = igu_sb_id; + igu_sb_cnt++; + } + } + } + +#ifdef CONFIG_PCI_MSI + /* + * It's expected that number of CAM entries for this functions is equal + * to the number evaluated based on the MSI-X table size. We want a + * harsh warning if these values are different! + */ + WARN_ON(bp->igu_sb_cnt != igu_sb_cnt); +#endif + + if (igu_sb_cnt == 0) + BNX2X_ERR("CAM configuration error\n"); +} + +static void __devinit bnx2x_link_settings_supported(struct bnx2x *bp, + u32 switch_cfg) +{ + int cfg_size = 0, idx, port = BP_PORT(bp); + + /* Aggregation of supported attributes of all external phys */ + bp->port.supported[0] = 0; + bp->port.supported[1] = 0; + switch (bp->link_params.num_phys) { + case 1: + bp->port.supported[0] = bp->link_params.phy[INT_PHY].supported; + cfg_size = 1; + break; + case 2: + bp->port.supported[0] = bp->link_params.phy[EXT_PHY1].supported; + cfg_size = 1; + break; + case 3: + if (bp->link_params.multi_phy_config & + PORT_HW_CFG_PHY_SWAPPED_ENABLED) { + bp->port.supported[1] = + bp->link_params.phy[EXT_PHY1].supported; + bp->port.supported[0] = + bp->link_params.phy[EXT_PHY2].supported; + } else { + bp->port.supported[0] = + bp->link_params.phy[EXT_PHY1].supported; + bp->port.supported[1] = + bp->link_params.phy[EXT_PHY2].supported; + } + cfg_size = 2; + break; + } + + if (!(bp->port.supported[0] || bp->port.supported[1])) { + BNX2X_ERR("NVRAM config error. BAD phy config." + "PHY1 config 0x%x, PHY2 config 0x%x\n", + SHMEM_RD(bp, + dev_info.port_hw_config[port].external_phy_config), + SHMEM_RD(bp, + dev_info.port_hw_config[port].external_phy_config2)); + return; + } + + if (CHIP_IS_E3(bp)) + bp->port.phy_addr = REG_RD(bp, MISC_REG_WC0_CTRL_PHY_ADDR); + else { + switch (switch_cfg) { + case SWITCH_CFG_1G: + bp->port.phy_addr = REG_RD( + bp, NIG_REG_SERDES0_CTRL_PHY_ADDR + port*0x10); + break; + case SWITCH_CFG_10G: + bp->port.phy_addr = REG_RD( + bp, NIG_REG_XGXS0_CTRL_PHY_ADDR + port*0x18); + break; + default: + BNX2X_ERR("BAD switch_cfg link_config 0x%x\n", + bp->port.link_config[0]); + return; + } + } + BNX2X_DEV_INFO("phy_addr 0x%x\n", bp->port.phy_addr); + /* mask what we support according to speed_cap_mask per configuration */ + for (idx = 0; idx < cfg_size; idx++) { + if (!(bp->link_params.speed_cap_mask[idx] & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_HALF)) + bp->port.supported[idx] &= ~SUPPORTED_10baseT_Half; + + if (!(bp->link_params.speed_cap_mask[idx] & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL)) + bp->port.supported[idx] &= ~SUPPORTED_10baseT_Full; + + if (!(bp->link_params.speed_cap_mask[idx] & + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_HALF)) + bp->port.supported[idx] &= ~SUPPORTED_100baseT_Half; + + if (!(bp->link_params.speed_cap_mask[idx] & + PORT_HW_CFG_SPEED_CAPABILITY_D0_100M_FULL)) + bp->port.supported[idx] &= ~SUPPORTED_100baseT_Full; + + if (!(bp->link_params.speed_cap_mask[idx] & + PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) + bp->port.supported[idx] &= ~(SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full); + + if (!(bp->link_params.speed_cap_mask[idx] & + PORT_HW_CFG_SPEED_CAPABILITY_D0_2_5G)) + bp->port.supported[idx] &= ~SUPPORTED_2500baseX_Full; + + if (!(bp->link_params.speed_cap_mask[idx] & + PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) + bp->port.supported[idx] &= ~SUPPORTED_10000baseT_Full; + + } + + BNX2X_DEV_INFO("supported 0x%x 0x%x\n", bp->port.supported[0], + bp->port.supported[1]); +} + +static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp) +{ + u32 link_config, idx, cfg_size = 0; + bp->port.advertising[0] = 0; + bp->port.advertising[1] = 0; + switch (bp->link_params.num_phys) { + case 1: + case 2: + cfg_size = 1; + break; + case 3: + cfg_size = 2; + break; + } + for (idx = 0; idx < cfg_size; idx++) { + bp->link_params.req_duplex[idx] = DUPLEX_FULL; + link_config = bp->port.link_config[idx]; + switch (link_config & PORT_FEATURE_LINK_SPEED_MASK) { + case PORT_FEATURE_LINK_SPEED_AUTO: + if (bp->port.supported[idx] & SUPPORTED_Autoneg) { + bp->link_params.req_line_speed[idx] = + SPEED_AUTO_NEG; + bp->port.advertising[idx] |= + bp->port.supported[idx]; + } else { + /* force 10G, no AN */ + bp->link_params.req_line_speed[idx] = + SPEED_10000; + bp->port.advertising[idx] |= + (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); + continue; + } + break; + + case PORT_FEATURE_LINK_SPEED_10M_FULL: + if (bp->port.supported[idx] & SUPPORTED_10baseT_Full) { + bp->link_params.req_line_speed[idx] = + SPEED_10; + bp->port.advertising[idx] |= + (ADVERTISED_10baseT_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + link_config, + bp->link_params.speed_cap_mask[idx]); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_10M_HALF: + if (bp->port.supported[idx] & SUPPORTED_10baseT_Half) { + bp->link_params.req_line_speed[idx] = + SPEED_10; + bp->link_params.req_duplex[idx] = + DUPLEX_HALF; + bp->port.advertising[idx] |= + (ADVERTISED_10baseT_Half | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + link_config, + bp->link_params.speed_cap_mask[idx]); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_100M_FULL: + if (bp->port.supported[idx] & + SUPPORTED_100baseT_Full) { + bp->link_params.req_line_speed[idx] = + SPEED_100; + bp->port.advertising[idx] |= + (ADVERTISED_100baseT_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + link_config, + bp->link_params.speed_cap_mask[idx]); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_100M_HALF: + if (bp->port.supported[idx] & + SUPPORTED_100baseT_Half) { + bp->link_params.req_line_speed[idx] = + SPEED_100; + bp->link_params.req_duplex[idx] = + DUPLEX_HALF; + bp->port.advertising[idx] |= + (ADVERTISED_100baseT_Half | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + link_config, + bp->link_params.speed_cap_mask[idx]); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_1G: + if (bp->port.supported[idx] & + SUPPORTED_1000baseT_Full) { + bp->link_params.req_line_speed[idx] = + SPEED_1000; + bp->port.advertising[idx] |= + (ADVERTISED_1000baseT_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + link_config, + bp->link_params.speed_cap_mask[idx]); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_2_5G: + if (bp->port.supported[idx] & + SUPPORTED_2500baseX_Full) { + bp->link_params.req_line_speed[idx] = + SPEED_2500; + bp->port.advertising[idx] |= + (ADVERTISED_2500baseX_Full | + ADVERTISED_TP); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + link_config, + bp->link_params.speed_cap_mask[idx]); + return; + } + break; + + case PORT_FEATURE_LINK_SPEED_10G_CX4: + if (bp->port.supported[idx] & + SUPPORTED_10000baseT_Full) { + bp->link_params.req_line_speed[idx] = + SPEED_10000; + bp->port.advertising[idx] |= + (ADVERTISED_10000baseT_Full | + ADVERTISED_FIBRE); + } else { + BNX2X_ERR("NVRAM config error. " + "Invalid link_config 0x%x" + " speed_cap_mask 0x%x\n", + link_config, + bp->link_params.speed_cap_mask[idx]); + return; + } + break; + case PORT_FEATURE_LINK_SPEED_20G: + bp->link_params.req_line_speed[idx] = SPEED_20000; + + break; + default: + BNX2X_ERR("NVRAM config error. " + "BAD link speed link_config 0x%x\n", + link_config); + bp->link_params.req_line_speed[idx] = + SPEED_AUTO_NEG; + bp->port.advertising[idx] = + bp->port.supported[idx]; + break; + } + + bp->link_params.req_flow_ctrl[idx] = (link_config & + PORT_FEATURE_FLOW_CONTROL_MASK); + if ((bp->link_params.req_flow_ctrl[idx] == + BNX2X_FLOW_CTRL_AUTO) && + !(bp->port.supported[idx] & SUPPORTED_Autoneg)) { + bp->link_params.req_flow_ctrl[idx] = + BNX2X_FLOW_CTRL_NONE; + } + + BNX2X_DEV_INFO("req_line_speed %d req_duplex %d req_flow_ctrl" + " 0x%x advertising 0x%x\n", + bp->link_params.req_line_speed[idx], + bp->link_params.req_duplex[idx], + bp->link_params.req_flow_ctrl[idx], + bp->port.advertising[idx]); + } +} + +static void __devinit bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi) +{ + mac_hi = cpu_to_be16(mac_hi); + mac_lo = cpu_to_be32(mac_lo); + memcpy(mac_buf, &mac_hi, sizeof(mac_hi)); + memcpy(mac_buf + sizeof(mac_hi), &mac_lo, sizeof(mac_lo)); +} + +static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + u32 config; + u32 ext_phy_type, ext_phy_config; + + bp->link_params.bp = bp; + bp->link_params.port = port; + + bp->link_params.lane_config = + SHMEM_RD(bp, dev_info.port_hw_config[port].lane_config); + + bp->link_params.speed_cap_mask[0] = + SHMEM_RD(bp, + dev_info.port_hw_config[port].speed_capability_mask); + bp->link_params.speed_cap_mask[1] = + SHMEM_RD(bp, + dev_info.port_hw_config[port].speed_capability_mask2); + bp->port.link_config[0] = + SHMEM_RD(bp, dev_info.port_feature_config[port].link_config); + + bp->port.link_config[1] = + SHMEM_RD(bp, dev_info.port_feature_config[port].link_config2); + + bp->link_params.multi_phy_config = + SHMEM_RD(bp, dev_info.port_hw_config[port].multi_phy_config); + /* If the device is capable of WoL, set the default state according + * to the HW + */ + config = SHMEM_RD(bp, dev_info.port_feature_config[port].config); + bp->wol = (!(bp->flags & NO_WOL_FLAG) && + (config & PORT_FEATURE_WOL_ENABLED)); + + BNX2X_DEV_INFO("lane_config 0x%08x " + "speed_cap_mask0 0x%08x link_config0 0x%08x\n", + bp->link_params.lane_config, + bp->link_params.speed_cap_mask[0], + bp->port.link_config[0]); + + bp->link_params.switch_cfg = (bp->port.link_config[0] & + PORT_FEATURE_CONNECTED_SWITCH_MASK); + bnx2x_phy_probe(&bp->link_params); + bnx2x_link_settings_supported(bp, bp->link_params.switch_cfg); + + bnx2x_link_settings_requested(bp); + + /* + * If connected directly, work with the internal PHY, otherwise, work + * with the external PHY + */ + ext_phy_config = + SHMEM_RD(bp, + dev_info.port_hw_config[port].external_phy_config); + ext_phy_type = XGXS_EXT_PHY_TYPE(ext_phy_config); + if (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) + bp->mdio.prtad = bp->port.phy_addr; + + else if ((ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE) && + (ext_phy_type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)) + bp->mdio.prtad = + XGXS_EXT_PHY_ADDR(ext_phy_config); + + /* + * Check if hw lock is required to access MDC/MDIO bus to the PHY(s) + * In MF mode, it is set to cover self test cases + */ + if (IS_MF(bp)) + bp->port.need_hw_lock = 1; + else + bp->port.need_hw_lock = bnx2x_hw_lock_required(bp, + bp->common.shmem_base, + bp->common.shmem2_base); +} + +#ifdef BCM_CNIC +static void __devinit bnx2x_get_cnic_info(struct bnx2x *bp) +{ + int port = BP_PORT(bp); + int func = BP_ABS_FUNC(bp); + + u32 max_iscsi_conn = FW_ENCODE_32BIT_PATTERN ^ SHMEM_RD(bp, + drv_lic_key[port].max_iscsi_conn); + u32 max_fcoe_conn = FW_ENCODE_32BIT_PATTERN ^ SHMEM_RD(bp, + drv_lic_key[port].max_fcoe_conn); + + /* Get the number of maximum allowed iSCSI and FCoE connections */ + bp->cnic_eth_dev.max_iscsi_conn = + (max_iscsi_conn & BNX2X_MAX_ISCSI_INIT_CONN_MASK) >> + BNX2X_MAX_ISCSI_INIT_CONN_SHIFT; + + bp->cnic_eth_dev.max_fcoe_conn = + (max_fcoe_conn & BNX2X_MAX_FCOE_INIT_CONN_MASK) >> + BNX2X_MAX_FCOE_INIT_CONN_SHIFT; + + /* Read the WWN: */ + if (!IS_MF(bp)) { + /* Port info */ + bp->cnic_eth_dev.fcoe_wwn_port_name_hi = + SHMEM_RD(bp, + dev_info.port_hw_config[port]. + fcoe_wwn_port_name_upper); + bp->cnic_eth_dev.fcoe_wwn_port_name_lo = + SHMEM_RD(bp, + dev_info.port_hw_config[port]. + fcoe_wwn_port_name_lower); + + /* Node info */ + bp->cnic_eth_dev.fcoe_wwn_node_name_hi = + SHMEM_RD(bp, + dev_info.port_hw_config[port]. + fcoe_wwn_node_name_upper); + bp->cnic_eth_dev.fcoe_wwn_node_name_lo = + SHMEM_RD(bp, + dev_info.port_hw_config[port]. + fcoe_wwn_node_name_lower); + } else if (!IS_MF_SD(bp)) { + u32 cfg = MF_CFG_RD(bp, func_ext_config[func].func_cfg); + + /* + * Read the WWN info only if the FCoE feature is enabled for + * this function. + */ + if (cfg & MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD) { + /* Port info */ + bp->cnic_eth_dev.fcoe_wwn_port_name_hi = + MF_CFG_RD(bp, func_ext_config[func]. + fcoe_wwn_port_name_upper); + bp->cnic_eth_dev.fcoe_wwn_port_name_lo = + MF_CFG_RD(bp, func_ext_config[func]. + fcoe_wwn_port_name_lower); + + /* Node info */ + bp->cnic_eth_dev.fcoe_wwn_node_name_hi = + MF_CFG_RD(bp, func_ext_config[func]. + fcoe_wwn_node_name_upper); + bp->cnic_eth_dev.fcoe_wwn_node_name_lo = + MF_CFG_RD(bp, func_ext_config[func]. + fcoe_wwn_node_name_lower); + } + } + + BNX2X_DEV_INFO("max_iscsi_conn 0x%x max_fcoe_conn 0x%x\n", + bp->cnic_eth_dev.max_iscsi_conn, + bp->cnic_eth_dev.max_fcoe_conn); + + /* + * If maximum allowed number of connections is zero - + * disable the feature. + */ + if (!bp->cnic_eth_dev.max_iscsi_conn) + bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG; + + if (!bp->cnic_eth_dev.max_fcoe_conn) + bp->flags |= NO_FCOE_FLAG; +} +#endif + +static void __devinit bnx2x_get_mac_hwinfo(struct bnx2x *bp) +{ + u32 val, val2; + int func = BP_ABS_FUNC(bp); + int port = BP_PORT(bp); +#ifdef BCM_CNIC + u8 *iscsi_mac = bp->cnic_eth_dev.iscsi_mac; + u8 *fip_mac = bp->fip_mac; +#endif + + /* Zero primary MAC configuration */ + memset(bp->dev->dev_addr, 0, ETH_ALEN); + + if (BP_NOMCP(bp)) { + BNX2X_ERROR("warning: random MAC workaround active\n"); + random_ether_addr(bp->dev->dev_addr); + } else if (IS_MF(bp)) { + val2 = MF_CFG_RD(bp, func_mf_config[func].mac_upper); + val = MF_CFG_RD(bp, func_mf_config[func].mac_lower); + if ((val2 != FUNC_MF_CFG_UPPERMAC_DEFAULT) && + (val != FUNC_MF_CFG_LOWERMAC_DEFAULT)) + bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2); + +#ifdef BCM_CNIC + /* iSCSI and FCoE NPAR MACs: if there is no either iSCSI or + * FCoE MAC then the appropriate feature should be disabled. + */ + if (IS_MF_SI(bp)) { + u32 cfg = MF_CFG_RD(bp, func_ext_config[func].func_cfg); + if (cfg & MACP_FUNC_CFG_FLAGS_ISCSI_OFFLOAD) { + val2 = MF_CFG_RD(bp, func_ext_config[func]. + iscsi_mac_addr_upper); + val = MF_CFG_RD(bp, func_ext_config[func]. + iscsi_mac_addr_lower); + bnx2x_set_mac_buf(iscsi_mac, val, val2); + BNX2X_DEV_INFO("Read iSCSI MAC: " + BNX2X_MAC_FMT"\n", + BNX2X_MAC_PRN_LIST(iscsi_mac)); + } else + bp->flags |= NO_ISCSI_OOO_FLAG | NO_ISCSI_FLAG; + + if (cfg & MACP_FUNC_CFG_FLAGS_FCOE_OFFLOAD) { + val2 = MF_CFG_RD(bp, func_ext_config[func]. + fcoe_mac_addr_upper); + val = MF_CFG_RD(bp, func_ext_config[func]. + fcoe_mac_addr_lower); + bnx2x_set_mac_buf(fip_mac, val, val2); + BNX2X_DEV_INFO("Read FCoE L2 MAC to " + BNX2X_MAC_FMT"\n", + BNX2X_MAC_PRN_LIST(fip_mac)); + + } else + bp->flags |= NO_FCOE_FLAG; + } +#endif + } else { + /* in SF read MACs from port configuration */ + val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper); + val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower); + bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2); + +#ifdef BCM_CNIC + val2 = SHMEM_RD(bp, dev_info.port_hw_config[port]. + iscsi_mac_upper); + val = SHMEM_RD(bp, dev_info.port_hw_config[port]. + iscsi_mac_lower); + bnx2x_set_mac_buf(iscsi_mac, val, val2); + + val2 = SHMEM_RD(bp, dev_info.port_hw_config[port]. + fcoe_fip_mac_upper); + val = SHMEM_RD(bp, dev_info.port_hw_config[port]. + fcoe_fip_mac_lower); + bnx2x_set_mac_buf(fip_mac, val, val2); +#endif + } + + memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN); + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN); + +#ifdef BCM_CNIC + /* Set the FCoE MAC in MF_SD mode */ + if (!CHIP_IS_E1x(bp) && IS_MF_SD(bp)) + memcpy(fip_mac, bp->dev->dev_addr, ETH_ALEN); + + /* Disable iSCSI if MAC configuration is + * invalid. + */ + if (!is_valid_ether_addr(iscsi_mac)) { + bp->flags |= NO_ISCSI_FLAG; + memset(iscsi_mac, 0, ETH_ALEN); + } + + /* Disable FCoE if MAC configuration is + * invalid. + */ + if (!is_valid_ether_addr(fip_mac)) { + bp->flags |= NO_FCOE_FLAG; + memset(bp->fip_mac, 0, ETH_ALEN); + } +#endif + + if (!is_valid_ether_addr(bp->dev->dev_addr)) + dev_err(&bp->pdev->dev, + "bad Ethernet MAC address configuration: " + BNX2X_MAC_FMT", change it manually before bringing up " + "the appropriate network interface\n", + BNX2X_MAC_PRN_LIST(bp->dev->dev_addr)); +} + +static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp) +{ + int /*abs*/func = BP_ABS_FUNC(bp); + int vn; + u32 val = 0; + int rc = 0; + + bnx2x_get_common_hwinfo(bp); + + /* + * initialize IGU parameters + */ + if (CHIP_IS_E1x(bp)) { + bp->common.int_block = INT_BLOCK_HC; + + bp->igu_dsb_id = DEF_SB_IGU_ID; + bp->igu_base_sb = 0; + } else { + bp->common.int_block = INT_BLOCK_IGU; + val = REG_RD(bp, IGU_REG_BLOCK_CONFIGURATION); + + if (val & IGU_BLOCK_CONFIGURATION_REG_BACKWARD_COMP_EN) { + int tout = 5000; + + BNX2X_DEV_INFO("FORCING Normal Mode\n"); + + val &= ~(IGU_BLOCK_CONFIGURATION_REG_BACKWARD_COMP_EN); + REG_WR(bp, IGU_REG_BLOCK_CONFIGURATION, val); + REG_WR(bp, IGU_REG_RESET_MEMORIES, 0x7f); + + while (tout && REG_RD(bp, IGU_REG_RESET_MEMORIES)) { + tout--; + usleep_range(1000, 1000); + } + + if (REG_RD(bp, IGU_REG_RESET_MEMORIES)) { + dev_err(&bp->pdev->dev, + "FORCING Normal Mode failed!!!\n"); + return -EPERM; + } + } + + if (val & IGU_BLOCK_CONFIGURATION_REG_BACKWARD_COMP_EN) { + BNX2X_DEV_INFO("IGU Backward Compatible Mode\n"); + bp->common.int_block |= INT_BLOCK_MODE_BW_COMP; + } else + BNX2X_DEV_INFO("IGU Normal Mode\n"); + + bnx2x_get_igu_cam_info(bp); + + } + + /* + * set base FW non-default (fast path) status block id, this value is + * used to initialize the fw_sb_id saved on the fp/queue structure to + * determine the id used by the FW. + */ + if (CHIP_IS_E1x(bp)) + bp->base_fw_ndsb = BP_PORT(bp) * FP_SB_MAX_E1x + BP_L_ID(bp); + else /* + * 57712 - we currently use one FW SB per IGU SB (Rx and Tx of + * the same queue are indicated on the same IGU SB). So we prefer + * FW and IGU SBs to be the same value. + */ + bp->base_fw_ndsb = bp->igu_base_sb; + + BNX2X_DEV_INFO("igu_dsb_id %d igu_base_sb %d igu_sb_cnt %d\n" + "base_fw_ndsb %d\n", bp->igu_dsb_id, bp->igu_base_sb, + bp->igu_sb_cnt, bp->base_fw_ndsb); + + /* + * Initialize MF configuration + */ + + bp->mf_ov = 0; + bp->mf_mode = 0; + vn = BP_E1HVN(bp); + + if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) { + BNX2X_DEV_INFO("shmem2base 0x%x, size %d, mfcfg offset %d\n", + bp->common.shmem2_base, SHMEM2_RD(bp, size), + (u32)offsetof(struct shmem2_region, mf_cfg_addr)); + + if (SHMEM2_HAS(bp, mf_cfg_addr)) + bp->common.mf_cfg_base = SHMEM2_RD(bp, mf_cfg_addr); + else + bp->common.mf_cfg_base = bp->common.shmem_base + + offsetof(struct shmem_region, func_mb) + + E1H_FUNC_MAX * sizeof(struct drv_func_mb); + /* + * get mf configuration: + * 1. existence of MF configuration + * 2. MAC address must be legal (check only upper bytes) + * for Switch-Independent mode; + * OVLAN must be legal for Switch-Dependent mode + * 3. SF_MODE configures specific MF mode + */ + if (bp->common.mf_cfg_base != SHMEM_MF_CFG_ADDR_NONE) { + /* get mf configuration */ + val = SHMEM_RD(bp, + dev_info.shared_feature_config.config); + val &= SHARED_FEAT_CFG_FORCE_SF_MODE_MASK; + + switch (val) { + case SHARED_FEAT_CFG_FORCE_SF_MODE_SWITCH_INDEPT: + val = MF_CFG_RD(bp, func_mf_config[func]. + mac_upper); + /* check for legal mac (upper bytes)*/ + if (val != 0xffff) { + bp->mf_mode = MULTI_FUNCTION_SI; + bp->mf_config[vn] = MF_CFG_RD(bp, + func_mf_config[func].config); + } else + BNX2X_DEV_INFO("illegal MAC address " + "for SI\n"); + break; + case SHARED_FEAT_CFG_FORCE_SF_MODE_MF_ALLOWED: + /* get OV configuration */ + val = MF_CFG_RD(bp, + func_mf_config[FUNC_0].e1hov_tag); + val &= FUNC_MF_CFG_E1HOV_TAG_MASK; + + if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { + bp->mf_mode = MULTI_FUNCTION_SD; + bp->mf_config[vn] = MF_CFG_RD(bp, + func_mf_config[func].config); + } else + BNX2X_DEV_INFO("illegal OV for SD\n"); + break; + default: + /* Unknown configuration: reset mf_config */ + bp->mf_config[vn] = 0; + BNX2X_DEV_INFO("unkown MF mode 0x%x\n", val); + } + } + + BNX2X_DEV_INFO("%s function mode\n", + IS_MF(bp) ? "multi" : "single"); + + switch (bp->mf_mode) { + case MULTI_FUNCTION_SD: + val = MF_CFG_RD(bp, func_mf_config[func].e1hov_tag) & + FUNC_MF_CFG_E1HOV_TAG_MASK; + if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) { + bp->mf_ov = val; + bp->path_has_ovlan = true; + + BNX2X_DEV_INFO("MF OV for func %d is %d " + "(0x%04x)\n", func, bp->mf_ov, + bp->mf_ov); + } else { + dev_err(&bp->pdev->dev, + "No valid MF OV for func %d, " + "aborting\n", func); + return -EPERM; + } + break; + case MULTI_FUNCTION_SI: + BNX2X_DEV_INFO("func %d is in MF " + "switch-independent mode\n", func); + break; + default: + if (vn) { + dev_err(&bp->pdev->dev, + "VN %d is in a single function mode, " + "aborting\n", vn); + return -EPERM; + } + break; + } + + /* check if other port on the path needs ovlan: + * Since MF configuration is shared between ports + * Possible mixed modes are only + * {SF, SI} {SF, SD} {SD, SF} {SI, SF} + */ + if (CHIP_MODE_IS_4_PORT(bp) && + !bp->path_has_ovlan && + !IS_MF(bp) && + bp->common.mf_cfg_base != SHMEM_MF_CFG_ADDR_NONE) { + u8 other_port = !BP_PORT(bp); + u8 other_func = BP_PATH(bp) + 2*other_port; + val = MF_CFG_RD(bp, + func_mf_config[other_func].e1hov_tag); + if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) + bp->path_has_ovlan = true; + } + } + + /* adjust igu_sb_cnt to MF for E1x */ + if (CHIP_IS_E1x(bp) && IS_MF(bp)) + bp->igu_sb_cnt /= E1HVN_MAX; + + /* port info */ + bnx2x_get_port_hwinfo(bp); + + if (!BP_NOMCP(bp)) { + bp->fw_seq = + (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); + } + + /* Get MAC addresses */ + bnx2x_get_mac_hwinfo(bp); + +#ifdef BCM_CNIC + bnx2x_get_cnic_info(bp); +#endif + + /* Get current FW pulse sequence */ + if (!BP_NOMCP(bp)) { + int mb_idx = BP_FW_MB_IDX(bp); + + bp->fw_drv_pulse_wr_seq = + (SHMEM_RD(bp, func_mb[mb_idx].drv_pulse_mb) & + DRV_PULSE_SEQ_MASK); + BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq); + } + + return rc; +} + +static void __devinit bnx2x_read_fwinfo(struct bnx2x *bp) +{ + int cnt, i, block_end, rodi; + char vpd_data[BNX2X_VPD_LEN+1]; + char str_id_reg[VENDOR_ID_LEN+1]; + char str_id_cap[VENDOR_ID_LEN+1]; + u8 len; + + cnt = pci_read_vpd(bp->pdev, 0, BNX2X_VPD_LEN, vpd_data); + memset(bp->fw_ver, 0, sizeof(bp->fw_ver)); + + if (cnt < BNX2X_VPD_LEN) + goto out_not_found; + + i = pci_vpd_find_tag(vpd_data, 0, BNX2X_VPD_LEN, + PCI_VPD_LRDT_RO_DATA); + if (i < 0) + goto out_not_found; + + + block_end = i + PCI_VPD_LRDT_TAG_SIZE + + pci_vpd_lrdt_size(&vpd_data[i]); + + i += PCI_VPD_LRDT_TAG_SIZE; + + if (block_end > BNX2X_VPD_LEN) + goto out_not_found; + + rodi = pci_vpd_find_info_keyword(vpd_data, i, block_end, + PCI_VPD_RO_KEYWORD_MFR_ID); + if (rodi < 0) + goto out_not_found; + + len = pci_vpd_info_field_size(&vpd_data[rodi]); + + if (len != VENDOR_ID_LEN) + goto out_not_found; + + rodi += PCI_VPD_INFO_FLD_HDR_SIZE; + + /* vendor specific info */ + snprintf(str_id_reg, VENDOR_ID_LEN + 1, "%04x", PCI_VENDOR_ID_DELL); + snprintf(str_id_cap, VENDOR_ID_LEN + 1, "%04X", PCI_VENDOR_ID_DELL); + if (!strncmp(str_id_reg, &vpd_data[rodi], VENDOR_ID_LEN) || + !strncmp(str_id_cap, &vpd_data[rodi], VENDOR_ID_LEN)) { + + rodi = pci_vpd_find_info_keyword(vpd_data, i, block_end, + PCI_VPD_RO_KEYWORD_VENDOR0); + if (rodi >= 0) { + len = pci_vpd_info_field_size(&vpd_data[rodi]); + + rodi += PCI_VPD_INFO_FLD_HDR_SIZE; + + if (len < 32 && (len + rodi) <= BNX2X_VPD_LEN) { + memcpy(bp->fw_ver, &vpd_data[rodi], len); + bp->fw_ver[len] = ' '; + } + } + return; + } +out_not_found: + return; +} + +static void __devinit bnx2x_set_modes_bitmap(struct bnx2x *bp) +{ + u32 flags = 0; + + if (CHIP_REV_IS_FPGA(bp)) + SET_FLAGS(flags, MODE_FPGA); + else if (CHIP_REV_IS_EMUL(bp)) + SET_FLAGS(flags, MODE_EMUL); + else + SET_FLAGS(flags, MODE_ASIC); + + if (CHIP_MODE_IS_4_PORT(bp)) + SET_FLAGS(flags, MODE_PORT4); + else + SET_FLAGS(flags, MODE_PORT2); + + if (CHIP_IS_E2(bp)) + SET_FLAGS(flags, MODE_E2); + else if (CHIP_IS_E3(bp)) { + SET_FLAGS(flags, MODE_E3); + if (CHIP_REV(bp) == CHIP_REV_Ax) + SET_FLAGS(flags, MODE_E3_A0); + else /*if (CHIP_REV(bp) == CHIP_REV_Bx)*/ + SET_FLAGS(flags, MODE_E3_B0 | MODE_COS3); + } + + if (IS_MF(bp)) { + SET_FLAGS(flags, MODE_MF); + switch (bp->mf_mode) { + case MULTI_FUNCTION_SD: + SET_FLAGS(flags, MODE_MF_SD); + break; + case MULTI_FUNCTION_SI: + SET_FLAGS(flags, MODE_MF_SI); + break; + } + } else + SET_FLAGS(flags, MODE_SF); + +#if defined(__LITTLE_ENDIAN) + SET_FLAGS(flags, MODE_LITTLE_ENDIAN); +#else /*(__BIG_ENDIAN)*/ + SET_FLAGS(flags, MODE_BIG_ENDIAN); +#endif + INIT_MODE_FLAGS(bp) = flags; +} + +static int __devinit bnx2x_init_bp(struct bnx2x *bp) +{ + int func; + int timer_interval; + int rc; + + mutex_init(&bp->port.phy_mutex); + mutex_init(&bp->fw_mb_mutex); + spin_lock_init(&bp->stats_lock); +#ifdef BCM_CNIC + mutex_init(&bp->cnic_mutex); +#endif + + INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task); + INIT_DELAYED_WORK(&bp->sp_rtnl_task, bnx2x_sp_rtnl_task); + INIT_DELAYED_WORK(&bp->period_task, bnx2x_period_task); + rc = bnx2x_get_hwinfo(bp); + if (rc) + return rc; + + bnx2x_set_modes_bitmap(bp); + + rc = bnx2x_alloc_mem_bp(bp); + if (rc) + return rc; + + bnx2x_read_fwinfo(bp); + + func = BP_FUNC(bp); + + /* need to reset chip if undi was active */ + if (!BP_NOMCP(bp)) + bnx2x_undi_unload(bp); + + if (CHIP_REV_IS_FPGA(bp)) + dev_err(&bp->pdev->dev, "FPGA detected\n"); + + if (BP_NOMCP(bp) && (func == 0)) + dev_err(&bp->pdev->dev, "MCP disabled, " + "must load devices in order!\n"); + + bp->multi_mode = multi_mode; + + /* Set TPA flags */ + if (disable_tpa) { + bp->flags &= ~TPA_ENABLE_FLAG; + bp->dev->features &= ~NETIF_F_LRO; + } else { + bp->flags |= TPA_ENABLE_FLAG; + bp->dev->features |= NETIF_F_LRO; + } + bp->disable_tpa = disable_tpa; + + if (CHIP_IS_E1(bp)) + bp->dropless_fc = 0; + else + bp->dropless_fc = dropless_fc; + + bp->mrrs = mrrs; + + bp->tx_ring_size = MAX_TX_AVAIL; + + /* make sure that the numbers are in the right granularity */ + bp->tx_ticks = (50 / BNX2X_BTR) * BNX2X_BTR; + bp->rx_ticks = (25 / BNX2X_BTR) * BNX2X_BTR; + + timer_interval = (CHIP_REV_IS_SLOW(bp) ? 5*HZ : HZ); + bp->current_interval = (poll ? poll : timer_interval); + + init_timer(&bp->timer); + bp->timer.expires = jiffies + bp->current_interval; + bp->timer.data = (unsigned long) bp; + bp->timer.function = bnx2x_timer; + + bnx2x_dcbx_set_state(bp, true, BNX2X_DCBX_ENABLED_ON_NEG_ON); + bnx2x_dcbx_init_params(bp); + +#ifdef BCM_CNIC + if (CHIP_IS_E1x(bp)) + bp->cnic_base_cl_id = FP_SB_MAX_E1x; + else + bp->cnic_base_cl_id = FP_SB_MAX_E2; +#endif + + /* multiple tx priority */ + if (CHIP_IS_E1x(bp)) + bp->max_cos = BNX2X_MULTI_TX_COS_E1X; + if (CHIP_IS_E2(bp) || CHIP_IS_E3A0(bp)) + bp->max_cos = BNX2X_MULTI_TX_COS_E2_E3A0; + if (CHIP_IS_E3B0(bp)) + bp->max_cos = BNX2X_MULTI_TX_COS_E3B0; + + return rc; +} + + +/**************************************************************************** +* General service functions +****************************************************************************/ + +/* + * net_device service functions + */ + +/* called with rtnl_lock */ +static int bnx2x_open(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + bool global = false; + int other_engine = BP_PATH(bp) ? 0 : 1; + u32 other_load_counter, load_counter; + + netif_carrier_off(dev); + + bnx2x_set_power_state(bp, PCI_D0); + + other_load_counter = bnx2x_get_load_cnt(bp, other_engine); + load_counter = bnx2x_get_load_cnt(bp, BP_PATH(bp)); + + /* + * If parity had happen during the unload, then attentions + * and/or RECOVERY_IN_PROGRES may still be set. In this case we + * want the first function loaded on the current engine to + * complete the recovery. + */ + if (!bnx2x_reset_is_done(bp, BP_PATH(bp)) || + bnx2x_chk_parity_attn(bp, &global, true)) + do { + /* + * If there are attentions and they are in a global + * blocks, set the GLOBAL_RESET bit regardless whether + * it will be this function that will complete the + * recovery or not. + */ + if (global) + bnx2x_set_reset_global(bp); + + /* + * Only the first function on the current engine should + * try to recover in open. In case of attentions in + * global blocks only the first in the chip should try + * to recover. + */ + if ((!load_counter && + (!global || !other_load_counter)) && + bnx2x_trylock_leader_lock(bp) && + !bnx2x_leader_reset(bp)) { + netdev_info(bp->dev, "Recovered in open\n"); + break; + } + + /* recovery has failed... */ + bnx2x_set_power_state(bp, PCI_D3hot); + bp->recovery_state = BNX2X_RECOVERY_FAILED; + + netdev_err(bp->dev, "Recovery flow hasn't been properly" + " completed yet. Try again later. If u still see this" + " message after a few retries then power cycle is" + " required.\n"); + + return -EAGAIN; + } while (0); + + bp->recovery_state = BNX2X_RECOVERY_DONE; + return bnx2x_nic_load(bp, LOAD_OPEN); +} + +/* called with rtnl_lock */ +static int bnx2x_close(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + /* Unload the driver, release IRQs */ + bnx2x_nic_unload(bp, UNLOAD_CLOSE); + + /* Power off */ + bnx2x_set_power_state(bp, PCI_D3hot); + + return 0; +} + +static inline int bnx2x_init_mcast_macs_list(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p) +{ + int mc_count = netdev_mc_count(bp->dev); + struct bnx2x_mcast_list_elem *mc_mac = + kzalloc(sizeof(*mc_mac) * mc_count, GFP_ATOMIC); + struct netdev_hw_addr *ha; + + if (!mc_mac) + return -ENOMEM; + + INIT_LIST_HEAD(&p->mcast_list); + + netdev_for_each_mc_addr(ha, bp->dev) { + mc_mac->mac = bnx2x_mc_addr(ha); + list_add_tail(&mc_mac->link, &p->mcast_list); + mc_mac++; + } + + p->mcast_list_len = mc_count; + + return 0; +} + +static inline void bnx2x_free_mcast_macs_list( + struct bnx2x_mcast_ramrod_params *p) +{ + struct bnx2x_mcast_list_elem *mc_mac = + list_first_entry(&p->mcast_list, struct bnx2x_mcast_list_elem, + link); + + WARN_ON(!mc_mac); + kfree(mc_mac); +} + +/** + * bnx2x_set_uc_list - configure a new unicast MACs list. + * + * @bp: driver handle + * + * We will use zero (0) as a MAC type for these MACs. + */ +static inline int bnx2x_set_uc_list(struct bnx2x *bp) +{ + int rc; + struct net_device *dev = bp->dev; + struct netdev_hw_addr *ha; + struct bnx2x_vlan_mac_obj *mac_obj = &bp->fp->mac_obj; + unsigned long ramrod_flags = 0; + + /* First schedule a cleanup up of old configuration */ + rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_UC_LIST_MAC, false); + if (rc < 0) { + BNX2X_ERR("Failed to schedule DELETE operations: %d\n", rc); + return rc; + } + + netdev_for_each_uc_addr(ha, dev) { + rc = bnx2x_set_mac_one(bp, bnx2x_uc_addr(ha), mac_obj, true, + BNX2X_UC_LIST_MAC, &ramrod_flags); + if (rc < 0) { + BNX2X_ERR("Failed to schedule ADD operations: %d\n", + rc); + return rc; + } + } + + /* Execute the pending commands */ + __set_bit(RAMROD_CONT, &ramrod_flags); + return bnx2x_set_mac_one(bp, NULL, mac_obj, false /* don't care */, + BNX2X_UC_LIST_MAC, &ramrod_flags); +} + +static inline int bnx2x_set_mc_list(struct bnx2x *bp) +{ + struct net_device *dev = bp->dev; + struct bnx2x_mcast_ramrod_params rparam = {0}; + int rc = 0; + + rparam.mcast_obj = &bp->mcast_obj; + + /* first, clear all configured multicast MACs */ + rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL); + if (rc < 0) { + BNX2X_ERR("Failed to clear multicast " + "configuration: %d\n", rc); + return rc; + } + + /* then, configure a new MACs list */ + if (netdev_mc_count(dev)) { + rc = bnx2x_init_mcast_macs_list(bp, &rparam); + if (rc) { + BNX2X_ERR("Failed to create multicast MACs " + "list: %d\n", rc); + return rc; + } + + /* Now add the new MACs */ + rc = bnx2x_config_mcast(bp, &rparam, + BNX2X_MCAST_CMD_ADD); + if (rc < 0) + BNX2X_ERR("Failed to set a new multicast " + "configuration: %d\n", rc); + + bnx2x_free_mcast_macs_list(&rparam); + } + + return rc; +} + + +/* If bp->state is OPEN, should be called with netif_addr_lock_bh() */ +void bnx2x_set_rx_mode(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + u32 rx_mode = BNX2X_RX_MODE_NORMAL; + + if (bp->state != BNX2X_STATE_OPEN) { + DP(NETIF_MSG_IFUP, "state is %x, returning\n", bp->state); + return; + } + + DP(NETIF_MSG_IFUP, "dev->flags = %x\n", bp->dev->flags); + + if (dev->flags & IFF_PROMISC) + rx_mode = BNX2X_RX_MODE_PROMISC; + else if ((dev->flags & IFF_ALLMULTI) || + ((netdev_mc_count(dev) > BNX2X_MAX_MULTICAST) && + CHIP_IS_E1(bp))) + rx_mode = BNX2X_RX_MODE_ALLMULTI; + else { + /* some multicasts */ + if (bnx2x_set_mc_list(bp) < 0) + rx_mode = BNX2X_RX_MODE_ALLMULTI; + + if (bnx2x_set_uc_list(bp) < 0) + rx_mode = BNX2X_RX_MODE_PROMISC; + } + + bp->rx_mode = rx_mode; + + /* Schedule the rx_mode command */ + if (test_bit(BNX2X_FILTER_RX_MODE_PENDING, &bp->sp_state)) { + set_bit(BNX2X_FILTER_RX_MODE_SCHED, &bp->sp_state); + return; + } + + bnx2x_set_storm_rx_mode(bp); +} + +/* called with rtnl_lock */ +static int bnx2x_mdio_read(struct net_device *netdev, int prtad, + int devad, u16 addr) +{ + struct bnx2x *bp = netdev_priv(netdev); + u16 value; + int rc; + + DP(NETIF_MSG_LINK, "mdio_read: prtad 0x%x, devad 0x%x, addr 0x%x\n", + prtad, devad, addr); + + /* The HW expects different devad if CL22 is used */ + devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad; + + bnx2x_acquire_phy_lock(bp); + rc = bnx2x_phy_read(&bp->link_params, prtad, devad, addr, &value); + bnx2x_release_phy_lock(bp); + DP(NETIF_MSG_LINK, "mdio_read_val 0x%x rc = 0x%x\n", value, rc); + + if (!rc) + rc = value; + return rc; +} + +/* called with rtnl_lock */ +static int bnx2x_mdio_write(struct net_device *netdev, int prtad, int devad, + u16 addr, u16 value) +{ + struct bnx2x *bp = netdev_priv(netdev); + int rc; + + DP(NETIF_MSG_LINK, "mdio_write: prtad 0x%x, devad 0x%x, addr 0x%x," + " value 0x%x\n", prtad, devad, addr, value); + + /* The HW expects different devad if CL22 is used */ + devad = (devad == MDIO_DEVAD_NONE) ? DEFAULT_PHY_DEV_ADDR : devad; + + bnx2x_acquire_phy_lock(bp); + rc = bnx2x_phy_write(&bp->link_params, prtad, devad, addr, value); + bnx2x_release_phy_lock(bp); + return rc; +} + +/* called with rtnl_lock */ +static int bnx2x_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct bnx2x *bp = netdev_priv(dev); + struct mii_ioctl_data *mdio = if_mii(ifr); + + DP(NETIF_MSG_LINK, "ioctl: phy id 0x%x, reg 0x%x, val_in 0x%x\n", + mdio->phy_id, mdio->reg_num, mdio->val_in); + + if (!netif_running(dev)) + return -EAGAIN; + + return mdio_mii_ioctl(&bp->mdio, mdio, cmd); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void poll_bnx2x(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + + disable_irq(bp->pdev->irq); + bnx2x_interrupt(bp->pdev->irq, dev); + enable_irq(bp->pdev->irq); +} +#endif + +static const struct net_device_ops bnx2x_netdev_ops = { + .ndo_open = bnx2x_open, + .ndo_stop = bnx2x_close, + .ndo_start_xmit = bnx2x_start_xmit, + .ndo_select_queue = bnx2x_select_queue, + .ndo_set_rx_mode = bnx2x_set_rx_mode, + .ndo_set_mac_address = bnx2x_change_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = bnx2x_ioctl, + .ndo_change_mtu = bnx2x_change_mtu, + .ndo_fix_features = bnx2x_fix_features, + .ndo_set_features = bnx2x_set_features, + .ndo_tx_timeout = bnx2x_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = poll_bnx2x, +#endif + .ndo_setup_tc = bnx2x_setup_tc, + +#if defined(NETDEV_FCOE_WWNN) && defined(BCM_CNIC) + .ndo_fcoe_get_wwn = bnx2x_fcoe_get_wwn, +#endif +}; + +static inline int bnx2x_set_coherency_mask(struct bnx2x *bp) +{ + struct device *dev = &bp->pdev->dev; + + if (dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) { + bp->flags |= USING_DAC_FLAG; + if (dma_set_coherent_mask(dev, DMA_BIT_MASK(64)) != 0) { + dev_err(dev, "dma_set_coherent_mask failed, " + "aborting\n"); + return -EIO; + } + } else if (dma_set_mask(dev, DMA_BIT_MASK(32)) != 0) { + dev_err(dev, "System does not support DMA, aborting\n"); + return -EIO; + } + + return 0; +} + +static int __devinit bnx2x_init_dev(struct pci_dev *pdev, + struct net_device *dev, + unsigned long board_type) +{ + struct bnx2x *bp; + int rc; + + SET_NETDEV_DEV(dev, &pdev->dev); + bp = netdev_priv(dev); + + bp->dev = dev; + bp->pdev = pdev; + bp->flags = 0; + bp->pf_num = PCI_FUNC(pdev->devfn); + + rc = pci_enable_device(pdev); + if (rc) { + dev_err(&bp->pdev->dev, + "Cannot enable PCI device, aborting\n"); + goto err_out; + } + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { + dev_err(&bp->pdev->dev, + "Cannot find PCI device base address, aborting\n"); + rc = -ENODEV; + goto err_out_disable; + } + + if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { + dev_err(&bp->pdev->dev, "Cannot find second PCI device" + " base address, aborting\n"); + rc = -ENODEV; + goto err_out_disable; + } + + if (atomic_read(&pdev->enable_cnt) == 1) { + rc = pci_request_regions(pdev, DRV_MODULE_NAME); + if (rc) { + dev_err(&bp->pdev->dev, + "Cannot obtain PCI resources, aborting\n"); + goto err_out_disable; + } + + pci_set_master(pdev); + pci_save_state(pdev); + } + + bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM); + if (bp->pm_cap == 0) { + dev_err(&bp->pdev->dev, + "Cannot find power management capability, aborting\n"); + rc = -EIO; + goto err_out_release; + } + + if (!pci_is_pcie(pdev)) { + dev_err(&bp->pdev->dev, "Not PCI Express, aborting\n"); + rc = -EIO; + goto err_out_release; + } + + rc = bnx2x_set_coherency_mask(bp); + if (rc) + goto err_out_release; + + dev->mem_start = pci_resource_start(pdev, 0); + dev->base_addr = dev->mem_start; + dev->mem_end = pci_resource_end(pdev, 0); + + dev->irq = pdev->irq; + + bp->regview = pci_ioremap_bar(pdev, 0); + if (!bp->regview) { + dev_err(&bp->pdev->dev, + "Cannot map register space, aborting\n"); + rc = -ENOMEM; + goto err_out_release; + } + + bnx2x_set_power_state(bp, PCI_D0); + + /* clean indirect addresses */ + pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, + PCICFG_VENDOR_ID_OFFSET); + REG_WR(bp, PXP2_REG_PGL_ADDR_88_F0 + BP_PORT(bp)*16, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_8C_F0 + BP_PORT(bp)*16, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0 + BP_PORT(bp)*16, 0); + REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0 + BP_PORT(bp)*16, 0); + + /* + * Enable internal target-read (in case we are probed after PF FLR). + * Must be done prior to any BAR read access. Only for 57712 and up + */ + if (board_type != BCM57710 && + board_type != BCM57711 && + board_type != BCM57711E) + REG_WR(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ, 1); + + /* Reset the load counter */ + bnx2x_clear_load_cnt(bp); + + dev->watchdog_timeo = TX_TIMEOUT; + + dev->netdev_ops = &bnx2x_netdev_ops; + bnx2x_set_ethtool_ops(dev); + + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | + NETIF_F_RXCSUM | NETIF_F_LRO | NETIF_F_HW_VLAN_TX; + + dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | + NETIF_F_TSO | NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_HIGHDMA; + + dev->features |= dev->hw_features | NETIF_F_HW_VLAN_RX; + if (bp->flags & USING_DAC_FLAG) + dev->features |= NETIF_F_HIGHDMA; + + /* Add Loopback capability to the device */ + dev->hw_features |= NETIF_F_LOOPBACK; + +#ifdef BCM_DCBNL + dev->dcbnl_ops = &bnx2x_dcbnl_ops; +#endif + + /* get_port_hwinfo() will set prtad and mmds properly */ + bp->mdio.prtad = MDIO_PRTAD_NONE; + bp->mdio.mmds = 0; + bp->mdio.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22; + bp->mdio.dev = dev; + bp->mdio.mdio_read = bnx2x_mdio_read; + bp->mdio.mdio_write = bnx2x_mdio_write; + + return 0; + +err_out_release: + if (atomic_read(&pdev->enable_cnt) == 1) + pci_release_regions(pdev); + +err_out_disable: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + +err_out: + return rc; +} + +static void __devinit bnx2x_get_pcie_width_speed(struct bnx2x *bp, + int *width, int *speed) +{ + u32 val = REG_RD(bp, PCICFG_OFFSET + PCICFG_LINK_CONTROL); + + *width = (val & PCICFG_LINK_WIDTH) >> PCICFG_LINK_WIDTH_SHIFT; + + /* return value of 1=2.5GHz 2=5GHz */ + *speed = (val & PCICFG_LINK_SPEED) >> PCICFG_LINK_SPEED_SHIFT; +} + +static int bnx2x_check_firmware(struct bnx2x *bp) +{ + const struct firmware *firmware = bp->firmware; + struct bnx2x_fw_file_hdr *fw_hdr; + struct bnx2x_fw_file_section *sections; + u32 offset, len, num_ops; + u16 *ops_offsets; + int i; + const u8 *fw_ver; + + if (firmware->size < sizeof(struct bnx2x_fw_file_hdr)) + return -EINVAL; + + fw_hdr = (struct bnx2x_fw_file_hdr *)firmware->data; + sections = (struct bnx2x_fw_file_section *)fw_hdr; + + /* Make sure none of the offsets and sizes make us read beyond + * the end of the firmware data */ + for (i = 0; i < sizeof(*fw_hdr) / sizeof(*sections); i++) { + offset = be32_to_cpu(sections[i].offset); + len = be32_to_cpu(sections[i].len); + if (offset + len > firmware->size) { + dev_err(&bp->pdev->dev, + "Section %d length is out of bounds\n", i); + return -EINVAL; + } + } + + /* Likewise for the init_ops offsets */ + offset = be32_to_cpu(fw_hdr->init_ops_offsets.offset); + ops_offsets = (u16 *)(firmware->data + offset); + num_ops = be32_to_cpu(fw_hdr->init_ops.len) / sizeof(struct raw_op); + + for (i = 0; i < be32_to_cpu(fw_hdr->init_ops_offsets.len) / 2; i++) { + if (be16_to_cpu(ops_offsets[i]) > num_ops) { + dev_err(&bp->pdev->dev, + "Section offset %d is out of bounds\n", i); + return -EINVAL; + } + } + + /* Check FW version */ + offset = be32_to_cpu(fw_hdr->fw_version.offset); + fw_ver = firmware->data + offset; + if ((fw_ver[0] != BCM_5710_FW_MAJOR_VERSION) || + (fw_ver[1] != BCM_5710_FW_MINOR_VERSION) || + (fw_ver[2] != BCM_5710_FW_REVISION_VERSION) || + (fw_ver[3] != BCM_5710_FW_ENGINEERING_VERSION)) { + dev_err(&bp->pdev->dev, + "Bad FW version:%d.%d.%d.%d. Should be %d.%d.%d.%d\n", + fw_ver[0], fw_ver[1], fw_ver[2], + fw_ver[3], BCM_5710_FW_MAJOR_VERSION, + BCM_5710_FW_MINOR_VERSION, + BCM_5710_FW_REVISION_VERSION, + BCM_5710_FW_ENGINEERING_VERSION); + return -EINVAL; + } + + return 0; +} + +static inline void be32_to_cpu_n(const u8 *_source, u8 *_target, u32 n) +{ + const __be32 *source = (const __be32 *)_source; + u32 *target = (u32 *)_target; + u32 i; + + for (i = 0; i < n/4; i++) + target[i] = be32_to_cpu(source[i]); +} + +/* + Ops array is stored in the following format: + {op(8bit), offset(24bit, big endian), data(32bit, big endian)} + */ +static inline void bnx2x_prep_ops(const u8 *_source, u8 *_target, u32 n) +{ + const __be32 *source = (const __be32 *)_source; + struct raw_op *target = (struct raw_op *)_target; + u32 i, j, tmp; + + for (i = 0, j = 0; i < n/8; i++, j += 2) { + tmp = be32_to_cpu(source[j]); + target[i].op = (tmp >> 24) & 0xff; + target[i].offset = tmp & 0xffffff; + target[i].raw_data = be32_to_cpu(source[j + 1]); + } +} + +/** + * IRO array is stored in the following format: + * {base(24bit), m1(16bit), m2(16bit), m3(16bit), size(16bit) } + */ +static inline void bnx2x_prep_iro(const u8 *_source, u8 *_target, u32 n) +{ + const __be32 *source = (const __be32 *)_source; + struct iro *target = (struct iro *)_target; + u32 i, j, tmp; + + for (i = 0, j = 0; i < n/sizeof(struct iro); i++) { + target[i].base = be32_to_cpu(source[j]); + j++; + tmp = be32_to_cpu(source[j]); + target[i].m1 = (tmp >> 16) & 0xffff; + target[i].m2 = tmp & 0xffff; + j++; + tmp = be32_to_cpu(source[j]); + target[i].m3 = (tmp >> 16) & 0xffff; + target[i].size = tmp & 0xffff; + j++; + } +} + +static inline void be16_to_cpu_n(const u8 *_source, u8 *_target, u32 n) +{ + const __be16 *source = (const __be16 *)_source; + u16 *target = (u16 *)_target; + u32 i; + + for (i = 0; i < n/2; i++) + target[i] = be16_to_cpu(source[i]); +} + +#define BNX2X_ALLOC_AND_SET(arr, lbl, func) \ +do { \ + u32 len = be32_to_cpu(fw_hdr->arr.len); \ + bp->arr = kmalloc(len, GFP_KERNEL); \ + if (!bp->arr) { \ + pr_err("Failed to allocate %d bytes for "#arr"\n", len); \ + goto lbl; \ + } \ + func(bp->firmware->data + be32_to_cpu(fw_hdr->arr.offset), \ + (u8 *)bp->arr, len); \ +} while (0) + +int bnx2x_init_firmware(struct bnx2x *bp) +{ + const char *fw_file_name; + struct bnx2x_fw_file_hdr *fw_hdr; + int rc; + + if (CHIP_IS_E1(bp)) + fw_file_name = FW_FILE_NAME_E1; + else if (CHIP_IS_E1H(bp)) + fw_file_name = FW_FILE_NAME_E1H; + else if (!CHIP_IS_E1x(bp)) + fw_file_name = FW_FILE_NAME_E2; + else { + BNX2X_ERR("Unsupported chip revision\n"); + return -EINVAL; + } + + BNX2X_DEV_INFO("Loading %s\n", fw_file_name); + + rc = request_firmware(&bp->firmware, fw_file_name, &bp->pdev->dev); + if (rc) { + BNX2X_ERR("Can't load firmware file %s\n", fw_file_name); + goto request_firmware_exit; + } + + rc = bnx2x_check_firmware(bp); + if (rc) { + BNX2X_ERR("Corrupt firmware file %s\n", fw_file_name); + goto request_firmware_exit; + } + + fw_hdr = (struct bnx2x_fw_file_hdr *)bp->firmware->data; + + /* Initialize the pointers to the init arrays */ + /* Blob */ + BNX2X_ALLOC_AND_SET(init_data, request_firmware_exit, be32_to_cpu_n); + + /* Opcodes */ + BNX2X_ALLOC_AND_SET(init_ops, init_ops_alloc_err, bnx2x_prep_ops); + + /* Offsets */ + BNX2X_ALLOC_AND_SET(init_ops_offsets, init_offsets_alloc_err, + be16_to_cpu_n); + + /* STORMs firmware */ + INIT_TSEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->tsem_int_table_data.offset); + INIT_TSEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->tsem_pram_data.offset); + INIT_USEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->usem_int_table_data.offset); + INIT_USEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->usem_pram_data.offset); + INIT_XSEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->xsem_int_table_data.offset); + INIT_XSEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->xsem_pram_data.offset); + INIT_CSEM_INT_TABLE_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->csem_int_table_data.offset); + INIT_CSEM_PRAM_DATA(bp) = bp->firmware->data + + be32_to_cpu(fw_hdr->csem_pram_data.offset); + /* IRO */ + BNX2X_ALLOC_AND_SET(iro_arr, iro_alloc_err, bnx2x_prep_iro); + + return 0; + +iro_alloc_err: + kfree(bp->init_ops_offsets); +init_offsets_alloc_err: + kfree(bp->init_ops); +init_ops_alloc_err: + kfree(bp->init_data); +request_firmware_exit: + release_firmware(bp->firmware); + + return rc; +} + +static void bnx2x_release_firmware(struct bnx2x *bp) +{ + kfree(bp->init_ops_offsets); + kfree(bp->init_ops); + kfree(bp->init_data); + release_firmware(bp->firmware); +} + + +static struct bnx2x_func_sp_drv_ops bnx2x_func_sp_drv = { + .init_hw_cmn_chip = bnx2x_init_hw_common_chip, + .init_hw_cmn = bnx2x_init_hw_common, + .init_hw_port = bnx2x_init_hw_port, + .init_hw_func = bnx2x_init_hw_func, + + .reset_hw_cmn = bnx2x_reset_common, + .reset_hw_port = bnx2x_reset_port, + .reset_hw_func = bnx2x_reset_func, + + .gunzip_init = bnx2x_gunzip_init, + .gunzip_end = bnx2x_gunzip_end, + + .init_fw = bnx2x_init_firmware, + .release_fw = bnx2x_release_firmware, +}; + +void bnx2x__init_func_obj(struct bnx2x *bp) +{ + /* Prepare DMAE related driver resources */ + bnx2x_setup_dmae(bp); + + bnx2x_init_func_obj(bp, &bp->func_obj, + bnx2x_sp(bp, func_rdata), + bnx2x_sp_mapping(bp, func_rdata), + &bnx2x_func_sp_drv); +} + +/* must be called after sriov-enable */ +static inline int bnx2x_set_qm_cid_count(struct bnx2x *bp) +{ + int cid_count = BNX2X_L2_CID_COUNT(bp); + +#ifdef BCM_CNIC + cid_count += CNIC_CID_MAX; +#endif + return roundup(cid_count, QM_CID_ROUND); +} + +/** + * bnx2x_get_num_none_def_sbs - return the number of none default SBs + * + * @dev: pci device + * + */ +static inline int bnx2x_get_num_non_def_sbs(struct pci_dev *pdev) +{ + int pos; + u16 control; + + pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX); + + /* + * If MSI-X is not supported - return number of SBs needed to support + * one fast path queue: one FP queue + SB for CNIC + */ + if (!pos) + return 1 + CNIC_PRESENT; + + /* + * The value in the PCI configuration space is the index of the last + * entry, namely one less than the actual size of the table, which is + * exactly what we want to return from this function: number of all SBs + * without the default SB. + */ + pci_read_config_word(pdev, pos + PCI_MSI_FLAGS, &control); + return control & PCI_MSIX_FLAGS_QSIZE; +} + +static int __devinit bnx2x_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev = NULL; + struct bnx2x *bp; + int pcie_width, pcie_speed; + int rc, max_non_def_sbs; + int rx_count, tx_count, rss_count; + /* + * An estimated maximum supported CoS number according to the chip + * version. + * We will try to roughly estimate the maximum number of CoSes this chip + * may support in order to minimize the memory allocated for Tx + * netdev_queue's. This number will be accurately calculated during the + * initialization of bp->max_cos based on the chip versions AND chip + * revision in the bnx2x_init_bp(). + */ + u8 max_cos_est = 0; + + switch (ent->driver_data) { + case BCM57710: + case BCM57711: + case BCM57711E: + max_cos_est = BNX2X_MULTI_TX_COS_E1X; + break; + + case BCM57712: + case BCM57712_MF: + max_cos_est = BNX2X_MULTI_TX_COS_E2_E3A0; + break; + + case BCM57800: + case BCM57800_MF: + case BCM57810: + case BCM57810_MF: + case BCM57840: + case BCM57840_MF: + max_cos_est = BNX2X_MULTI_TX_COS_E3B0; + break; + + default: + pr_err("Unknown board_type (%ld), aborting\n", + ent->driver_data); + return -ENODEV; + } + + max_non_def_sbs = bnx2x_get_num_non_def_sbs(pdev); + + /* !!! FIXME !!! + * Do not allow the maximum SB count to grow above 16 + * since Special CIDs starts from 16*BNX2X_MULTI_TX_COS=48. + * We will use the FP_SB_MAX_E1x macro for this matter. + */ + max_non_def_sbs = min_t(int, FP_SB_MAX_E1x, max_non_def_sbs); + + WARN_ON(!max_non_def_sbs); + + /* Maximum number of RSS queues: one IGU SB goes to CNIC */ + rss_count = max_non_def_sbs - CNIC_PRESENT; + + /* Maximum number of netdev Rx queues: RSS + FCoE L2 */ + rx_count = rss_count + FCOE_PRESENT; + + /* + * Maximum number of netdev Tx queues: + * Maximum TSS queues * Maximum supported number of CoS + FCoE L2 + */ + tx_count = MAX_TXQS_PER_COS * max_cos_est + FCOE_PRESENT; + + /* dev zeroed in init_etherdev */ + dev = alloc_etherdev_mqs(sizeof(*bp), tx_count, rx_count); + if (!dev) { + dev_err(&pdev->dev, "Cannot allocate net device\n"); + return -ENOMEM; + } + + bp = netdev_priv(dev); + + DP(NETIF_MSG_DRV, "Allocated netdev with %d tx and %d rx queues\n", + tx_count, rx_count); + + bp->igu_sb_cnt = max_non_def_sbs; + bp->msg_enable = debug; + pci_set_drvdata(pdev, dev); + + rc = bnx2x_init_dev(pdev, dev, ent->driver_data); + if (rc < 0) { + free_netdev(dev); + return rc; + } + + DP(NETIF_MSG_DRV, "max_non_def_sbs %d", max_non_def_sbs); + + rc = bnx2x_init_bp(bp); + if (rc) + goto init_one_exit; + + /* + * Map doorbels here as we need the real value of bp->max_cos which + * is initialized in bnx2x_init_bp(). + */ + bp->doorbells = ioremap_nocache(pci_resource_start(pdev, 2), + min_t(u64, BNX2X_DB_SIZE(bp), + pci_resource_len(pdev, 2))); + if (!bp->doorbells) { + dev_err(&bp->pdev->dev, + "Cannot map doorbell space, aborting\n"); + rc = -ENOMEM; + goto init_one_exit; + } + + /* calc qm_cid_count */ + bp->qm_cid_count = bnx2x_set_qm_cid_count(bp); + +#ifdef BCM_CNIC + /* disable FCOE L2 queue for E1x and E3*/ + if (CHIP_IS_E1x(bp) || CHIP_IS_E3(bp)) + bp->flags |= NO_FCOE_FLAG; + +#endif + + /* Configure interrupt mode: try to enable MSI-X/MSI if + * needed, set bp->num_queues appropriately. + */ + bnx2x_set_int_mode(bp); + + /* Add all NAPI objects */ + bnx2x_add_all_napi(bp); + + rc = register_netdev(dev); + if (rc) { + dev_err(&pdev->dev, "Cannot register net device\n"); + goto init_one_exit; + } + +#ifdef BCM_CNIC + if (!NO_FCOE(bp)) { + /* Add storage MAC address */ + rtnl_lock(); + dev_addr_add(bp->dev, bp->fip_mac, NETDEV_HW_ADDR_T_SAN); + rtnl_unlock(); + } +#endif + + bnx2x_get_pcie_width_speed(bp, &pcie_width, &pcie_speed); + + netdev_info(dev, "%s (%c%d) PCI-E x%d %s found at mem %lx," + " IRQ %d, ", board_info[ent->driver_data].name, + (CHIP_REV(bp) >> 12) + 'A', (CHIP_METAL(bp) >> 4), + pcie_width, + ((!CHIP_IS_E2(bp) && pcie_speed == 2) || + (CHIP_IS_E2(bp) && pcie_speed == 1)) ? + "5GHz (Gen2)" : "2.5GHz", + dev->base_addr, bp->pdev->irq); + pr_cont("node addr %pM\n", dev->dev_addr); + + return 0; + +init_one_exit: + if (bp->regview) + iounmap(bp->regview); + + if (bp->doorbells) + iounmap(bp->doorbells); + + free_netdev(dev); + + if (atomic_read(&pdev->enable_cnt) == 1) + pci_release_regions(pdev); + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + + return rc; +} + +static void __devexit bnx2x_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp; + + if (!dev) { + dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n"); + return; + } + bp = netdev_priv(dev); + +#ifdef BCM_CNIC + /* Delete storage MAC address */ + if (!NO_FCOE(bp)) { + rtnl_lock(); + dev_addr_del(bp->dev, bp->fip_mac, NETDEV_HW_ADDR_T_SAN); + rtnl_unlock(); + } +#endif + +#ifdef BCM_DCBNL + /* Delete app tlvs from dcbnl */ + bnx2x_dcbnl_update_applist(bp, true); +#endif + + unregister_netdev(dev); + + /* Delete all NAPI objects */ + bnx2x_del_all_napi(bp); + + /* Power on: we can't let PCI layer write to us while we are in D3 */ + bnx2x_set_power_state(bp, PCI_D0); + + /* Disable MSI/MSI-X */ + bnx2x_disable_msi(bp); + + /* Power off */ + bnx2x_set_power_state(bp, PCI_D3hot); + + /* Make sure RESET task is not scheduled before continuing */ + cancel_delayed_work_sync(&bp->sp_rtnl_task); + + if (bp->regview) + iounmap(bp->regview); + + if (bp->doorbells) + iounmap(bp->doorbells); + + bnx2x_free_mem_bp(bp); + + free_netdev(dev); + + if (atomic_read(&pdev->enable_cnt) == 1) + pci_release_regions(pdev); + + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static int bnx2x_eeh_nic_unload(struct bnx2x *bp) +{ + int i; + + bp->state = BNX2X_STATE_ERROR; + + bp->rx_mode = BNX2X_RX_MODE_NONE; + +#ifdef BCM_CNIC + bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD); +#endif + /* Stop Tx */ + bnx2x_tx_disable(bp); + + bnx2x_netif_stop(bp, 0); + + del_timer_sync(&bp->timer); + + bnx2x_stats_handle(bp, STATS_EVENT_STOP); + + /* Release IRQs */ + bnx2x_free_irq(bp); + + /* Free SKBs, SGEs, TPA pool and driver internals */ + bnx2x_free_skbs(bp); + + for_each_rx_queue(bp, i) + bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); + + bnx2x_free_mem(bp); + + bp->state = BNX2X_STATE_CLOSED; + + netif_carrier_off(bp->dev); + + return 0; +} + +static void bnx2x_eeh_recover(struct bnx2x *bp) +{ + u32 val; + + mutex_init(&bp->port.phy_mutex); + + bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR); + bp->link_params.shmem_base = bp->common.shmem_base; + BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base); + + if (!bp->common.shmem_base || + (bp->common.shmem_base < 0xA0000) || + (bp->common.shmem_base >= 0xC0000)) { + BNX2X_DEV_INFO("MCP not active\n"); + bp->flags |= NO_MCP_FLAG; + return; + } + + val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]); + if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) + != (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB)) + BNX2X_ERR("BAD MCP validity signature\n"); + + if (!BP_NOMCP(bp)) { + bp->fw_seq = + (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) & + DRV_MSG_SEQ_NUMBER_MASK); + BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); + } +} + +/** + * bnx2x_io_error_detected - called when PCI error is detected + * @pdev: Pointer to PCI device + * @state: The current pci connection state + * + * This function is called after a PCI bus error affecting + * this device has been detected. + */ +static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp = netdev_priv(dev); + + rtnl_lock(); + + netif_device_detach(dev); + + if (state == pci_channel_io_perm_failure) { + rtnl_unlock(); + return PCI_ERS_RESULT_DISCONNECT; + } + + if (netif_running(dev)) + bnx2x_eeh_nic_unload(bp); + + pci_disable_device(pdev); + + rtnl_unlock(); + + /* Request a slot reset */ + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * bnx2x_io_slot_reset - called after the PCI bus has been reset + * @pdev: Pointer to PCI device + * + * Restart the card from scratch, as if from a cold-boot. + */ +static pci_ers_result_t bnx2x_io_slot_reset(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp = netdev_priv(dev); + + rtnl_lock(); + + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, + "Cannot re-enable PCI device after reset\n"); + rtnl_unlock(); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_set_master(pdev); + pci_restore_state(pdev); + + if (netif_running(dev)) + bnx2x_set_power_state(bp, PCI_D0); + + rtnl_unlock(); + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * bnx2x_io_resume - called when traffic can start flowing again + * @pdev: Pointer to PCI device + * + * This callback is called when the error recovery driver tells us that + * its OK to resume normal operation. + */ +static void bnx2x_io_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct bnx2x *bp = netdev_priv(dev); + + if (bp->recovery_state != BNX2X_RECOVERY_DONE) { + netdev_err(bp->dev, "Handling parity error recovery. " + "Try again later\n"); + return; + } + + rtnl_lock(); + + bnx2x_eeh_recover(bp); + + if (netif_running(dev)) + bnx2x_nic_load(bp, LOAD_NORMAL); + + netif_device_attach(dev); + + rtnl_unlock(); +} + +static struct pci_error_handlers bnx2x_err_handler = { + .error_detected = bnx2x_io_error_detected, + .slot_reset = bnx2x_io_slot_reset, + .resume = bnx2x_io_resume, +}; + +static struct pci_driver bnx2x_pci_driver = { + .name = DRV_MODULE_NAME, + .id_table = bnx2x_pci_tbl, + .probe = bnx2x_init_one, + .remove = __devexit_p(bnx2x_remove_one), + .suspend = bnx2x_suspend, + .resume = bnx2x_resume, + .err_handler = &bnx2x_err_handler, +}; + +static int __init bnx2x_init(void) +{ + int ret; + + pr_info("%s", version); + + bnx2x_wq = create_singlethread_workqueue("bnx2x"); + if (bnx2x_wq == NULL) { + pr_err("Cannot create workqueue\n"); + return -ENOMEM; + } + + ret = pci_register_driver(&bnx2x_pci_driver); + if (ret) { + pr_err("Cannot register driver\n"); + destroy_workqueue(bnx2x_wq); + } + return ret; +} + +static void __exit bnx2x_cleanup(void) +{ + pci_unregister_driver(&bnx2x_pci_driver); + + destroy_workqueue(bnx2x_wq); +} + +void bnx2x_notify_link_changed(struct bnx2x *bp) +{ + REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + BP_FUNC(bp)*sizeof(u32), 1); +} + +module_init(bnx2x_init); +module_exit(bnx2x_cleanup); + +#ifdef BCM_CNIC +/** + * bnx2x_set_iscsi_eth_mac_addr - set iSCSI MAC(s). + * + * @bp: driver handle + * @set: set or clear the CAM entry + * + * This function will wait until the ramdord completion returns. + * Return 0 if success, -ENODEV if ramrod doesn't return. + */ +static inline int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp) +{ + unsigned long ramrod_flags = 0; + + __set_bit(RAMROD_COMP_WAIT, &ramrod_flags); + return bnx2x_set_mac_one(bp, bp->cnic_eth_dev.iscsi_mac, + &bp->iscsi_l2_mac_obj, true, + BNX2X_ISCSI_ETH_MAC, &ramrod_flags); +} + +/* count denotes the number of new completions we have seen */ +static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count) +{ + struct eth_spe *spe; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return; +#endif + + spin_lock_bh(&bp->spq_lock); + BUG_ON(bp->cnic_spq_pending < count); + bp->cnic_spq_pending -= count; + + + for (; bp->cnic_kwq_pending; bp->cnic_kwq_pending--) { + u16 type = (le16_to_cpu(bp->cnic_kwq_cons->hdr.type) + & SPE_HDR_CONN_TYPE) >> + SPE_HDR_CONN_TYPE_SHIFT; + u8 cmd = (le32_to_cpu(bp->cnic_kwq_cons->hdr.conn_and_cmd_data) + >> SPE_HDR_CMD_ID_SHIFT) & 0xff; + + /* Set validation for iSCSI L2 client before sending SETUP + * ramrod + */ + if (type == ETH_CONNECTION_TYPE) { + if (cmd == RAMROD_CMD_ID_ETH_CLIENT_SETUP) + bnx2x_set_ctx_validation(bp, &bp->context. + vcxt[BNX2X_ISCSI_ETH_CID].eth, + BNX2X_ISCSI_ETH_CID); + } + + /* + * There may be not more than 8 L2, not more than 8 L5 SPEs + * and in the air. We also check that number of outstanding + * COMMON ramrods is not more than the EQ and SPQ can + * accommodate. + */ + if (type == ETH_CONNECTION_TYPE) { + if (!atomic_read(&bp->cq_spq_left)) + break; + else + atomic_dec(&bp->cq_spq_left); + } else if (type == NONE_CONNECTION_TYPE) { + if (!atomic_read(&bp->eq_spq_left)) + break; + else + atomic_dec(&bp->eq_spq_left); + } else if ((type == ISCSI_CONNECTION_TYPE) || + (type == FCOE_CONNECTION_TYPE)) { + if (bp->cnic_spq_pending >= + bp->cnic_eth_dev.max_kwqe_pending) + break; + else + bp->cnic_spq_pending++; + } else { + BNX2X_ERR("Unknown SPE type: %d\n", type); + bnx2x_panic(); + break; + } + + spe = bnx2x_sp_get_next(bp); + *spe = *bp->cnic_kwq_cons; + + DP(NETIF_MSG_TIMER, "pending on SPQ %d, on KWQ %d count %d\n", + bp->cnic_spq_pending, bp->cnic_kwq_pending, count); + + if (bp->cnic_kwq_cons == bp->cnic_kwq_last) + bp->cnic_kwq_cons = bp->cnic_kwq; + else + bp->cnic_kwq_cons++; + } + bnx2x_sp_prod_update(bp); + spin_unlock_bh(&bp->spq_lock); +} + +static int bnx2x_cnic_sp_queue(struct net_device *dev, + struct kwqe_16 *kwqes[], u32 count) +{ + struct bnx2x *bp = netdev_priv(dev); + int i; + +#ifdef BNX2X_STOP_ON_ERROR + if (unlikely(bp->panic)) + return -EIO; +#endif + + spin_lock_bh(&bp->spq_lock); + + for (i = 0; i < count; i++) { + struct eth_spe *spe = (struct eth_spe *)kwqes[i]; + + if (bp->cnic_kwq_pending == MAX_SP_DESC_CNT) + break; + + *bp->cnic_kwq_prod = *spe; + + bp->cnic_kwq_pending++; + + DP(NETIF_MSG_TIMER, "L5 SPQE %x %x %x:%x pos %d\n", + spe->hdr.conn_and_cmd_data, spe->hdr.type, + spe->data.update_data_addr.hi, + spe->data.update_data_addr.lo, + bp->cnic_kwq_pending); + + if (bp->cnic_kwq_prod == bp->cnic_kwq_last) + bp->cnic_kwq_prod = bp->cnic_kwq; + else + bp->cnic_kwq_prod++; + } + + spin_unlock_bh(&bp->spq_lock); + + if (bp->cnic_spq_pending < bp->cnic_eth_dev.max_kwqe_pending) + bnx2x_cnic_sp_post(bp, 0); + + return i; +} + +static int bnx2x_cnic_ctl_send(struct bnx2x *bp, struct cnic_ctl_info *ctl) +{ + struct cnic_ops *c_ops; + int rc = 0; + + mutex_lock(&bp->cnic_mutex); + c_ops = rcu_dereference_protected(bp->cnic_ops, + lockdep_is_held(&bp->cnic_mutex)); + if (c_ops) + rc = c_ops->cnic_ctl(bp->cnic_data, ctl); + mutex_unlock(&bp->cnic_mutex); + + return rc; +} + +static int bnx2x_cnic_ctl_send_bh(struct bnx2x *bp, struct cnic_ctl_info *ctl) +{ + struct cnic_ops *c_ops; + int rc = 0; + + rcu_read_lock(); + c_ops = rcu_dereference(bp->cnic_ops); + if (c_ops) + rc = c_ops->cnic_ctl(bp->cnic_data, ctl); + rcu_read_unlock(); + + return rc; +} + +/* + * for commands that have no data + */ +int bnx2x_cnic_notify(struct bnx2x *bp, int cmd) +{ + struct cnic_ctl_info ctl = {0}; + + ctl.cmd = cmd; + + return bnx2x_cnic_ctl_send(bp, &ctl); +} + +static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid, u8 err) +{ + struct cnic_ctl_info ctl = {0}; + + /* first we tell CNIC and only then we count this as a completion */ + ctl.cmd = CNIC_CTL_COMPLETION_CMD; + ctl.data.comp.cid = cid; + ctl.data.comp.error = err; + + bnx2x_cnic_ctl_send_bh(bp, &ctl); + bnx2x_cnic_sp_post(bp, 0); +} + + +/* Called with netif_addr_lock_bh() taken. + * Sets an rx_mode config for an iSCSI ETH client. + * Doesn't block. + * Completion should be checked outside. + */ +static void bnx2x_set_iscsi_eth_rx_mode(struct bnx2x *bp, bool start) +{ + unsigned long accept_flags = 0, ramrod_flags = 0; + u8 cl_id = bnx2x_cnic_eth_cl_id(bp, BNX2X_ISCSI_ETH_CL_ID_IDX); + int sched_state = BNX2X_FILTER_ISCSI_ETH_STOP_SCHED; + + if (start) { + /* Start accepting on iSCSI L2 ring. Accept all multicasts + * because it's the only way for UIO Queue to accept + * multicasts (in non-promiscuous mode only one Queue per + * function will receive multicast packets (leading in our + * case). + */ + __set_bit(BNX2X_ACCEPT_UNICAST, &accept_flags); + __set_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept_flags); + __set_bit(BNX2X_ACCEPT_BROADCAST, &accept_flags); + __set_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags); + + /* Clear STOP_PENDING bit if START is requested */ + clear_bit(BNX2X_FILTER_ISCSI_ETH_STOP_SCHED, &bp->sp_state); + + sched_state = BNX2X_FILTER_ISCSI_ETH_START_SCHED; + } else + /* Clear START_PENDING bit if STOP is requested */ + clear_bit(BNX2X_FILTER_ISCSI_ETH_START_SCHED, &bp->sp_state); + + if (test_bit(BNX2X_FILTER_RX_MODE_PENDING, &bp->sp_state)) + set_bit(sched_state, &bp->sp_state); + else { + __set_bit(RAMROD_RX, &ramrod_flags); + bnx2x_set_q_rx_mode(bp, cl_id, 0, accept_flags, 0, + ramrod_flags); + } +} + + +static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl) +{ + struct bnx2x *bp = netdev_priv(dev); + int rc = 0; + + switch (ctl->cmd) { + case DRV_CTL_CTXTBL_WR_CMD: { + u32 index = ctl->data.io.offset; + dma_addr_t addr = ctl->data.io.dma_addr; + + bnx2x_ilt_wr(bp, index, addr); + break; + } + + case DRV_CTL_RET_L5_SPQ_CREDIT_CMD: { + int count = ctl->data.credit.credit_count; + + bnx2x_cnic_sp_post(bp, count); + break; + } + + /* rtnl_lock is held. */ + case DRV_CTL_START_L2_CMD: { + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + unsigned long sp_bits = 0; + + /* Configure the iSCSI classification object */ + bnx2x_init_mac_obj(bp, &bp->iscsi_l2_mac_obj, + cp->iscsi_l2_client_id, + cp->iscsi_l2_cid, BP_FUNC(bp), + bnx2x_sp(bp, mac_rdata), + bnx2x_sp_mapping(bp, mac_rdata), + BNX2X_FILTER_MAC_PENDING, + &bp->sp_state, BNX2X_OBJ_TYPE_RX, + &bp->macs_pool); + + /* Set iSCSI MAC address */ + rc = bnx2x_set_iscsi_eth_mac_addr(bp); + if (rc) + break; + + mmiowb(); + barrier(); + + /* Start accepting on iSCSI L2 ring */ + + netif_addr_lock_bh(dev); + bnx2x_set_iscsi_eth_rx_mode(bp, true); + netif_addr_unlock_bh(dev); + + /* bits to wait on */ + __set_bit(BNX2X_FILTER_RX_MODE_PENDING, &sp_bits); + __set_bit(BNX2X_FILTER_ISCSI_ETH_START_SCHED, &sp_bits); + + if (!bnx2x_wait_sp_comp(bp, sp_bits)) + BNX2X_ERR("rx_mode completion timed out!\n"); + + break; + } + + /* rtnl_lock is held. */ + case DRV_CTL_STOP_L2_CMD: { + unsigned long sp_bits = 0; + + /* Stop accepting on iSCSI L2 ring */ + netif_addr_lock_bh(dev); + bnx2x_set_iscsi_eth_rx_mode(bp, false); + netif_addr_unlock_bh(dev); + + /* bits to wait on */ + __set_bit(BNX2X_FILTER_RX_MODE_PENDING, &sp_bits); + __set_bit(BNX2X_FILTER_ISCSI_ETH_STOP_SCHED, &sp_bits); + + if (!bnx2x_wait_sp_comp(bp, sp_bits)) + BNX2X_ERR("rx_mode completion timed out!\n"); + + mmiowb(); + barrier(); + + /* Unset iSCSI L2 MAC */ + rc = bnx2x_del_all_macs(bp, &bp->iscsi_l2_mac_obj, + BNX2X_ISCSI_ETH_MAC, true); + break; + } + case DRV_CTL_RET_L2_SPQ_CREDIT_CMD: { + int count = ctl->data.credit.credit_count; + + smp_mb__before_atomic_inc(); + atomic_add(count, &bp->cq_spq_left); + smp_mb__after_atomic_inc(); + break; + } + + default: + BNX2X_ERR("unknown command %x\n", ctl->cmd); + rc = -EINVAL; + } + + return rc; +} + +void bnx2x_setup_cnic_irq_info(struct bnx2x *bp) +{ + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + + if (bp->flags & USING_MSIX_FLAG) { + cp->drv_state |= CNIC_DRV_STATE_USING_MSIX; + cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX; + cp->irq_arr[0].vector = bp->msix_table[1].vector; + } else { + cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX; + cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX; + } + if (!CHIP_IS_E1x(bp)) + cp->irq_arr[0].status_blk = (void *)bp->cnic_sb.e2_sb; + else + cp->irq_arr[0].status_blk = (void *)bp->cnic_sb.e1x_sb; + + cp->irq_arr[0].status_blk_num = bnx2x_cnic_fw_sb_id(bp); + cp->irq_arr[0].status_blk_num2 = bnx2x_cnic_igu_sb_id(bp); + cp->irq_arr[1].status_blk = bp->def_status_blk; + cp->irq_arr[1].status_blk_num = DEF_SB_ID; + cp->irq_arr[1].status_blk_num2 = DEF_SB_IGU_ID; + + cp->num_irq = 2; +} + +static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops, + void *data) +{ + struct bnx2x *bp = netdev_priv(dev); + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + + if (ops == NULL) + return -EINVAL; + + bp->cnic_kwq = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!bp->cnic_kwq) + return -ENOMEM; + + bp->cnic_kwq_cons = bp->cnic_kwq; + bp->cnic_kwq_prod = bp->cnic_kwq; + bp->cnic_kwq_last = bp->cnic_kwq + MAX_SP_DESC_CNT; + + bp->cnic_spq_pending = 0; + bp->cnic_kwq_pending = 0; + + bp->cnic_data = data; + + cp->num_irq = 0; + cp->drv_state |= CNIC_DRV_STATE_REGD; + cp->iro_arr = bp->iro_arr; + + bnx2x_setup_cnic_irq_info(bp); + + rcu_assign_pointer(bp->cnic_ops, ops); + + return 0; +} + +static int bnx2x_unregister_cnic(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + + mutex_lock(&bp->cnic_mutex); + cp->drv_state = 0; + rcu_assign_pointer(bp->cnic_ops, NULL); + mutex_unlock(&bp->cnic_mutex); + synchronize_rcu(); + kfree(bp->cnic_kwq); + bp->cnic_kwq = NULL; + + return 0; +} + +struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev) +{ + struct bnx2x *bp = netdev_priv(dev); + struct cnic_eth_dev *cp = &bp->cnic_eth_dev; + + /* If both iSCSI and FCoE are disabled - return NULL in + * order to indicate CNIC that it should not try to work + * with this device. + */ + if (NO_ISCSI(bp) && NO_FCOE(bp)) + return NULL; + + cp->drv_owner = THIS_MODULE; + cp->chip_id = CHIP_ID(bp); + cp->pdev = bp->pdev; + cp->io_base = bp->regview; + cp->io_base2 = bp->doorbells; + cp->max_kwqe_pending = 8; + cp->ctx_blk_size = CDU_ILT_PAGE_SZ; + cp->ctx_tbl_offset = FUNC_ILT_BASE(BP_FUNC(bp)) + + bnx2x_cid_ilt_lines(bp); + cp->ctx_tbl_len = CNIC_ILT_LINES; + cp->starting_cid = bnx2x_cid_ilt_lines(bp) * ILT_PAGE_CIDS; + cp->drv_submit_kwqes_16 = bnx2x_cnic_sp_queue; + cp->drv_ctl = bnx2x_drv_ctl; + cp->drv_register_cnic = bnx2x_register_cnic; + cp->drv_unregister_cnic = bnx2x_unregister_cnic; + cp->fcoe_init_cid = BNX2X_FCOE_ETH_CID; + cp->iscsi_l2_client_id = + bnx2x_cnic_eth_cl_id(bp, BNX2X_ISCSI_ETH_CL_ID_IDX); + cp->iscsi_l2_cid = BNX2X_ISCSI_ETH_CID; + + if (NO_ISCSI_OOO(bp)) + cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI_OOO; + + if (NO_ISCSI(bp)) + cp->drv_state |= CNIC_DRV_STATE_NO_ISCSI; + + if (NO_FCOE(bp)) + cp->drv_state |= CNIC_DRV_STATE_NO_FCOE; + + DP(BNX2X_MSG_SP, "page_size %d, tbl_offset %d, tbl_lines %d, " + "starting cid %d\n", + cp->ctx_blk_size, + cp->ctx_tbl_offset, + cp->ctx_tbl_len, + cp->starting_cid); + return cp; +} +EXPORT_SYMBOL(bnx2x_cnic_probe); + +#endif /* BCM_CNIC */ + diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h new file mode 100644 index 000000000000..27b5ecb11830 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -0,0 +1,7146 @@ +/* bnx2x_reg.h: Broadcom Everest network driver. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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. + * + * The registers description starts with the register Access type followed + * by size in bits. For example [RW 32]. The access types are: + * R - Read only + * RC - Clear on read + * RW - Read/Write + * ST - Statistics register (clear on read) + * W - Write only + * WB - Wide bus register - the size is over 32 bits and it should be + * read/write in consecutive 32 bits accesses + * WR - Write Clear (write 1 to clear the bit) + * + */ +#ifndef BNX2X_REG_H +#define BNX2X_REG_H + +#define ATC_ATC_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define ATC_ATC_INT_STS_REG_ATC_GPA_MULTIPLE_HITS (0x1<<2) +#define ATC_ATC_INT_STS_REG_ATC_IREQ_LESS_THAN_STU (0x1<<5) +#define ATC_ATC_INT_STS_REG_ATC_RCPL_TO_EMPTY_CNT (0x1<<3) +#define ATC_ATC_INT_STS_REG_ATC_TCPL_ERROR (0x1<<4) +#define ATC_ATC_INT_STS_REG_ATC_TCPL_TO_NOT_PEND (0x1<<1) +/* [RW 1] Initiate the ATC array - reset all the valid bits */ +#define ATC_REG_ATC_INIT_ARRAY 0x1100b8 +/* [R 1] ATC initalization done */ +#define ATC_REG_ATC_INIT_DONE 0x1100bc +/* [RC 6] Interrupt register #0 read clear */ +#define ATC_REG_ATC_INT_STS_CLR 0x1101c0 +/* [RW 5] Parity mask register #0 read/write */ +#define ATC_REG_ATC_PRTY_MASK 0x1101d8 +/* [RC 5] Parity register #0 read clear */ +#define ATC_REG_ATC_PRTY_STS_CLR 0x1101d0 +/* [RW 19] Interrupt mask register #0 read/write */ +#define BRB1_REG_BRB1_INT_MASK 0x60128 +/* [R 19] Interrupt register #0 read */ +#define BRB1_REG_BRB1_INT_STS 0x6011c +/* [RW 4] Parity mask register #0 read/write */ +#define BRB1_REG_BRB1_PRTY_MASK 0x60138 +/* [R 4] Parity register #0 read */ +#define BRB1_REG_BRB1_PRTY_STS 0x6012c +/* [RC 4] Parity register #0 read clear */ +#define BRB1_REG_BRB1_PRTY_STS_CLR 0x60130 +/* [RW 10] At address BRB1_IND_FREE_LIST_PRS_CRDT initialize free head. At + * address BRB1_IND_FREE_LIST_PRS_CRDT+1 initialize free tail. At address + * BRB1_IND_FREE_LIST_PRS_CRDT+2 initialize parser initial credit. Warning - + * following reset the first rbc access to this reg must be write; there can + * be no more rbc writes after the first one; there can be any number of rbc + * read following the first write; rbc access not following these rules will + * result in hang condition. */ +#define BRB1_REG_FREE_LIST_PRS_CRDT 0x60200 +/* [RW 10] The number of free blocks below which the full signal to class 0 + * is asserted */ +#define BRB1_REG_FULL_0_XOFF_THRESHOLD_0 0x601d0 +#define BRB1_REG_FULL_0_XOFF_THRESHOLD_1 0x60230 +/* [RW 11] The number of free blocks above which the full signal to class 0 + * is de-asserted */ +#define BRB1_REG_FULL_0_XON_THRESHOLD_0 0x601d4 +#define BRB1_REG_FULL_0_XON_THRESHOLD_1 0x60234 +/* [RW 11] The number of free blocks below which the full signal to class 1 + * is asserted */ +#define BRB1_REG_FULL_1_XOFF_THRESHOLD_0 0x601d8 +#define BRB1_REG_FULL_1_XOFF_THRESHOLD_1 0x60238 +/* [RW 11] The number of free blocks above which the full signal to class 1 + * is de-asserted */ +#define BRB1_REG_FULL_1_XON_THRESHOLD_0 0x601dc +#define BRB1_REG_FULL_1_XON_THRESHOLD_1 0x6023c +/* [RW 11] The number of free blocks below which the full signal to the LB + * port is asserted */ +#define BRB1_REG_FULL_LB_XOFF_THRESHOLD 0x601e0 +/* [RW 10] The number of free blocks above which the full signal to the LB + * port is de-asserted */ +#define BRB1_REG_FULL_LB_XON_THRESHOLD 0x601e4 +/* [RW 10] The number of free blocks above which the High_llfc signal to + interface #n is de-asserted. */ +#define BRB1_REG_HIGH_LLFC_HIGH_THRESHOLD_0 0x6014c +/* [RW 10] The number of free blocks below which the High_llfc signal to + interface #n is asserted. */ +#define BRB1_REG_HIGH_LLFC_LOW_THRESHOLD_0 0x6013c +/* [RW 11] The number of blocks guarantied for the LB port */ +#define BRB1_REG_LB_GUARANTIED 0x601ec +/* [RW 11] The hysteresis on the guarantied buffer space for the Lb port + * before signaling XON. */ +#define BRB1_REG_LB_GUARANTIED_HYST 0x60264 +/* [RW 24] LL RAM data. */ +#define BRB1_REG_LL_RAM 0x61000 +/* [RW 10] The number of free blocks above which the Low_llfc signal to + interface #n is de-asserted. */ +#define BRB1_REG_LOW_LLFC_HIGH_THRESHOLD_0 0x6016c +/* [RW 10] The number of free blocks below which the Low_llfc signal to + interface #n is asserted. */ +#define BRB1_REG_LOW_LLFC_LOW_THRESHOLD_0 0x6015c +/* [RW 11] The number of blocks guarantied for class 0 in MAC 0. The + * register is applicable only when per_class_guaranty_mode is set. */ +#define BRB1_REG_MAC_0_CLASS_0_GUARANTIED 0x60244 +/* [RW 11] The hysteresis on the guarantied buffer space for class 0 in MAC + * 1 before signaling XON. The register is applicable only when + * per_class_guaranty_mode is set. */ +#define BRB1_REG_MAC_0_CLASS_0_GUARANTIED_HYST 0x60254 +/* [RW 11] The number of blocks guarantied for class 1 in MAC 0. The + * register is applicable only when per_class_guaranty_mode is set. */ +#define BRB1_REG_MAC_0_CLASS_1_GUARANTIED 0x60248 +/* [RW 11] The hysteresis on the guarantied buffer space for class 1in MAC 0 + * before signaling XON. The register is applicable only when + * per_class_guaranty_mode is set. */ +#define BRB1_REG_MAC_0_CLASS_1_GUARANTIED_HYST 0x60258 +/* [RW 11] The number of blocks guarantied for class 0in MAC1.The register + * is applicable only when per_class_guaranty_mode is set. */ +#define BRB1_REG_MAC_1_CLASS_0_GUARANTIED 0x6024c +/* [RW 11] The hysteresis on the guarantied buffer space for class 0 in MAC + * 1 before signaling XON. The register is applicable only when + * per_class_guaranty_mode is set. */ +#define BRB1_REG_MAC_1_CLASS_0_GUARANTIED_HYST 0x6025c +/* [RW 11] The number of blocks guarantied for class 1 in MAC 1. The + * register is applicable only when per_class_guaranty_mode is set. */ +#define BRB1_REG_MAC_1_CLASS_1_GUARANTIED 0x60250 +/* [RW 11] The hysteresis on the guarantied buffer space for class 1 in MAC + * 1 before signaling XON. The register is applicable only when + * per_class_guaranty_mode is set. */ +#define BRB1_REG_MAC_1_CLASS_1_GUARANTIED_HYST 0x60260 +/* [RW 11] The number of blocks guarantied for the MAC port. The register is + * applicable only when per_class_guaranty_mode is reset. */ +#define BRB1_REG_MAC_GUARANTIED_0 0x601e8 +#define BRB1_REG_MAC_GUARANTIED_1 0x60240 +/* [R 24] The number of full blocks. */ +#define BRB1_REG_NUM_OF_FULL_BLOCKS 0x60090 +/* [ST 32] The number of cycles that the write_full signal towards MAC #0 + was asserted. */ +#define BRB1_REG_NUM_OF_FULL_CYCLES_0 0x600c8 +#define BRB1_REG_NUM_OF_FULL_CYCLES_1 0x600cc +#define BRB1_REG_NUM_OF_FULL_CYCLES_4 0x600d8 +/* [ST 32] The number of cycles that the pause signal towards MAC #0 was + asserted. */ +#define BRB1_REG_NUM_OF_PAUSE_CYCLES_0 0x600b8 +#define BRB1_REG_NUM_OF_PAUSE_CYCLES_1 0x600bc +/* [RW 10] The number of free blocks below which the pause signal to class 0 + * is asserted */ +#define BRB1_REG_PAUSE_0_XOFF_THRESHOLD_0 0x601c0 +#define BRB1_REG_PAUSE_0_XOFF_THRESHOLD_1 0x60220 +/* [RW 11] The number of free blocks above which the pause signal to class 0 + * is de-asserted */ +#define BRB1_REG_PAUSE_0_XON_THRESHOLD_0 0x601c4 +#define BRB1_REG_PAUSE_0_XON_THRESHOLD_1 0x60224 +/* [RW 11] The number of free blocks below which the pause signal to class 1 + * is asserted */ +#define BRB1_REG_PAUSE_1_XOFF_THRESHOLD_0 0x601c8 +#define BRB1_REG_PAUSE_1_XOFF_THRESHOLD_1 0x60228 +/* [RW 11] The number of free blocks above which the pause signal to class 1 + * is de-asserted */ +#define BRB1_REG_PAUSE_1_XON_THRESHOLD_0 0x601cc +#define BRB1_REG_PAUSE_1_XON_THRESHOLD_1 0x6022c +/* [RW 10] Write client 0: De-assert pause threshold. Not Functional */ +#define BRB1_REG_PAUSE_HIGH_THRESHOLD_0 0x60078 +#define BRB1_REG_PAUSE_HIGH_THRESHOLD_1 0x6007c +/* [RW 10] Write client 0: Assert pause threshold. */ +#define BRB1_REG_PAUSE_LOW_THRESHOLD_0 0x60068 +#define BRB1_REG_PAUSE_LOW_THRESHOLD_1 0x6006c +/* [R 24] The number of full blocks occupied by port. */ +#define BRB1_REG_PORT_NUM_OCC_BLOCKS_0 0x60094 +/* [RW 1] Reset the design by software. */ +#define BRB1_REG_SOFT_RESET 0x600dc +/* [R 5] Used to read the value of the XX protection CAM occupancy counter. */ +#define CCM_REG_CAM_OCCUP 0xd0188 +/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CCM_CFC_IFEN 0xd003c +/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CCM_CQM_IFEN 0xd000c +/* [RW 1] If set the Q index; received from the QM is inserted to event ID. + Otherwise 0 is inserted. */ +#define CCM_REG_CCM_CQM_USE_Q 0xd00c0 +/* [RW 11] Interrupt mask register #0 read/write */ +#define CCM_REG_CCM_INT_MASK 0xd01e4 +/* [R 11] Interrupt register #0 read */ +#define CCM_REG_CCM_INT_STS 0xd01d8 +/* [RW 27] Parity mask register #0 read/write */ +#define CCM_REG_CCM_PRTY_MASK 0xd01f4 +/* [R 27] Parity register #0 read */ +#define CCM_REG_CCM_PRTY_STS 0xd01e8 +/* [RC 27] Parity register #0 read clear */ +#define CCM_REG_CCM_PRTY_STS_CLR 0xd01ec +/* [RW 3] The size of AG context region 0 in REG-pairs. Designates the MS + REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). + Is used to determine the number of the AG context REG-pairs written back; + when the input message Reg1WbFlg isn't set. */ +#define CCM_REG_CCM_REG0_SZ 0xd00c4 +/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CCM_STORM0_IFEN 0xd0004 +/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CCM_STORM1_IFEN 0xd0008 +/* [RW 1] CDU AG read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define CCM_REG_CDU_AG_RD_IFEN 0xd0030 +/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input + are disregarded; all other signals are treated as usual; if 1 - normal + activity. */ +#define CCM_REG_CDU_AG_WR_IFEN 0xd002c +/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define CCM_REG_CDU_SM_RD_IFEN 0xd0038 +/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid + input is disregarded; all other signals are treated as usual; if 1 - + normal activity. */ +#define CCM_REG_CDU_SM_WR_IFEN 0xd0034 +/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 1 at start-up. */ +#define CCM_REG_CFC_INIT_CRD 0xd0204 +/* [RW 2] Auxiliary counter flag Q number 1. */ +#define CCM_REG_CNT_AUX1_Q 0xd00c8 +/* [RW 2] Auxiliary counter flag Q number 2. */ +#define CCM_REG_CNT_AUX2_Q 0xd00cc +/* [RW 28] The CM header value for QM request (primary). */ +#define CCM_REG_CQM_CCM_HDR_P 0xd008c +/* [RW 28] The CM header value for QM request (secondary). */ +#define CCM_REG_CQM_CCM_HDR_S 0xd0090 +/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CQM_CCM_IFEN 0xd0014 +/* [RW 6] QM output initial credit. Max credit available - 32. Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 32 at start-up. */ +#define CCM_REG_CQM_INIT_CRD 0xd020c +/* [RW 3] The weight of the QM (primary) input in the WRR mechanism. 0 + stands for weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_CQM_P_WEIGHT 0xd00b8 +/* [RW 3] The weight of the QM (secondary) input in the WRR mechanism. 0 + stands for weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_CQM_S_WEIGHT 0xd00bc +/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_CSDM_IFEN 0xd0018 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the SDM interface is detected. */ +#define CCM_REG_CSDM_LENGTH_MIS 0xd0170 +/* [RW 3] The weight of the SDM input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_CSDM_WEIGHT 0xd00b4 +/* [RW 28] The CM header for QM formatting in case of an error in the QM + inputs. */ +#define CCM_REG_ERR_CCM_HDR 0xd0094 +/* [RW 8] The Event ID in case the input message ErrorFlg is set. */ +#define CCM_REG_ERR_EVNT_ID 0xd0098 +/* [RW 8] FIC0 output initial credit. Max credit available - 255. Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define CCM_REG_FIC0_INIT_CRD 0xd0210 +/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define CCM_REG_FIC1_INIT_CRD 0xd0214 +/* [RW 1] Arbitration between Input Arbiter groups: 0 - fair Round-Robin; 1 + - strict priority defined by ~ccm_registers_gr_ag_pr.gr_ag_pr; + ~ccm_registers_gr_ld0_pr.gr_ld0_pr and + ~ccm_registers_gr_ld1_pr.gr_ld1_pr. Groups are according to channels and + outputs to STORM: aggregation; load FIC0; load FIC1 and store. */ +#define CCM_REG_GR_ARB_TYPE 0xd015c +/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed; that the Store channel priority is + the compliment to 4 of the rest priorities - Aggregation channel; Load + (FIC0) channel and Load (FIC1). */ +#define CCM_REG_GR_LD0_PR 0xd0164 +/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed; that the Store channel priority is + the compliment to 4 of the rest priorities - Aggregation channel; Load + (FIC0) channel and Load (FIC1). */ +#define CCM_REG_GR_LD1_PR 0xd0168 +/* [RW 2] General flags index. */ +#define CCM_REG_INV_DONE_Q 0xd0108 +/* [RW 4] The number of double REG-pairs(128 bits); loaded from the STORM + context and sent to STORM; for a specific connection type. The double + REG-pairs are used in order to align to STORM context row size of 128 + bits. The offset of these data in the STORM context is always 0. Index + _(0..15) stands for the connection type (one of 16). */ +#define CCM_REG_N_SM_CTX_LD_0 0xd004c +#define CCM_REG_N_SM_CTX_LD_1 0xd0050 +#define CCM_REG_N_SM_CTX_LD_2 0xd0054 +#define CCM_REG_N_SM_CTX_LD_3 0xd0058 +#define CCM_REG_N_SM_CTX_LD_4 0xd005c +/* [RW 1] Input pbf Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define CCM_REG_PBF_IFEN 0xd0028 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the pbf interface is detected. */ +#define CCM_REG_PBF_LENGTH_MIS 0xd0180 +/* [RW 3] The weight of the input pbf in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_PBF_WEIGHT 0xd00ac +#define CCM_REG_PHYS_QNUM1_0 0xd0134 +#define CCM_REG_PHYS_QNUM1_1 0xd0138 +#define CCM_REG_PHYS_QNUM2_0 0xd013c +#define CCM_REG_PHYS_QNUM2_1 0xd0140 +#define CCM_REG_PHYS_QNUM3_0 0xd0144 +#define CCM_REG_PHYS_QNUM3_1 0xd0148 +#define CCM_REG_QOS_PHYS_QNUM0_0 0xd0114 +#define CCM_REG_QOS_PHYS_QNUM0_1 0xd0118 +#define CCM_REG_QOS_PHYS_QNUM1_0 0xd011c +#define CCM_REG_QOS_PHYS_QNUM1_1 0xd0120 +#define CCM_REG_QOS_PHYS_QNUM2_0 0xd0124 +#define CCM_REG_QOS_PHYS_QNUM2_1 0xd0128 +#define CCM_REG_QOS_PHYS_QNUM3_0 0xd012c +#define CCM_REG_QOS_PHYS_QNUM3_1 0xd0130 +/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define CCM_REG_STORM_CCM_IFEN 0xd0010 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the STORM interface is detected. */ +#define CCM_REG_STORM_LENGTH_MIS 0xd016c +/* [RW 3] The weight of the STORM input in the WRR (Weighted Round robin) + mechanism. 0 stands for weight 8 (the most prioritised); 1 stands for + weight 1(least prioritised); 2 stands for weight 2 (more prioritised); + tc. */ +#define CCM_REG_STORM_WEIGHT 0xd009c +/* [RW 1] Input tsem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define CCM_REG_TSEM_IFEN 0xd001c +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the tsem interface is detected. */ +#define CCM_REG_TSEM_LENGTH_MIS 0xd0174 +/* [RW 3] The weight of the input tsem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_TSEM_WEIGHT 0xd00a0 +/* [RW 1] Input usem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define CCM_REG_USEM_IFEN 0xd0024 +/* [RC 1] Set when message length mismatch (relative to last indication) at + the usem interface is detected. */ +#define CCM_REG_USEM_LENGTH_MIS 0xd017c +/* [RW 3] The weight of the input usem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_USEM_WEIGHT 0xd00a8 +/* [RW 1] Input xsem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define CCM_REG_XSEM_IFEN 0xd0020 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the xsem interface is detected. */ +#define CCM_REG_XSEM_LENGTH_MIS 0xd0178 +/* [RW 3] The weight of the input xsem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define CCM_REG_XSEM_WEIGHT 0xd00a4 +/* [RW 19] Indirect access to the descriptor table of the XX protection + mechanism. The fields are: [5:0] - message length; [12:6] - message + pointer; 18:13] - next pointer. */ +#define CCM_REG_XX_DESCR_TABLE 0xd0300 +#define CCM_REG_XX_DESCR_TABLE_SIZE 24 +/* [R 7] Used to read the value of XX protection Free counter. */ +#define CCM_REG_XX_FREE 0xd0184 +/* [RW 6] Initial value for the credit counter; responsible for fulfilling + of the Input Stage XX protection buffer by the XX protection pending + messages. Max credit available - 127. Write writes the initial credit + value; read returns the current value of the credit counter. Must be + initialized to maximum XX protected message size - 2 at start-up. */ +#define CCM_REG_XX_INIT_CRD 0xd0220 +/* [RW 7] The maximum number of pending messages; which may be stored in XX + protection. At read the ~ccm_registers_xx_free.xx_free counter is read. + At write comprises the start value of the ~ccm_registers_xx_free.xx_free + counter. */ +#define CCM_REG_XX_MSG_NUM 0xd0224 +/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */ +#define CCM_REG_XX_OVFL_EVNT_ID 0xd0044 +/* [RW 18] Indirect access to the XX table of the XX protection mechanism. + The fields are: [5:0] - tail pointer; 11:6] - Link List size; 17:12] - + header pointer. */ +#define CCM_REG_XX_TABLE 0xd0280 +#define CDU_REG_CDU_CHK_MASK0 0x101000 +#define CDU_REG_CDU_CHK_MASK1 0x101004 +#define CDU_REG_CDU_CONTROL0 0x101008 +#define CDU_REG_CDU_DEBUG 0x101010 +#define CDU_REG_CDU_GLOBAL_PARAMS 0x101020 +/* [RW 7] Interrupt mask register #0 read/write */ +#define CDU_REG_CDU_INT_MASK 0x10103c +/* [R 7] Interrupt register #0 read */ +#define CDU_REG_CDU_INT_STS 0x101030 +/* [RW 5] Parity mask register #0 read/write */ +#define CDU_REG_CDU_PRTY_MASK 0x10104c +/* [R 5] Parity register #0 read */ +#define CDU_REG_CDU_PRTY_STS 0x101040 +/* [RC 5] Parity register #0 read clear */ +#define CDU_REG_CDU_PRTY_STS_CLR 0x101044 +/* [RC 32] logging of error data in case of a CDU load error: + {expected_cid[15:0]; xpected_type[2:0]; xpected_region[2:0]; ctive_error; + ype_error; ctual_active; ctual_compressed_context}; */ +#define CDU_REG_ERROR_DATA 0x101014 +/* [WB 216] L1TT ram access. each entry has the following format : + {mrege_regions[7:0]; ffset12[5:0]...offset0[5:0]; + ength12[5:0]...length0[5:0]; d12[3:0]...id0[3:0]} */ +#define CDU_REG_L1TT 0x101800 +/* [WB 24] MATT ram access. each entry has the following + format:{RegionLength[11:0]; egionOffset[11:0]} */ +#define CDU_REG_MATT 0x101100 +/* [RW 1] when this bit is set the CDU operates in e1hmf mode */ +#define CDU_REG_MF_MODE 0x101050 +/* [R 1] indication the initializing the activity counter by the hardware + was done. */ +#define CFC_REG_AC_INIT_DONE 0x104078 +/* [RW 13] activity counter ram access */ +#define CFC_REG_ACTIVITY_COUNTER 0x104400 +#define CFC_REG_ACTIVITY_COUNTER_SIZE 256 +/* [R 1] indication the initializing the cams by the hardware was done. */ +#define CFC_REG_CAM_INIT_DONE 0x10407c +/* [RW 2] Interrupt mask register #0 read/write */ +#define CFC_REG_CFC_INT_MASK 0x104108 +/* [R 2] Interrupt register #0 read */ +#define CFC_REG_CFC_INT_STS 0x1040fc +/* [RC 2] Interrupt register #0 read clear */ +#define CFC_REG_CFC_INT_STS_CLR 0x104100 +/* [RW 4] Parity mask register #0 read/write */ +#define CFC_REG_CFC_PRTY_MASK 0x104118 +/* [R 4] Parity register #0 read */ +#define CFC_REG_CFC_PRTY_STS 0x10410c +/* [RC 4] Parity register #0 read clear */ +#define CFC_REG_CFC_PRTY_STS_CLR 0x104110 +/* [RW 21] CID cam access (21:1 - Data; alid - 0) */ +#define CFC_REG_CID_CAM 0x104800 +#define CFC_REG_CONTROL0 0x104028 +#define CFC_REG_DEBUG0 0x104050 +/* [RW 14] indicates per error (in #cfc_registers_cfc_error_vector.cfc_error + vector) whether the cfc should be disabled upon it */ +#define CFC_REG_DISABLE_ON_ERROR 0x104044 +/* [RC 14] CFC error vector. when the CFC detects an internal error it will + set one of these bits. the bit description can be found in CFC + specifications */ +#define CFC_REG_ERROR_VECTOR 0x10403c +/* [WB 93] LCID info ram access */ +#define CFC_REG_INFO_RAM 0x105000 +#define CFC_REG_INFO_RAM_SIZE 1024 +#define CFC_REG_INIT_REG 0x10404c +#define CFC_REG_INTERFACES 0x104058 +/* [RW 24] {weight_load_client7[2:0] to weight_load_client0[2:0]}. this + field allows changing the priorities of the weighted-round-robin arbiter + which selects which CFC load client should be served next */ +#define CFC_REG_LCREQ_WEIGHTS 0x104084 +/* [RW 16] Link List ram access; data = {prev_lcid; ext_lcid} */ +#define CFC_REG_LINK_LIST 0x104c00 +#define CFC_REG_LINK_LIST_SIZE 256 +/* [R 1] indication the initializing the link list by the hardware was done. */ +#define CFC_REG_LL_INIT_DONE 0x104074 +/* [R 9] Number of allocated LCIDs which are at empty state */ +#define CFC_REG_NUM_LCIDS_ALLOC 0x104020 +/* [R 9] Number of Arriving LCIDs in Link List Block */ +#define CFC_REG_NUM_LCIDS_ARRIVING 0x104004 +#define CFC_REG_NUM_LCIDS_INSIDE_PF 0x104120 +/* [R 9] Number of Leaving LCIDs in Link List Block */ +#define CFC_REG_NUM_LCIDS_LEAVING 0x104018 +#define CFC_REG_WEAK_ENABLE_PF 0x104124 +/* [RW 8] The event id for aggregated interrupt 0 */ +#define CSDM_REG_AGG_INT_EVENT_0 0xc2038 +#define CSDM_REG_AGG_INT_EVENT_10 0xc2060 +#define CSDM_REG_AGG_INT_EVENT_11 0xc2064 +#define CSDM_REG_AGG_INT_EVENT_12 0xc2068 +#define CSDM_REG_AGG_INT_EVENT_13 0xc206c +#define CSDM_REG_AGG_INT_EVENT_14 0xc2070 +#define CSDM_REG_AGG_INT_EVENT_15 0xc2074 +#define CSDM_REG_AGG_INT_EVENT_16 0xc2078 +#define CSDM_REG_AGG_INT_EVENT_2 0xc2040 +#define CSDM_REG_AGG_INT_EVENT_3 0xc2044 +#define CSDM_REG_AGG_INT_EVENT_4 0xc2048 +#define CSDM_REG_AGG_INT_EVENT_5 0xc204c +#define CSDM_REG_AGG_INT_EVENT_6 0xc2050 +#define CSDM_REG_AGG_INT_EVENT_7 0xc2054 +#define CSDM_REG_AGG_INT_EVENT_8 0xc2058 +#define CSDM_REG_AGG_INT_EVENT_9 0xc205c +/* [RW 1] For each aggregated interrupt index whether the mode is normal (0) + or auto-mask-mode (1) */ +#define CSDM_REG_AGG_INT_MODE_10 0xc21e0 +#define CSDM_REG_AGG_INT_MODE_11 0xc21e4 +#define CSDM_REG_AGG_INT_MODE_12 0xc21e8 +#define CSDM_REG_AGG_INT_MODE_13 0xc21ec +#define CSDM_REG_AGG_INT_MODE_14 0xc21f0 +#define CSDM_REG_AGG_INT_MODE_15 0xc21f4 +#define CSDM_REG_AGG_INT_MODE_16 0xc21f8 +#define CSDM_REG_AGG_INT_MODE_6 0xc21d0 +#define CSDM_REG_AGG_INT_MODE_7 0xc21d4 +#define CSDM_REG_AGG_INT_MODE_8 0xc21d8 +#define CSDM_REG_AGG_INT_MODE_9 0xc21dc +/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ +#define CSDM_REG_CFC_RSP_START_ADDR 0xc2008 +/* [RW 16] The maximum value of the completion counter #0 */ +#define CSDM_REG_CMP_COUNTER_MAX0 0xc201c +/* [RW 16] The maximum value of the completion counter #1 */ +#define CSDM_REG_CMP_COUNTER_MAX1 0xc2020 +/* [RW 16] The maximum value of the completion counter #2 */ +#define CSDM_REG_CMP_COUNTER_MAX2 0xc2024 +/* [RW 16] The maximum value of the completion counter #3 */ +#define CSDM_REG_CMP_COUNTER_MAX3 0xc2028 +/* [RW 13] The start address in the internal RAM for the completion + counters. */ +#define CSDM_REG_CMP_COUNTER_START_ADDR 0xc200c +/* [RW 32] Interrupt mask register #0 read/write */ +#define CSDM_REG_CSDM_INT_MASK_0 0xc229c +#define CSDM_REG_CSDM_INT_MASK_1 0xc22ac +/* [R 32] Interrupt register #0 read */ +#define CSDM_REG_CSDM_INT_STS_0 0xc2290 +#define CSDM_REG_CSDM_INT_STS_1 0xc22a0 +/* [RW 11] Parity mask register #0 read/write */ +#define CSDM_REG_CSDM_PRTY_MASK 0xc22bc +/* [R 11] Parity register #0 read */ +#define CSDM_REG_CSDM_PRTY_STS 0xc22b0 +/* [RC 11] Parity register #0 read clear */ +#define CSDM_REG_CSDM_PRTY_STS_CLR 0xc22b4 +#define CSDM_REG_ENABLE_IN1 0xc2238 +#define CSDM_REG_ENABLE_IN2 0xc223c +#define CSDM_REG_ENABLE_OUT1 0xc2240 +#define CSDM_REG_ENABLE_OUT2 0xc2244 +/* [RW 4] The initial number of messages that can be sent to the pxp control + interface without receiving any ACK. */ +#define CSDM_REG_INIT_CREDIT_PXP_CTRL 0xc24bc +/* [ST 32] The number of ACK after placement messages received */ +#define CSDM_REG_NUM_OF_ACK_AFTER_PLACE 0xc227c +/* [ST 32] The number of packet end messages received from the parser */ +#define CSDM_REG_NUM_OF_PKT_END_MSG 0xc2274 +/* [ST 32] The number of requests received from the pxp async if */ +#define CSDM_REG_NUM_OF_PXP_ASYNC_REQ 0xc2278 +/* [ST 32] The number of commands received in queue 0 */ +#define CSDM_REG_NUM_OF_Q0_CMD 0xc2248 +/* [ST 32] The number of commands received in queue 10 */ +#define CSDM_REG_NUM_OF_Q10_CMD 0xc226c +/* [ST 32] The number of commands received in queue 11 */ +#define CSDM_REG_NUM_OF_Q11_CMD 0xc2270 +/* [ST 32] The number of commands received in queue 1 */ +#define CSDM_REG_NUM_OF_Q1_CMD 0xc224c +/* [ST 32] The number of commands received in queue 3 */ +#define CSDM_REG_NUM_OF_Q3_CMD 0xc2250 +/* [ST 32] The number of commands received in queue 4 */ +#define CSDM_REG_NUM_OF_Q4_CMD 0xc2254 +/* [ST 32] The number of commands received in queue 5 */ +#define CSDM_REG_NUM_OF_Q5_CMD 0xc2258 +/* [ST 32] The number of commands received in queue 6 */ +#define CSDM_REG_NUM_OF_Q6_CMD 0xc225c +/* [ST 32] The number of commands received in queue 7 */ +#define CSDM_REG_NUM_OF_Q7_CMD 0xc2260 +/* [ST 32] The number of commands received in queue 8 */ +#define CSDM_REG_NUM_OF_Q8_CMD 0xc2264 +/* [ST 32] The number of commands received in queue 9 */ +#define CSDM_REG_NUM_OF_Q9_CMD 0xc2268 +/* [RW 13] The start address in the internal RAM for queue counters */ +#define CSDM_REG_Q_COUNTER_START_ADDR 0xc2010 +/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */ +#define CSDM_REG_RSP_PXP_CTRL_RDATA_EMPTY 0xc2548 +/* [R 1] parser fifo empty in sdm_sync block */ +#define CSDM_REG_SYNC_PARSER_EMPTY 0xc2550 +/* [R 1] parser serial fifo empty in sdm_sync block */ +#define CSDM_REG_SYNC_SYNC_EMPTY 0xc2558 +/* [RW 32] Tick for timer counter. Applicable only when + ~csdm_registers_timer_tick_enable.timer_tick_enable =1 */ +#define CSDM_REG_TIMER_TICK 0xc2000 +/* [RW 5] The number of time_slots in the arbitration cycle */ +#define CSEM_REG_ARB_CYCLE_SIZE 0x200034 +/* [RW 3] The source that is associated with arbitration element 0. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2 */ +#define CSEM_REG_ARB_ELEMENT0 0x200020 +/* [RW 3] The source that is associated with arbitration element 1. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~csem_registers_arb_element0.arb_element0 */ +#define CSEM_REG_ARB_ELEMENT1 0x200024 +/* [RW 3] The source that is associated with arbitration element 2. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~csem_registers_arb_element0.arb_element0 + and ~csem_registers_arb_element1.arb_element1 */ +#define CSEM_REG_ARB_ELEMENT2 0x200028 +/* [RW 3] The source that is associated with arbitration element 3. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2.Could + not be equal to register ~csem_registers_arb_element0.arb_element0 and + ~csem_registers_arb_element1.arb_element1 and + ~csem_registers_arb_element2.arb_element2 */ +#define CSEM_REG_ARB_ELEMENT3 0x20002c +/* [RW 3] The source that is associated with arbitration element 4. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~csem_registers_arb_element0.arb_element0 + and ~csem_registers_arb_element1.arb_element1 and + ~csem_registers_arb_element2.arb_element2 and + ~csem_registers_arb_element3.arb_element3 */ +#define CSEM_REG_ARB_ELEMENT4 0x200030 +/* [RW 32] Interrupt mask register #0 read/write */ +#define CSEM_REG_CSEM_INT_MASK_0 0x200110 +#define CSEM_REG_CSEM_INT_MASK_1 0x200120 +/* [R 32] Interrupt register #0 read */ +#define CSEM_REG_CSEM_INT_STS_0 0x200104 +#define CSEM_REG_CSEM_INT_STS_1 0x200114 +/* [RW 32] Parity mask register #0 read/write */ +#define CSEM_REG_CSEM_PRTY_MASK_0 0x200130 +#define CSEM_REG_CSEM_PRTY_MASK_1 0x200140 +/* [R 32] Parity register #0 read */ +#define CSEM_REG_CSEM_PRTY_STS_0 0x200124 +#define CSEM_REG_CSEM_PRTY_STS_1 0x200134 +/* [RC 32] Parity register #0 read clear */ +#define CSEM_REG_CSEM_PRTY_STS_CLR_0 0x200128 +#define CSEM_REG_CSEM_PRTY_STS_CLR_1 0x200138 +#define CSEM_REG_ENABLE_IN 0x2000a4 +#define CSEM_REG_ENABLE_OUT 0x2000a8 +/* [RW 32] This address space contains all registers and memories that are + placed in SEM_FAST block. The SEM_FAST registers are described in + appendix B. In order to access the sem_fast registers the base address + ~fast_memory.fast_memory should be added to eachsem_fast register offset. */ +#define CSEM_REG_FAST_MEMORY 0x220000 +/* [RW 1] Disables input messages from FIC0 May be updated during run_time + by the microcode */ +#define CSEM_REG_FIC0_DISABLE 0x200224 +/* [RW 1] Disables input messages from FIC1 May be updated during run_time + by the microcode */ +#define CSEM_REG_FIC1_DISABLE 0x200234 +/* [RW 15] Interrupt table Read and write access to it is not possible in + the middle of the work */ +#define CSEM_REG_INT_TABLE 0x200400 +/* [ST 24] Statistics register. The number of messages that entered through + FIC0 */ +#define CSEM_REG_MSG_NUM_FIC0 0x200000 +/* [ST 24] Statistics register. The number of messages that entered through + FIC1 */ +#define CSEM_REG_MSG_NUM_FIC1 0x200004 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC0 */ +#define CSEM_REG_MSG_NUM_FOC0 0x200008 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC1 */ +#define CSEM_REG_MSG_NUM_FOC1 0x20000c +/* [ST 24] Statistics register. The number of messages that were sent to + FOC2 */ +#define CSEM_REG_MSG_NUM_FOC2 0x200010 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC3 */ +#define CSEM_REG_MSG_NUM_FOC3 0x200014 +/* [RW 1] Disables input messages from the passive buffer May be updated + during run_time by the microcode */ +#define CSEM_REG_PAS_DISABLE 0x20024c +/* [WB 128] Debug only. Passive buffer memory */ +#define CSEM_REG_PASSIVE_BUFFER 0x202000 +/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */ +#define CSEM_REG_PRAM 0x240000 +/* [R 16] Valid sleeping threads indication have bit per thread */ +#define CSEM_REG_SLEEP_THREADS_VALID 0x20026c +/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */ +#define CSEM_REG_SLOW_EXT_STORE_EMPTY 0x2002a0 +/* [RW 16] List of free threads . There is a bit per thread. */ +#define CSEM_REG_THREADS_LIST 0x2002e4 +/* [RW 3] The arbitration scheme of time_slot 0 */ +#define CSEM_REG_TS_0_AS 0x200038 +/* [RW 3] The arbitration scheme of time_slot 10 */ +#define CSEM_REG_TS_10_AS 0x200060 +/* [RW 3] The arbitration scheme of time_slot 11 */ +#define CSEM_REG_TS_11_AS 0x200064 +/* [RW 3] The arbitration scheme of time_slot 12 */ +#define CSEM_REG_TS_12_AS 0x200068 +/* [RW 3] The arbitration scheme of time_slot 13 */ +#define CSEM_REG_TS_13_AS 0x20006c +/* [RW 3] The arbitration scheme of time_slot 14 */ +#define CSEM_REG_TS_14_AS 0x200070 +/* [RW 3] The arbitration scheme of time_slot 15 */ +#define CSEM_REG_TS_15_AS 0x200074 +/* [RW 3] The arbitration scheme of time_slot 16 */ +#define CSEM_REG_TS_16_AS 0x200078 +/* [RW 3] The arbitration scheme of time_slot 17 */ +#define CSEM_REG_TS_17_AS 0x20007c +/* [RW 3] The arbitration scheme of time_slot 18 */ +#define CSEM_REG_TS_18_AS 0x200080 +/* [RW 3] The arbitration scheme of time_slot 1 */ +#define CSEM_REG_TS_1_AS 0x20003c +/* [RW 3] The arbitration scheme of time_slot 2 */ +#define CSEM_REG_TS_2_AS 0x200040 +/* [RW 3] The arbitration scheme of time_slot 3 */ +#define CSEM_REG_TS_3_AS 0x200044 +/* [RW 3] The arbitration scheme of time_slot 4 */ +#define CSEM_REG_TS_4_AS 0x200048 +/* [RW 3] The arbitration scheme of time_slot 5 */ +#define CSEM_REG_TS_5_AS 0x20004c +/* [RW 3] The arbitration scheme of time_slot 6 */ +#define CSEM_REG_TS_6_AS 0x200050 +/* [RW 3] The arbitration scheme of time_slot 7 */ +#define CSEM_REG_TS_7_AS 0x200054 +/* [RW 3] The arbitration scheme of time_slot 8 */ +#define CSEM_REG_TS_8_AS 0x200058 +/* [RW 3] The arbitration scheme of time_slot 9 */ +#define CSEM_REG_TS_9_AS 0x20005c +/* [W 7] VF or PF ID for reset error bit. Values 0-63 reset error bit for 64 + * VF; values 64-67 reset error for 4 PF; values 68-127 are not valid. */ +#define CSEM_REG_VFPF_ERR_NUM 0x200380 +/* [RW 1] Parity mask register #0 read/write */ +#define DBG_REG_DBG_PRTY_MASK 0xc0a8 +/* [R 1] Parity register #0 read */ +#define DBG_REG_DBG_PRTY_STS 0xc09c +/* [RC 1] Parity register #0 read clear */ +#define DBG_REG_DBG_PRTY_STS_CLR 0xc0a0 +/* [RW 1] When set the DMAE will process the commands as in E1.5. 1.The + * function that is used is always SRC-PCI; 2.VF_Valid = 0; 3.VFID=0; + * 4.Completion function=0; 5.Error handling=0 */ +#define DMAE_REG_BACKWARD_COMP_EN 0x10207c +/* [RW 32] Commands memory. The address to command X; row Y is to calculated + as 14*X+Y. */ +#define DMAE_REG_CMD_MEM 0x102400 +#define DMAE_REG_CMD_MEM_SIZE 224 +/* [RW 1] If 0 - the CRC-16c initial value is all zeroes; if 1 - the CRC-16c + initial value is all ones. */ +#define DMAE_REG_CRC16C_INIT 0x10201c +/* [RW 1] If 0 - the CRC-16 T10 initial value is all zeroes; if 1 - the + CRC-16 T10 initial value is all ones. */ +#define DMAE_REG_CRC16T10_INIT 0x102020 +/* [RW 2] Interrupt mask register #0 read/write */ +#define DMAE_REG_DMAE_INT_MASK 0x102054 +/* [RW 4] Parity mask register #0 read/write */ +#define DMAE_REG_DMAE_PRTY_MASK 0x102064 +/* [R 4] Parity register #0 read */ +#define DMAE_REG_DMAE_PRTY_STS 0x102058 +/* [RC 4] Parity register #0 read clear */ +#define DMAE_REG_DMAE_PRTY_STS_CLR 0x10205c +/* [RW 1] Command 0 go. */ +#define DMAE_REG_GO_C0 0x102080 +/* [RW 1] Command 1 go. */ +#define DMAE_REG_GO_C1 0x102084 +/* [RW 1] Command 10 go. */ +#define DMAE_REG_GO_C10 0x102088 +/* [RW 1] Command 11 go. */ +#define DMAE_REG_GO_C11 0x10208c +/* [RW 1] Command 12 go. */ +#define DMAE_REG_GO_C12 0x102090 +/* [RW 1] Command 13 go. */ +#define DMAE_REG_GO_C13 0x102094 +/* [RW 1] Command 14 go. */ +#define DMAE_REG_GO_C14 0x102098 +/* [RW 1] Command 15 go. */ +#define DMAE_REG_GO_C15 0x10209c +/* [RW 1] Command 2 go. */ +#define DMAE_REG_GO_C2 0x1020a0 +/* [RW 1] Command 3 go. */ +#define DMAE_REG_GO_C3 0x1020a4 +/* [RW 1] Command 4 go. */ +#define DMAE_REG_GO_C4 0x1020a8 +/* [RW 1] Command 5 go. */ +#define DMAE_REG_GO_C5 0x1020ac +/* [RW 1] Command 6 go. */ +#define DMAE_REG_GO_C6 0x1020b0 +/* [RW 1] Command 7 go. */ +#define DMAE_REG_GO_C7 0x1020b4 +/* [RW 1] Command 8 go. */ +#define DMAE_REG_GO_C8 0x1020b8 +/* [RW 1] Command 9 go. */ +#define DMAE_REG_GO_C9 0x1020bc +/* [RW 1] DMAE GRC Interface (Target; aster) enable. If 0 - the acknowledge + input is disregarded; valid is deasserted; all other signals are treated + as usual; if 1 - normal activity. */ +#define DMAE_REG_GRC_IFEN 0x102008 +/* [RW 1] DMAE PCI Interface (Request; ead; rite) enable. If 0 - the + acknowledge input is disregarded; valid is deasserted; full is asserted; + all other signals are treated as usual; if 1 - normal activity. */ +#define DMAE_REG_PCI_IFEN 0x102004 +/* [RW 4] DMAE- PCI Request Interface initial credit. Write writes the + initial value to the credit counter; related to the address. Read returns + the current value of the counter. */ +#define DMAE_REG_PXP_REQ_INIT_CRD 0x1020c0 +/* [RW 8] Aggregation command. */ +#define DORQ_REG_AGG_CMD0 0x170060 +/* [RW 8] Aggregation command. */ +#define DORQ_REG_AGG_CMD1 0x170064 +/* [RW 8] Aggregation command. */ +#define DORQ_REG_AGG_CMD2 0x170068 +/* [RW 8] Aggregation command. */ +#define DORQ_REG_AGG_CMD3 0x17006c +/* [RW 28] UCM Header. */ +#define DORQ_REG_CMHEAD_RX 0x170050 +/* [RW 32] Doorbell address for RBC doorbells (function 0). */ +#define DORQ_REG_DB_ADDR0 0x17008c +/* [RW 5] Interrupt mask register #0 read/write */ +#define DORQ_REG_DORQ_INT_MASK 0x170180 +/* [R 5] Interrupt register #0 read */ +#define DORQ_REG_DORQ_INT_STS 0x170174 +/* [RC 5] Interrupt register #0 read clear */ +#define DORQ_REG_DORQ_INT_STS_CLR 0x170178 +/* [RW 2] Parity mask register #0 read/write */ +#define DORQ_REG_DORQ_PRTY_MASK 0x170190 +/* [R 2] Parity register #0 read */ +#define DORQ_REG_DORQ_PRTY_STS 0x170184 +/* [RC 2] Parity register #0 read clear */ +#define DORQ_REG_DORQ_PRTY_STS_CLR 0x170188 +/* [RW 8] The address to write the DPM CID to STORM. */ +#define DORQ_REG_DPM_CID_ADDR 0x170044 +/* [RW 5] The DPM mode CID extraction offset. */ +#define DORQ_REG_DPM_CID_OFST 0x170030 +/* [RW 12] The threshold of the DQ FIFO to send the almost full interrupt. */ +#define DORQ_REG_DQ_FIFO_AFULL_TH 0x17007c +/* [RW 12] The threshold of the DQ FIFO to send the full interrupt. */ +#define DORQ_REG_DQ_FIFO_FULL_TH 0x170078 +/* [R 13] Current value of the DQ FIFO fill level according to following + pointer. The range is 0 - 256 FIFO rows; where each row stands for the + doorbell. */ +#define DORQ_REG_DQ_FILL_LVLF 0x1700a4 +/* [R 1] DQ FIFO full status. Is set; when FIFO filling level is more or + equal to full threshold; reset on full clear. */ +#define DORQ_REG_DQ_FULL_ST 0x1700c0 +/* [RW 28] The value sent to CM header in the case of CFC load error. */ +#define DORQ_REG_ERR_CMHEAD 0x170058 +#define DORQ_REG_IF_EN 0x170004 +#define DORQ_REG_MODE_ACT 0x170008 +/* [RW 5] The normal mode CID extraction offset. */ +#define DORQ_REG_NORM_CID_OFST 0x17002c +/* [RW 28] TCM Header when only TCP context is loaded. */ +#define DORQ_REG_NORM_CMHEAD_TX 0x17004c +/* [RW 3] The number of simultaneous outstanding requests to Context Fetch + Interface. */ +#define DORQ_REG_OUTST_REQ 0x17003c +#define DORQ_REG_PF_USAGE_CNT 0x1701d0 +#define DORQ_REG_REGN 0x170038 +/* [R 4] Current value of response A counter credit. Initial credit is + configured through write to ~dorq_registers_rsp_init_crd.rsp_init_crd + register. */ +#define DORQ_REG_RSPA_CRD_CNT 0x1700ac +/* [R 4] Current value of response B counter credit. Initial credit is + configured through write to ~dorq_registers_rsp_init_crd.rsp_init_crd + register. */ +#define DORQ_REG_RSPB_CRD_CNT 0x1700b0 +/* [RW 4] The initial credit at the Doorbell Response Interface. The write + writes the same initial credit to the rspa_crd_cnt and rspb_crd_cnt. The + read reads this written value. */ +#define DORQ_REG_RSP_INIT_CRD 0x170048 +/* [RW 4] Initial activity counter value on the load request; when the + shortcut is done. */ +#define DORQ_REG_SHRT_ACT_CNT 0x170070 +/* [RW 28] TCM Header when both ULP and TCP context is loaded. */ +#define DORQ_REG_SHRT_CMHEAD 0x170054 +#define HC_CONFIG_0_REG_ATTN_BIT_EN_0 (0x1<<4) +#define HC_CONFIG_0_REG_BLOCK_DISABLE_0 (0x1<<0) +#define HC_CONFIG_0_REG_INT_LINE_EN_0 (0x1<<3) +#define HC_CONFIG_0_REG_MSI_ATTN_EN_0 (0x1<<7) +#define HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 (0x1<<2) +#define HC_CONFIG_0_REG_SINGLE_ISR_EN_0 (0x1<<1) +#define HC_CONFIG_1_REG_BLOCK_DISABLE_1 (0x1<<0) +#define HC_REG_AGG_INT_0 0x108050 +#define HC_REG_AGG_INT_1 0x108054 +#define HC_REG_ATTN_BIT 0x108120 +#define HC_REG_ATTN_IDX 0x108100 +#define HC_REG_ATTN_MSG0_ADDR_L 0x108018 +#define HC_REG_ATTN_MSG1_ADDR_L 0x108020 +#define HC_REG_ATTN_NUM_P0 0x108038 +#define HC_REG_ATTN_NUM_P1 0x10803c +#define HC_REG_COMMAND_REG 0x108180 +#define HC_REG_CONFIG_0 0x108000 +#define HC_REG_CONFIG_1 0x108004 +#define HC_REG_FUNC_NUM_P0 0x1080ac +#define HC_REG_FUNC_NUM_P1 0x1080b0 +/* [RW 3] Parity mask register #0 read/write */ +#define HC_REG_HC_PRTY_MASK 0x1080a0 +/* [R 3] Parity register #0 read */ +#define HC_REG_HC_PRTY_STS 0x108094 +/* [RC 3] Parity register #0 read clear */ +#define HC_REG_HC_PRTY_STS_CLR 0x108098 +#define HC_REG_INT_MASK 0x108108 +#define HC_REG_LEADING_EDGE_0 0x108040 +#define HC_REG_LEADING_EDGE_1 0x108048 +#define HC_REG_MAIN_MEMORY 0x108800 +#define HC_REG_MAIN_MEMORY_SIZE 152 +#define HC_REG_P0_PROD_CONS 0x108200 +#define HC_REG_P1_PROD_CONS 0x108400 +#define HC_REG_PBA_COMMAND 0x108140 +#define HC_REG_PCI_CONFIG_0 0x108010 +#define HC_REG_PCI_CONFIG_1 0x108014 +#define HC_REG_STATISTIC_COUNTERS 0x109000 +#define HC_REG_TRAILING_EDGE_0 0x108044 +#define HC_REG_TRAILING_EDGE_1 0x10804c +#define HC_REG_UC_RAM_ADDR_0 0x108028 +#define HC_REG_UC_RAM_ADDR_1 0x108030 +#define HC_REG_USTORM_ADDR_FOR_COALESCE 0x108068 +#define HC_REG_VQID_0 0x108008 +#define HC_REG_VQID_1 0x10800c +#define IGU_BLOCK_CONFIGURATION_REG_BACKWARD_COMP_EN (0x1<<1) +#define IGU_BLOCK_CONFIGURATION_REG_BLOCK_ENABLE (0x1<<0) +#define IGU_REG_ATTENTION_ACK_BITS 0x130108 +/* [R 4] Debug: attn_fsm */ +#define IGU_REG_ATTN_FSM 0x130054 +#define IGU_REG_ATTN_MSG_ADDR_H 0x13011c +#define IGU_REG_ATTN_MSG_ADDR_L 0x130120 +/* [R 4] Debug: [3] - attention write done message is pending (0-no pending; + * 1-pending). [2:0] = PFID. Pending means attention message was sent; but + * write done didn't receive. */ +#define IGU_REG_ATTN_WRITE_DONE_PENDING 0x130030 +#define IGU_REG_BLOCK_CONFIGURATION 0x130000 +#define IGU_REG_COMMAND_REG_32LSB_DATA 0x130124 +#define IGU_REG_COMMAND_REG_CTRL 0x13012c +/* [WB_R 32] Cleanup bit status per SB. 1 = cleanup is set. 0 = cleanup bit + * is clear. The bits in this registers are set and clear via the producer + * command. Data valid only in addresses 0-4. all the rest are zero. */ +#define IGU_REG_CSTORM_TYPE_0_SB_CLEANUP 0x130200 +/* [R 5] Debug: ctrl_fsm */ +#define IGU_REG_CTRL_FSM 0x130064 +/* [R 1] data available for error memory. If this bit is clear do not red + * from error_handling_memory. */ +#define IGU_REG_ERROR_HANDLING_DATA_VALID 0x130130 +/* [RW 11] Parity mask register #0 read/write */ +#define IGU_REG_IGU_PRTY_MASK 0x1300a8 +/* [R 11] Parity register #0 read */ +#define IGU_REG_IGU_PRTY_STS 0x13009c +/* [RC 11] Parity register #0 read clear */ +#define IGU_REG_IGU_PRTY_STS_CLR 0x1300a0 +/* [R 4] Debug: int_handle_fsm */ +#define IGU_REG_INT_HANDLE_FSM 0x130050 +#define IGU_REG_LEADING_EDGE_LATCH 0x130134 +/* [RW 14] mapping CAM; relevant for E2 operating mode only. [0] - valid. + * [6:1] - vector number; [13:7] - FID (if VF - [13] = 0; [12:7] = VF + * number; if PF - [13] = 1; [12:10] = 0; [9:7] = PF number); */ +#define IGU_REG_MAPPING_MEMORY 0x131000 +#define IGU_REG_MAPPING_MEMORY_SIZE 136 +#define IGU_REG_PBA_STATUS_LSB 0x130138 +#define IGU_REG_PBA_STATUS_MSB 0x13013c +#define IGU_REG_PCI_PF_MSI_EN 0x130140 +#define IGU_REG_PCI_PF_MSIX_EN 0x130144 +#define IGU_REG_PCI_PF_MSIX_FUNC_MASK 0x130148 +/* [WB_R 32] Each bit represent the pending bits status for that SB. 0 = no + * pending; 1 = pending. Pendings means interrupt was asserted; and write + * done was not received. Data valid only in addresses 0-4. all the rest are + * zero. */ +#define IGU_REG_PENDING_BITS_STATUS 0x130300 +#define IGU_REG_PF_CONFIGURATION 0x130154 +/* [RW 20] producers only. E2 mode: address 0-135 match to the mapping + * memory; 136 - PF0 default prod; 137 PF1 default prod; 138 - PF2 default + * prod; 139 PF3 default prod; 140 - PF0 - ATTN prod; 141 - PF1 - ATTN prod; + * 142 - PF2 - ATTN prod; 143 - PF3 - ATTN prod; 144-147 reserved. E1.5 mode + * - In backward compatible mode; for non default SB; each even line in the + * memory holds the U producer and each odd line hold the C producer. The + * first 128 producer are for NDSB (PF0 - 0-31; PF1 - 32-63 and so on). The + * last 20 producers are for the DSB for each PF. each PF has five segments + * (the order inside each segment is PF0; PF1; PF2; PF3) - 128-131 U prods; + * 132-135 C prods; 136-139 X prods; 140-143 T prods; 144-147 ATTN prods; */ +#define IGU_REG_PROD_CONS_MEMORY 0x132000 +/* [R 3] Debug: pxp_arb_fsm */ +#define IGU_REG_PXP_ARB_FSM 0x130068 +/* [RW 6] Write one for each bit will reset the appropriate memory. When the + * memory reset finished the appropriate bit will be clear. Bit 0 - mapping + * memory; Bit 1 - SB memory; Bit 2 - SB interrupt and mask register; Bit 3 + * - MSIX memory; Bit 4 - PBA memory; Bit 5 - statistics; */ +#define IGU_REG_RESET_MEMORIES 0x130158 +/* [R 4] Debug: sb_ctrl_fsm */ +#define IGU_REG_SB_CTRL_FSM 0x13004c +#define IGU_REG_SB_INT_BEFORE_MASK_LSB 0x13015c +#define IGU_REG_SB_INT_BEFORE_MASK_MSB 0x130160 +#define IGU_REG_SB_MASK_LSB 0x130164 +#define IGU_REG_SB_MASK_MSB 0x130168 +/* [RW 16] Number of command that were dropped without causing an interrupt + * due to: read access for WO BAR address; or write access for RO BAR + * address or any access for reserved address or PCI function error is set + * and address is not MSIX; PBA or cleanup */ +#define IGU_REG_SILENT_DROP 0x13016c +/* [RW 10] Number of MSI/MSIX/ATTN messages sent for the function: 0-63 - + * number of MSIX messages per VF; 64-67 - number of MSI/MSIX messages per + * PF; 68-71 number of ATTN messages per PF */ +#define IGU_REG_STATISTIC_NUM_MESSAGE_SENT 0x130800 +/* [RW 32] Number of cycles the timer mask masking the IGU interrupt when a + * timer mask command arrives. Value must be bigger than 100. */ +#define IGU_REG_TIMER_MASKING_VALUE 0x13003c +#define IGU_REG_TRAILING_EDGE_LATCH 0x130104 +#define IGU_REG_VF_CONFIGURATION 0x130170 +/* [WB_R 32] Each bit represent write done pending bits status for that SB + * (MSI/MSIX message was sent and write done was not received yet). 0 = + * clear; 1 = set. Data valid only in addresses 0-4. all the rest are zero. */ +#define IGU_REG_WRITE_DONE_PENDING 0x130480 +#define MCP_A_REG_MCPR_SCRATCH 0x3a0000 +#define MCP_REG_MCPR_CPU_PROGRAM_COUNTER 0x8501c +#define MCP_REG_MCPR_GP_INPUTS 0x800c0 +#define MCP_REG_MCPR_GP_OENABLE 0x800c8 +#define MCP_REG_MCPR_GP_OUTPUTS 0x800c4 +#define MCP_REG_MCPR_IMC_COMMAND 0x85900 +#define MCP_REG_MCPR_IMC_DATAREG0 0x85920 +#define MCP_REG_MCPR_IMC_SLAVE_CONTROL 0x85904 +#define MCP_REG_MCPR_CPU_PROGRAM_COUNTER 0x8501c +#define MCP_REG_MCPR_NVM_ACCESS_ENABLE 0x86424 +#define MCP_REG_MCPR_NVM_ADDR 0x8640c +#define MCP_REG_MCPR_NVM_CFG4 0x8642c +#define MCP_REG_MCPR_NVM_COMMAND 0x86400 +#define MCP_REG_MCPR_NVM_READ 0x86410 +#define MCP_REG_MCPR_NVM_SW_ARB 0x86420 +#define MCP_REG_MCPR_NVM_WRITE 0x86408 +#define MCP_REG_MCPR_SCRATCH 0xa0000 +#define MISC_AEU_GENERAL_MASK_REG_AEU_NIG_CLOSE_MASK (0x1<<1) +#define MISC_AEU_GENERAL_MASK_REG_AEU_PXP_CLOSE_MASK (0x1<<0) +/* [R 32] read first 32 bit after inversion of function 0. mapped as + follows: [0] NIG attention for function0; [1] NIG attention for + function1; [2] GPIO1 mcp; [3] GPIO2 mcp; [4] GPIO3 mcp; [5] GPIO4 mcp; + [6] GPIO1 function 1; [7] GPIO2 function 1; [8] GPIO3 function 1; [9] + GPIO4 function 1; [10] PCIE glue/PXP VPD event function0; [11] PCIE + glue/PXP VPD event function1; [12] PCIE glue/PXP Expansion ROM event0; + [13] PCIE glue/PXP Expansion ROM event1; [14] SPIO4; [15] SPIO5; [16] + MSI/X indication for mcp; [17] MSI/X indication for function 1; [18] BRB + Parity error; [19] BRB Hw interrupt; [20] PRS Parity error; [21] PRS Hw + interrupt; [22] SRC Parity error; [23] SRC Hw interrupt; [24] TSDM Parity + error; [25] TSDM Hw interrupt; [26] TCM Parity error; [27] TCM Hw + interrupt; [28] TSEMI Parity error; [29] TSEMI Hw interrupt; [30] PBF + Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_AFTER_INVERT_1_FUNC_0 0xa42c +#define MISC_REG_AEU_AFTER_INVERT_1_FUNC_1 0xa430 +/* [R 32] read first 32 bit after inversion of mcp. mapped as follows: [0] + NIG attention for function0; [1] NIG attention for function1; [2] GPIO1 + mcp; [3] GPIO2 mcp; [4] GPIO3 mcp; [5] GPIO4 mcp; [6] GPIO1 function 1; + [7] GPIO2 function 1; [8] GPIO3 function 1; [9] GPIO4 function 1; [10] + PCIE glue/PXP VPD event function0; [11] PCIE glue/PXP VPD event + function1; [12] PCIE glue/PXP Expansion ROM event0; [13] PCIE glue/PXP + Expansion ROM event1; [14] SPIO4; [15] SPIO5; [16] MSI/X indication for + mcp; [17] MSI/X indication for function 1; [18] BRB Parity error; [19] + BRB Hw interrupt; [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC + Parity error; [23] SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw + interrupt; [26] TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI + Parity error; [29] TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw + interrupt; */ +#define MISC_REG_AEU_AFTER_INVERT_1_MCP 0xa434 +/* [R 32] read second 32 bit after inversion of function 0. mapped as + follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM + Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw + interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity + error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw + interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] + NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; + [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw + interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM + Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI + Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM + Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw + interrupt; */ +#define MISC_REG_AEU_AFTER_INVERT_2_FUNC_0 0xa438 +#define MISC_REG_AEU_AFTER_INVERT_2_FUNC_1 0xa43c +/* [R 32] read second 32 bit after inversion of mcp. mapped as follows: [0] + PBClient Parity error; [1] PBClient Hw interrupt; [2] QM Parity error; + [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw interrupt; + [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity error; [9] + XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw interrupt; [12] + DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] NIG Parity + error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; [17] Vaux + PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw interrupt; + [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM Parity error; + [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI Hw interrupt; + [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM Parity error; + [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw interrupt; */ +#define MISC_REG_AEU_AFTER_INVERT_2_MCP 0xa440 +/* [R 32] read third 32 bit after inversion of function 0. mapped as + follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP Parity + error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error; [5] + PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw + interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity + error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) + Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16] + pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20] + MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23] + SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW + timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 + func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General + attn1; */ +#define MISC_REG_AEU_AFTER_INVERT_3_FUNC_0 0xa444 +#define MISC_REG_AEU_AFTER_INVERT_3_FUNC_1 0xa448 +/* [R 32] read third 32 bit after inversion of mcp. mapped as follows: [0] + CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP Parity error; [3] PXP + Hw interrupt; [4] PXPpciClockClient Parity error; [5] PXPpciClockClient + Hw interrupt; [6] CFC Parity error; [7] CFC Hw interrupt; [8] CDU Parity + error; [9] CDU Hw interrupt; [10] DMAE Parity error; [11] DMAE Hw + interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) Hw interrupt; [14] + MISC Parity error; [15] MISC Hw interrupt; [16] pxp_misc_mps_attn; [17] + Flash event; [18] SMB event; [19] MCP attn0; [20] MCP attn1; [21] SW + timers attn_1 func0; [22] SW timers attn_2 func0; [23] SW timers attn_3 + func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW timers attn_1 + func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 func1; [29] SW + timers attn_4 func1; [30] General attn0; [31] General attn1; */ +#define MISC_REG_AEU_AFTER_INVERT_3_MCP 0xa44c +/* [R 32] read fourth 32 bit after inversion of function 0. mapped as + follows: [0] General attn2; [1] General attn3; [2] General attn4; [3] + General attn5; [4] General attn6; [5] General attn7; [6] General attn8; + [7] General attn9; [8] General attn10; [9] General attn11; [10] General + attn12; [11] General attn13; [12] General attn14; [13] General attn15; + [14] General attn16; [15] General attn17; [16] General attn18; [17] + General attn19; [18] General attn20; [19] General attn21; [20] Main power + interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN + Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC + Latched timeout attention; [27] GRC Latched reserved access attention; + [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP + Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ +#define MISC_REG_AEU_AFTER_INVERT_4_FUNC_0 0xa450 +#define MISC_REG_AEU_AFTER_INVERT_4_FUNC_1 0xa454 +/* [R 32] read fourth 32 bit after inversion of mcp. mapped as follows: [0] + General attn2; [1] General attn3; [2] General attn4; [3] General attn5; + [4] General attn6; [5] General attn7; [6] General attn8; [7] General + attn9; [8] General attn10; [9] General attn11; [10] General attn12; [11] + General attn13; [12] General attn14; [13] General attn15; [14] General + attn16; [15] General attn17; [16] General attn18; [17] General attn19; + [18] General attn20; [19] General attn21; [20] Main power interrupt; [21] + RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN Latched attn; [24] + RBCU Latched attn; [25] RBCP Latched attn; [26] GRC Latched timeout + attention; [27] GRC Latched reserved access attention; [28] MCP Latched + rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP Latched + ump_tx_parity; [31] MCP Latched scpad_parity; */ +#define MISC_REG_AEU_AFTER_INVERT_4_MCP 0xa458 +/* [R 32] Read fifth 32 bit after inversion of function 0. Mapped as + * follows: [0] PGLUE config_space; [1] PGLUE misc_flr; [2] PGLUE B RBC + * attention [3] PGLUE B RBC parity; [4] ATC attention; [5] ATC parity; [6] + * CNIG attention (reserved); [7] CNIG parity (reserved); [31-8] Reserved; */ +#define MISC_REG_AEU_AFTER_INVERT_5_FUNC_0 0xa700 +/* [W 14] write to this register results with the clear of the latched + signals; one in d0 clears RBCR latch; one in d1 clears RBCT latch; one in + d2 clears RBCN latch; one in d3 clears RBCU latch; one in d4 clears RBCP + latch; one in d5 clears GRC Latched timeout attention; one in d6 clears + GRC Latched reserved access attention; one in d7 clears Latched + rom_parity; one in d8 clears Latched ump_rx_parity; one in d9 clears + Latched ump_tx_parity; one in d10 clears Latched scpad_parity (both + ports); one in d11 clears pxpv_misc_mps_attn; one in d12 clears + pxp_misc_exp_rom_attn0; one in d13 clears pxp_misc_exp_rom_attn1; read + from this register return zero */ +#define MISC_REG_AEU_CLR_LATCH_SIGNAL 0xa45c +/* [RW 32] first 32b for enabling the output for function 0 output0. mapped + as follows: [0] NIG attention for function0; [1] NIG attention for + function1; [2] GPIO1 function 0; [3] GPIO2 function 0; [4] GPIO3 function + 0; [5] GPIO4 function 0; [6] GPIO1 function 1; [7] GPIO2 function 1; [8] + GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event + function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP + Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14] + SPIO4; [15] SPIO5; [16] MSI/X indication for function 0; [17] MSI/X + indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt; + [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23] + SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26] + TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29] + TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0 0xa06c +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_1 0xa07c +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_2 0xa08c +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_3 0xa09c +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_5 0xa0bc +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_6 0xa0cc +#define MISC_REG_AEU_ENABLE1_FUNC_0_OUT_7 0xa0dc +/* [RW 32] first 32b for enabling the output for function 1 output0. mapped + as follows: [0] NIG attention for function0; [1] NIG attention for + function1; [2] GPIO1 function 1; [3] GPIO2 function 1; [4] GPIO3 function + 1; [5] GPIO4 function 1; [6] GPIO1 function 1; [7] GPIO2 function 1; [8] + GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event + function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP + Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14] + SPIO4; [15] SPIO5; [16] MSI/X indication for function 1; [17] MSI/X + indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt; + [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23] + SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26] + TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29] + TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0 0xa10c +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_1 0xa11c +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_2 0xa12c +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_3 0xa13c +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_5 0xa15c +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_6 0xa16c +#define MISC_REG_AEU_ENABLE1_FUNC_1_OUT_7 0xa17c +/* [RW 32] first 32b for enabling the output for close the gate nig. mapped + as follows: [0] NIG attention for function0; [1] NIG attention for + function1; [2] GPIO1 function 0; [3] GPIO2 function 0; [4] GPIO3 function + 0; [5] GPIO4 function 0; [6] GPIO1 function 1; [7] GPIO2 function 1; [8] + GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event + function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP + Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14] + SPIO4; [15] SPIO5; [16] MSI/X indication for function 0; [17] MSI/X + indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt; + [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23] + SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26] + TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29] + TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_ENABLE1_NIG_0 0xa0ec +#define MISC_REG_AEU_ENABLE1_NIG_1 0xa18c +/* [RW 32] first 32b for enabling the output for close the gate pxp. mapped + as follows: [0] NIG attention for function0; [1] NIG attention for + function1; [2] GPIO1 function 0; [3] GPIO2 function 0; [4] GPIO3 function + 0; [5] GPIO4 function 0; [6] GPIO1 function 1; [7] GPIO2 function 1; [8] + GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event + function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP + Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14] + SPIO4; [15] SPIO5; [16] MSI/X indication for function 0; [17] MSI/X + indication for function 1; [18] BRB Parity error; [19] BRB Hw interrupt; + [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23] + SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26] + TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29] + TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_ENABLE1_PXP_0 0xa0fc +#define MISC_REG_AEU_ENABLE1_PXP_1 0xa19c +/* [RW 32] second 32b for enabling the output for function 0 output0. mapped + as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM + Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw + interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity + error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw + interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] + NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; + [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw + interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM + Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI + Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM + Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw + interrupt; */ +#define MISC_REG_AEU_ENABLE2_FUNC_0_OUT_0 0xa070 +#define MISC_REG_AEU_ENABLE2_FUNC_0_OUT_1 0xa080 +/* [RW 32] second 32b for enabling the output for function 1 output0. mapped + as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM + Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw + interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity + error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw + interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] + NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; + [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw + interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM + Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI + Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM + Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw + interrupt; */ +#define MISC_REG_AEU_ENABLE2_FUNC_1_OUT_0 0xa110 +#define MISC_REG_AEU_ENABLE2_FUNC_1_OUT_1 0xa120 +/* [RW 32] second 32b for enabling the output for close the gate nig. mapped + as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM + Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw + interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity + error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw + interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] + NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; + [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw + interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM + Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI + Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM + Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw + interrupt; */ +#define MISC_REG_AEU_ENABLE2_NIG_0 0xa0f0 +#define MISC_REG_AEU_ENABLE2_NIG_1 0xa190 +/* [RW 32] second 32b for enabling the output for close the gate pxp. mapped + as follows: [0] PBClient Parity error; [1] PBClient Hw interrupt; [2] QM + Parity error; [3] QM Hw interrupt; [4] Timers Parity error; [5] Timers Hw + interrupt; [6] XSDM Parity error; [7] XSDM Hw interrupt; [8] XCM Parity + error; [9] XCM Hw interrupt; [10] XSEMI Parity error; [11] XSEMI Hw + interrupt; [12] DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] + NIG Parity error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; + [17] Vaux PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw + interrupt; [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM + Parity error; [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI + Hw interrupt; [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM + Parity error; [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw + interrupt; */ +#define MISC_REG_AEU_ENABLE2_PXP_0 0xa100 +#define MISC_REG_AEU_ENABLE2_PXP_1 0xa1a0 +/* [RW 32] third 32b for enabling the output for function 0 output0. mapped + as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP + Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error; + [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw + interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity + error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) + Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16] + pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20] + MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23] + SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW + timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 + func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General + attn1; */ +#define MISC_REG_AEU_ENABLE3_FUNC_0_OUT_0 0xa074 +#define MISC_REG_AEU_ENABLE3_FUNC_0_OUT_1 0xa084 +/* [RW 32] third 32b for enabling the output for function 1 output0. mapped + as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP + Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error; + [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw + interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity + error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) + Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16] + pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20] + MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23] + SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW + timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 + func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General + attn1; */ +#define MISC_REG_AEU_ENABLE3_FUNC_1_OUT_0 0xa114 +#define MISC_REG_AEU_ENABLE3_FUNC_1_OUT_1 0xa124 +/* [RW 32] third 32b for enabling the output for close the gate nig. mapped + as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP + Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error; + [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw + interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity + error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) + Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16] + pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20] + MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23] + SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW + timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 + func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General + attn1; */ +#define MISC_REG_AEU_ENABLE3_NIG_0 0xa0f4 +#define MISC_REG_AEU_ENABLE3_NIG_1 0xa194 +/* [RW 32] third 32b for enabling the output for close the gate pxp. mapped + as follows: [0] CSEMI Parity error; [1] CSEMI Hw interrupt; [2] PXP + Parity error; [3] PXP Hw interrupt; [4] PXPpciClockClient Parity error; + [5] PXPpciClockClient Hw interrupt; [6] CFC Parity error; [7] CFC Hw + interrupt; [8] CDU Parity error; [9] CDU Hw interrupt; [10] DMAE Parity + error; [11] DMAE Hw interrupt; [12] IGU (HC) Parity error; [13] IGU (HC) + Hw interrupt; [14] MISC Parity error; [15] MISC Hw interrupt; [16] + pxp_misc_mps_attn; [17] Flash event; [18] SMB event; [19] MCP attn0; [20] + MCP attn1; [21] SW timers attn_1 func0; [22] SW timers attn_2 func0; [23] + SW timers attn_3 func0; [24] SW timers attn_4 func0; [25] PERST; [26] SW + timers attn_1 func1; [27] SW timers attn_2 func1; [28] SW timers attn_3 + func1; [29] SW timers attn_4 func1; [30] General attn0; [31] General + attn1; */ +#define MISC_REG_AEU_ENABLE3_PXP_0 0xa104 +#define MISC_REG_AEU_ENABLE3_PXP_1 0xa1a4 +/* [RW 32] fourth 32b for enabling the output for function 0 output0.mapped + as follows: [0] General attn2; [1] General attn3; [2] General attn4; [3] + General attn5; [4] General attn6; [5] General attn7; [6] General attn8; + [7] General attn9; [8] General attn10; [9] General attn11; [10] General + attn12; [11] General attn13; [12] General attn14; [13] General attn15; + [14] General attn16; [15] General attn17; [16] General attn18; [17] + General attn19; [18] General attn20; [19] General attn21; [20] Main power + interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN + Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC + Latched timeout attention; [27] GRC Latched reserved access attention; + [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP + Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_0 0xa078 +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_2 0xa098 +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_4 0xa0b8 +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_5 0xa0c8 +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_6 0xa0d8 +#define MISC_REG_AEU_ENABLE4_FUNC_0_OUT_7 0xa0e8 +/* [RW 32] fourth 32b for enabling the output for function 1 output0.mapped + as follows: [0] General attn2; [1] General attn3; [2] General attn4; [3] + General attn5; [4] General attn6; [5] General attn7; [6] General attn8; + [7] General attn9; [8] General attn10; [9] General attn11; [10] General + attn12; [11] General attn13; [12] General attn14; [13] General attn15; + [14] General attn16; [15] General attn17; [16] General attn18; [17] + General attn19; [18] General attn20; [19] General attn21; [20] Main power + interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN + Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC + Latched timeout attention; [27] GRC Latched reserved access attention; + [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP + Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_0 0xa118 +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_2 0xa138 +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_4 0xa158 +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_5 0xa168 +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_6 0xa178 +#define MISC_REG_AEU_ENABLE4_FUNC_1_OUT_7 0xa188 +/* [RW 32] fourth 32b for enabling the output for close the gate nig.mapped + as follows: [0] General attn2; [1] General attn3; [2] General attn4; [3] + General attn5; [4] General attn6; [5] General attn7; [6] General attn8; + [7] General attn9; [8] General attn10; [9] General attn11; [10] General + attn12; [11] General attn13; [12] General attn14; [13] General attn15; + [14] General attn16; [15] General attn17; [16] General attn18; [17] + General attn19; [18] General attn20; [19] General attn21; [20] Main power + interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN + Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC + Latched timeout attention; [27] GRC Latched reserved access attention; + [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP + Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ +#define MISC_REG_AEU_ENABLE4_NIG_0 0xa0f8 +#define MISC_REG_AEU_ENABLE4_NIG_1 0xa198 +/* [RW 32] fourth 32b for enabling the output for close the gate pxp.mapped + as follows: [0] General attn2; [1] General attn3; [2] General attn4; [3] + General attn5; [4] General attn6; [5] General attn7; [6] General attn8; + [7] General attn9; [8] General attn10; [9] General attn11; [10] General + attn12; [11] General attn13; [12] General attn14; [13] General attn15; + [14] General attn16; [15] General attn17; [16] General attn18; [17] + General attn19; [18] General attn20; [19] General attn21; [20] Main power + interrupt; [21] RBCR Latched attn; [22] RBCT Latched attn; [23] RBCN + Latched attn; [24] RBCU Latched attn; [25] RBCP Latched attn; [26] GRC + Latched timeout attention; [27] GRC Latched reserved access attention; + [28] MCP Latched rom_parity; [29] MCP Latched ump_rx_parity; [30] MCP + Latched ump_tx_parity; [31] MCP Latched scpad_parity; */ +#define MISC_REG_AEU_ENABLE4_PXP_0 0xa108 +#define MISC_REG_AEU_ENABLE4_PXP_1 0xa1a8 +/* [RW 1] set/clr general attention 0; this will set/clr bit 94 in the aeu + 128 bit vector */ +#define MISC_REG_AEU_GENERAL_ATTN_0 0xa000 +#define MISC_REG_AEU_GENERAL_ATTN_1 0xa004 +#define MISC_REG_AEU_GENERAL_ATTN_10 0xa028 +#define MISC_REG_AEU_GENERAL_ATTN_11 0xa02c +#define MISC_REG_AEU_GENERAL_ATTN_12 0xa030 +#define MISC_REG_AEU_GENERAL_ATTN_2 0xa008 +#define MISC_REG_AEU_GENERAL_ATTN_3 0xa00c +#define MISC_REG_AEU_GENERAL_ATTN_4 0xa010 +#define MISC_REG_AEU_GENERAL_ATTN_5 0xa014 +#define MISC_REG_AEU_GENERAL_ATTN_6 0xa018 +#define MISC_REG_AEU_GENERAL_ATTN_7 0xa01c +#define MISC_REG_AEU_GENERAL_ATTN_8 0xa020 +#define MISC_REG_AEU_GENERAL_ATTN_9 0xa024 +#define MISC_REG_AEU_GENERAL_MASK 0xa61c +/* [RW 32] first 32b for inverting the input for function 0; for each bit: + 0= do not invert; 1= invert; mapped as follows: [0] NIG attention for + function0; [1] NIG attention for function1; [2] GPIO1 mcp; [3] GPIO2 mcp; + [4] GPIO3 mcp; [5] GPIO4 mcp; [6] GPIO1 function 1; [7] GPIO2 function 1; + [8] GPIO3 function 1; [9] GPIO4 function 1; [10] PCIE glue/PXP VPD event + function0; [11] PCIE glue/PXP VPD event function1; [12] PCIE glue/PXP + Expansion ROM event0; [13] PCIE glue/PXP Expansion ROM event1; [14] + SPIO4; [15] SPIO5; [16] MSI/X indication for mcp; [17] MSI/X indication + for function 1; [18] BRB Parity error; [19] BRB Hw interrupt; [20] PRS + Parity error; [21] PRS Hw interrupt; [22] SRC Parity error; [23] SRC Hw + interrupt; [24] TSDM Parity error; [25] TSDM Hw interrupt; [26] TCM + Parity error; [27] TCM Hw interrupt; [28] TSEMI Parity error; [29] TSEMI + Hw interrupt; [30] PBF Parity error; [31] PBF Hw interrupt; */ +#define MISC_REG_AEU_INVERTER_1_FUNC_0 0xa22c +#define MISC_REG_AEU_INVERTER_1_FUNC_1 0xa23c +/* [RW 32] second 32b for inverting the input for function 0; for each bit: + 0= do not invert; 1= invert. mapped as follows: [0] PBClient Parity + error; [1] PBClient Hw interrupt; [2] QM Parity error; [3] QM Hw + interrupt; [4] Timers Parity error; [5] Timers Hw interrupt; [6] XSDM + Parity error; [7] XSDM Hw interrupt; [8] XCM Parity error; [9] XCM Hw + interrupt; [10] XSEMI Parity error; [11] XSEMI Hw interrupt; [12] + DoorbellQ Parity error; [13] DoorbellQ Hw interrupt; [14] NIG Parity + error; [15] NIG Hw interrupt; [16] Vaux PCI core Parity error; [17] Vaux + PCI core Hw interrupt; [18] Debug Parity error; [19] Debug Hw interrupt; + [20] USDM Parity error; [21] USDM Hw interrupt; [22] UCM Parity error; + [23] UCM Hw interrupt; [24] USEMI Parity error; [25] USEMI Hw interrupt; + [26] UPB Parity error; [27] UPB Hw interrupt; [28] CSDM Parity error; + [29] CSDM Hw interrupt; [30] CCM Parity error; [31] CCM Hw interrupt; */ +#define MISC_REG_AEU_INVERTER_2_FUNC_0 0xa230 +#define MISC_REG_AEU_INVERTER_2_FUNC_1 0xa240 +/* [RW 10] [7:0] = mask 8 attention output signals toward IGU function0; + [9:8] = raserved. Zero = mask; one = unmask */ +#define MISC_REG_AEU_MASK_ATTN_FUNC_0 0xa060 +#define MISC_REG_AEU_MASK_ATTN_FUNC_1 0xa064 +/* [RW 1] If set a system kill occurred */ +#define MISC_REG_AEU_SYS_KILL_OCCURRED 0xa610 +/* [RW 32] Represent the status of the input vector to the AEU when a system + kill occurred. The register is reset in por reset. Mapped as follows: [0] + NIG attention for function0; [1] NIG attention for function1; [2] GPIO1 + mcp; [3] GPIO2 mcp; [4] GPIO3 mcp; [5] GPIO4 mcp; [6] GPIO1 function 1; + [7] GPIO2 function 1; [8] GPIO3 function 1; [9] GPIO4 function 1; [10] + PCIE glue/PXP VPD event function0; [11] PCIE glue/PXP VPD event + function1; [12] PCIE glue/PXP Expansion ROM event0; [13] PCIE glue/PXP + Expansion ROM event1; [14] SPIO4; [15] SPIO5; [16] MSI/X indication for + mcp; [17] MSI/X indication for function 1; [18] BRB Parity error; [19] + BRB Hw interrupt; [20] PRS Parity error; [21] PRS Hw interrupt; [22] SRC + Parity error; [23] SRC Hw interrupt; [24] TSDM Parity error; [25] TSDM Hw + interrupt; [26] TCM Parity error; [27] TCM Hw interrupt; [28] TSEMI + Parity error; [29] TSEMI Hw interrupt; [30] PBF Parity error; [31] PBF Hw + interrupt; */ +#define MISC_REG_AEU_SYS_KILL_STATUS_0 0xa600 +#define MISC_REG_AEU_SYS_KILL_STATUS_1 0xa604 +#define MISC_REG_AEU_SYS_KILL_STATUS_2 0xa608 +#define MISC_REG_AEU_SYS_KILL_STATUS_3 0xa60c +/* [R 4] This field indicates the type of the device. '0' - 2 Ports; '1' - 1 + Port. */ +#define MISC_REG_BOND_ID 0xa400 +/* [R 8] These bits indicate the metal revision of the chip. This value + starts at 0x00 for each all-layer tape-out and increments by one for each + tape-out. */ +#define MISC_REG_CHIP_METAL 0xa404 +/* [R 16] These bits indicate the part number for the chip. */ +#define MISC_REG_CHIP_NUM 0xa408 +/* [R 4] These bits indicate the base revision of the chip. This value + starts at 0x0 for the A0 tape-out and increments by one for each + all-layer tape-out. */ +#define MISC_REG_CHIP_REV 0xa40c +/* [RW 32] The following driver registers(1...16) represent 16 drivers and + 32 clients. Each client can be controlled by one driver only. One in each + bit represent that this driver control the appropriate client (Ex: bit 5 + is set means this driver control client number 5). addr1 = set; addr0 = + clear; read from both addresses will give the same result = status. write + to address 1 will set a request to control all the clients that their + appropriate bit (in the write command) is set. if the client is free (the + appropriate bit in all the other drivers is clear) one will be written to + that driver register; if the client isn't free the bit will remain zero. + if the appropriate bit is set (the driver request to gain control on a + client it already controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW + interrupt will be asserted). write to address 0 will set a request to + free all the clients that their appropriate bit (in the write command) is + set. if the appropriate bit is clear (the driver request to free a client + it doesn't controls the ~MISC_REGISTERS_INT_STS.GENERIC_SW interrupt will + be asserted). */ +#define MISC_REG_DRIVER_CONTROL_1 0xa510 +#define MISC_REG_DRIVER_CONTROL_7 0xa3c8 +/* [RW 1] e1hmf for WOL. If clr WOL signal o the PXP will be send on bit 0 + only. */ +#define MISC_REG_E1HMF_MODE 0xa5f8 +/* [R 1] Status of four port mode path swap input pin. */ +#define MISC_REG_FOUR_PORT_PATH_SWAP 0xa75c +/* [RW 2] 4 port path swap overwrite.[0] - Overwrite control; if it is 0 - + the path_swap output is equal to 4 port mode path swap input pin; if it + is 1 - the path_swap output is equal to bit[1] of this register; [1] - + Overwrite value. If bit[0] of this register is 1 this is the value that + receives the path_swap output. Reset on Hard reset. */ +#define MISC_REG_FOUR_PORT_PATH_SWAP_OVWR 0xa738 +/* [R 1] Status of 4 port mode port swap input pin. */ +#define MISC_REG_FOUR_PORT_PORT_SWAP 0xa754 +/* [RW 2] 4 port port swap overwrite.[0] - Overwrite control; if it is 0 - + the port_swap output is equal to 4 port mode port swap input pin; if it + is 1 - the port_swap output is equal to bit[1] of this register; [1] - + Overwrite value. If bit[0] of this register is 1 this is the value that + receives the port_swap output. Reset on Hard reset. */ +#define MISC_REG_FOUR_PORT_PORT_SWAP_OVWR 0xa734 +/* [RW 32] Debug only: spare RW register reset by core reset */ +#define MISC_REG_GENERIC_CR_0 0xa460 +#define MISC_REG_GENERIC_CR_1 0xa464 +/* [RW 32] Debug only: spare RW register reset by por reset */ +#define MISC_REG_GENERIC_POR_1 0xa474 +/* [RW 32] Bit[0]: EPIO MODE SEL: Setting this bit to 1 will allow SW/FW to + use all of the 32 Extended GPIO pins. Without setting this bit; an EPIO + can not be configured as an output. Each output has its output enable in + the MCP register space; but this bit needs to be set to make use of that. + Bit[3:1] spare. Bit[4]: WCVTMON_PWRDN: Powerdown for Warpcore VTMON. When + set to 1 - Powerdown. Bit[5]: WCVTMON_RESETB: Reset for Warpcore VTMON. + When set to 0 - vTMON is in reset. Bit[6]: setting this bit will change + the i/o to an output and will drive the TimeSync output. Bit[31:7]: + spare. Global register. Reset by hard reset. */ +#define MISC_REG_GEN_PURP_HWG 0xa9a0 +/* [RW 32] GPIO. [31-28] FLOAT port 0; [27-24] FLOAT port 0; When any of + these bits is written as a '1'; the corresponding SPIO bit will turn off + it's drivers and become an input. This is the reset state of all GPIO + pins. The read value of these bits will be a '1' if that last command + (#SET; #CLR; or #FLOAT) for this bit was a #FLOAT. (reset value 0xff). + [23-20] CLR port 1; 19-16] CLR port 0; When any of these bits is written + as a '1'; the corresponding GPIO bit will drive low. The read value of + these bits will be a '1' if that last command (#SET; #CLR; or #FLOAT) for + this bit was a #CLR. (reset value 0). [15-12] SET port 1; 11-8] port 0; + SET When any of these bits is written as a '1'; the corresponding GPIO + bit will drive high (if it has that capability). The read value of these + bits will be a '1' if that last command (#SET; #CLR; or #FLOAT) for this + bit was a #SET. (reset value 0). [7-4] VALUE port 1; [3-0] VALUE port 0; + RO; These bits indicate the read value of each of the eight GPIO pins. + This is the result value of the pin; not the drive value. Writing these + bits will have not effect. */ +#define MISC_REG_GPIO 0xa490 +/* [RW 8] These bits enable the GPIO_INTs to signals event to the + IGU/MCP.according to the following map: [0] p0_gpio_0; [1] p0_gpio_1; [2] + p0_gpio_2; [3] p0_gpio_3; [4] p1_gpio_0; [5] p1_gpio_1; [6] p1_gpio_2; + [7] p1_gpio_3; */ +#define MISC_REG_GPIO_EVENT_EN 0xa2bc +/* [RW 32] GPIO INT. [31-28] OLD_CLR port1; [27-24] OLD_CLR port0; Writing a + '1' to these bit clears the corresponding bit in the #OLD_VALUE register. + This will acknowledge an interrupt on the falling edge of corresponding + GPIO input (reset value 0). [23-16] OLD_SET [23-16] port1; OLD_SET port0; + Writing a '1' to these bit sets the corresponding bit in the #OLD_VALUE + register. This will acknowledge an interrupt on the rising edge of + corresponding SPIO input (reset value 0). [15-12] OLD_VALUE [11-8] port1; + OLD_VALUE port0; RO; These bits indicate the old value of the GPIO input + value. When the ~INT_STATE bit is set; this bit indicates the OLD value + of the pin such that if ~INT_STATE is set and this bit is '0'; then the + interrupt is due to a low to high edge. If ~INT_STATE is set and this bit + is '1'; then the interrupt is due to a high to low edge (reset value 0). + [7-4] INT_STATE port1; [3-0] INT_STATE RO port0; These bits indicate the + current GPIO interrupt state for each GPIO pin. This bit is cleared when + the appropriate #OLD_SET or #OLD_CLR command bit is written. This bit is + set when the GPIO input does not match the current value in #OLD_VALUE + (reset value 0). */ +#define MISC_REG_GPIO_INT 0xa494 +/* [R 28] this field hold the last information that caused reserved + attention. bits [19:0] - address; [22:20] function; [23] reserved; + [27:24] the master that caused the attention - according to the following + encodeing:1 = pxp; 2 = mcp; 3 = usdm; 4 = tsdm; 5 = xsdm; 6 = csdm; 7 = + dbu; 8 = dmae */ +#define MISC_REG_GRC_RSV_ATTN 0xa3c0 +/* [R 28] this field hold the last information that caused timeout + attention. bits [19:0] - address; [22:20] function; [23] reserved; + [27:24] the master that caused the attention - according to the following + encodeing:1 = pxp; 2 = mcp; 3 = usdm; 4 = tsdm; 5 = xsdm; 6 = csdm; 7 = + dbu; 8 = dmae */ +#define MISC_REG_GRC_TIMEOUT_ATTN 0xa3c4 +/* [RW 1] Setting this bit enables a timer in the GRC block to timeout any + access that does not finish within + ~misc_registers_grc_timout_val.grc_timeout_val cycles. When this bit is + cleared; this timeout is disabled. If this timeout occurs; the GRC shall + assert it attention output. */ +#define MISC_REG_GRC_TIMEOUT_EN 0xa280 +/* [RW 28] 28 LSB of LCPLL first register; reset val = 521. inside order of + the bits is: [2:0] OAC reset value 001) CML output buffer bias control; + 111 for +40%; 011 for +20%; 001 for 0%; 000 for -20%. [5:3] Icp_ctrl + (reset value 001) Charge pump current control; 111 for 720u; 011 for + 600u; 001 for 480u and 000 for 360u. [7:6] Bias_ctrl (reset value 00) + Global bias control; When bit 7 is high bias current will be 10 0gh; When + bit 6 is high bias will be 100w; Valid values are 00; 10; 01. [10:8] + Pll_observe (reset value 010) Bits to control observability. bit 10 is + for test bias; bit 9 is for test CK; bit 8 is test Vc. [12:11] Vth_ctrl + (reset value 00) Comparator threshold control. 00 for 0.6V; 01 for 0.54V + and 10 for 0.66V. [13] pllSeqStart (reset value 0) Enables VCO tuning + sequencer: 1= sequencer disabled; 0= sequencer enabled (inverted + internally). [14] reserved (reset value 0) Reset for VCO sequencer is + connected to RESET input directly. [15] capRetry_en (reset value 0) + enable retry on cap search failure (inverted). [16] freqMonitor_e (reset + value 0) bit to continuously monitor vco freq (inverted). [17] + freqDetRestart_en (reset value 0) bit to enable restart when not freq + locked (inverted). [18] freqDetRetry_en (reset value 0) bit to enable + retry on freq det failure(inverted). [19] pllForceFdone_en (reset value + 0) bit to enable pllForceFdone & pllForceFpass into pllSeq. [20] + pllForceFdone (reset value 0) bit to force freqDone. [21] pllForceFpass + (reset value 0) bit to force freqPass. [22] pllForceDone_en (reset value + 0) bit to enable pllForceCapDone. [23] pllForceCapDone (reset value 0) + bit to force capDone. [24] pllForceCapPass_en (reset value 0) bit to + enable pllForceCapPass. [25] pllForceCapPass (reset value 0) bit to force + capPass. [26] capRestart (reset value 0) bit to force cap sequencer to + restart. [27] capSelectM_en (reset value 0) bit to enable cap select + register bits. */ +#define MISC_REG_LCPLL_CTRL_1 0xa2a4 +#define MISC_REG_LCPLL_CTRL_REG_2 0xa2a8 +/* [RW 4] Interrupt mask register #0 read/write */ +#define MISC_REG_MISC_INT_MASK 0xa388 +/* [RW 1] Parity mask register #0 read/write */ +#define MISC_REG_MISC_PRTY_MASK 0xa398 +/* [R 1] Parity register #0 read */ +#define MISC_REG_MISC_PRTY_STS 0xa38c +/* [RC 1] Parity register #0 read clear */ +#define MISC_REG_MISC_PRTY_STS_CLR 0xa390 +#define MISC_REG_NIG_WOL_P0 0xa270 +#define MISC_REG_NIG_WOL_P1 0xa274 +/* [R 1] If set indicate that the pcie_rst_b was asserted without perst + assertion */ +#define MISC_REG_PCIE_HOT_RESET 0xa618 +/* [RW 32] 32 LSB of storm PLL first register; reset val = 0x 071d2911. + inside order of the bits is: [0] P1 divider[0] (reset value 1); [1] P1 + divider[1] (reset value 0); [2] P1 divider[2] (reset value 0); [3] P1 + divider[3] (reset value 0); [4] P2 divider[0] (reset value 1); [5] P2 + divider[1] (reset value 0); [6] P2 divider[2] (reset value 0); [7] P2 + divider[3] (reset value 0); [8] ph_det_dis (reset value 1); [9] + freq_det_dis (reset value 0); [10] Icpx[0] (reset value 0); [11] Icpx[1] + (reset value 1); [12] Icpx[2] (reset value 0); [13] Icpx[3] (reset value + 1); [14] Icpx[4] (reset value 0); [15] Icpx[5] (reset value 0); [16] + Rx[0] (reset value 1); [17] Rx[1] (reset value 0); [18] vc_en (reset + value 1); [19] vco_rng[0] (reset value 1); [20] vco_rng[1] (reset value + 1); [21] Kvco_xf[0] (reset value 0); [22] Kvco_xf[1] (reset value 0); + [23] Kvco_xf[2] (reset value 0); [24] Kvco_xs[0] (reset value 1); [25] + Kvco_xs[1] (reset value 1); [26] Kvco_xs[2] (reset value 1); [27] + testd_en (reset value 0); [28] testd_sel[0] (reset value 0); [29] + testd_sel[1] (reset value 0); [30] testd_sel[2] (reset value 0); [31] + testa_en (reset value 0); */ +#define MISC_REG_PLL_STORM_CTRL_1 0xa294 +#define MISC_REG_PLL_STORM_CTRL_2 0xa298 +#define MISC_REG_PLL_STORM_CTRL_3 0xa29c +#define MISC_REG_PLL_STORM_CTRL_4 0xa2a0 +/* [R 1] Status of 4 port mode enable input pin. */ +#define MISC_REG_PORT4MODE_EN 0xa750 +/* [RW 2] 4 port mode enable overwrite.[0] - Overwrite control; if it is 0 - + * the port4mode_en output is equal to 4 port mode input pin; if it is 1 - + * the port4mode_en output is equal to bit[1] of this register; [1] - + * Overwrite value. If bit[0] of this register is 1 this is the value that + * receives the port4mode_en output . */ +#define MISC_REG_PORT4MODE_EN_OVWR 0xa720 +/* [RW 32] reset reg#2; rite/read one = the specific block is out of reset; + write/read zero = the specific block is in reset; addr 0-wr- the write + value will be written to the register; addr 1-set - one will be written + to all the bits that have the value of one in the data written (bits that + have the value of zero will not be change) ; addr 2-clear - zero will be + written to all the bits that have the value of one in the data written + (bits that have the value of zero will not be change); addr 3-ignore; + read ignore from all addr except addr 00; inside order of the bits is: + [0] rst_bmac0; [1] rst_bmac1; [2] rst_emac0; [3] rst_emac1; [4] rst_grc; + [5] rst_mcp_n_reset_reg_hard_core; [6] rst_ mcp_n_hard_core_rst_b; [7] + rst_ mcp_n_reset_cmn_cpu; [8] rst_ mcp_n_reset_cmn_core; [9] rst_rbcn; + [10] rst_dbg; [11] rst_misc_core; [12] rst_dbue (UART); [13] + Pci_resetmdio_n; [14] rst_emac0_hard_core; [15] rst_emac1_hard_core; 16] + rst_pxp_rq_rd_wr; 31:17] reserved */ +#define MISC_REG_RESET_REG_2 0xa590 +/* [RW 20] 20 bit GRC address where the scratch-pad of the MCP that is + shared with the driver resides */ +#define MISC_REG_SHARED_MEM_ADDR 0xa2b4 +/* [RW 32] SPIO. [31-24] FLOAT When any of these bits is written as a '1'; + the corresponding SPIO bit will turn off it's drivers and become an + input. This is the reset state of all SPIO pins. The read value of these + bits will be a '1' if that last command (#SET; #CL; or #FLOAT) for this + bit was a #FLOAT. (reset value 0xff). [23-16] CLR When any of these bits + is written as a '1'; the corresponding SPIO bit will drive low. The read + value of these bits will be a '1' if that last command (#SET; #CLR; or +#FLOAT) for this bit was a #CLR. (reset value 0). [15-8] SET When any of + these bits is written as a '1'; the corresponding SPIO bit will drive + high (if it has that capability). The read value of these bits will be a + '1' if that last command (#SET; #CLR; or #FLOAT) for this bit was a #SET. + (reset value 0). [7-0] VALUE RO; These bits indicate the read value of + each of the eight SPIO pins. This is the result value of the pin; not the + drive value. Writing these bits will have not effect. Each 8 bits field + is divided as follows: [0] VAUX Enable; when pulsed low; enables supply + from VAUX. (This is an output pin only; the FLOAT field is not applicable + for this pin); [1] VAUX Disable; when pulsed low; disables supply form + VAUX. (This is an output pin only; FLOAT field is not applicable for this + pin); [2] SEL_VAUX_B - Control to power switching logic. Drive low to + select VAUX supply. (This is an output pin only; it is not controlled by + the SET and CLR fields; it is controlled by the Main Power SM; the FLOAT + field is not applicable for this pin; only the VALUE fields is relevant - + it reflects the output value); [3] port swap [4] spio_4; [5] spio_5; [6] + Bit 0 of UMP device ID select; read by UMP firmware; [7] Bit 1 of UMP + device ID select; read by UMP firmware. */ +#define MISC_REG_SPIO 0xa4fc +/* [RW 8] These bits enable the SPIO_INTs to signals event to the IGU/MC. + according to the following map: [3:0] reserved; [4] spio_4 [5] spio_5; + [7:0] reserved */ +#define MISC_REG_SPIO_EVENT_EN 0xa2b8 +/* [RW 32] SPIO INT. [31-24] OLD_CLR Writing a '1' to these bit clears the + corresponding bit in the #OLD_VALUE register. This will acknowledge an + interrupt on the falling edge of corresponding SPIO input (reset value + 0). [23-16] OLD_SET Writing a '1' to these bit sets the corresponding bit + in the #OLD_VALUE register. This will acknowledge an interrupt on the + rising edge of corresponding SPIO input (reset value 0). [15-8] OLD_VALUE + RO; These bits indicate the old value of the SPIO input value. When the + ~INT_STATE bit is set; this bit indicates the OLD value of the pin such + that if ~INT_STATE is set and this bit is '0'; then the interrupt is due + to a low to high edge. If ~INT_STATE is set and this bit is '1'; then the + interrupt is due to a high to low edge (reset value 0). [7-0] INT_STATE + RO; These bits indicate the current SPIO interrupt state for each SPIO + pin. This bit is cleared when the appropriate #OLD_SET or #OLD_CLR + command bit is written. This bit is set when the SPIO input does not + match the current value in #OLD_VALUE (reset value 0). */ +#define MISC_REG_SPIO_INT 0xa500 +/* [RW 32] reload value for counter 4 if reload; the value will be reload if + the counter reached zero and the reload bit + (~misc_registers_sw_timer_cfg_4.sw_timer_cfg_4[1] ) is set */ +#define MISC_REG_SW_TIMER_RELOAD_VAL_4 0xa2fc +/* [RW 32] the value of the counter for sw timers1-8. there are 8 addresses + in this register. address 0 - timer 1; address 1 - timer 2, ... address 7 - + timer 8 */ +#define MISC_REG_SW_TIMER_VAL 0xa5c0 +/* [R 1] Status of two port mode path swap input pin. */ +#define MISC_REG_TWO_PORT_PATH_SWAP 0xa758 +/* [RW 2] 2 port swap overwrite.[0] - Overwrite control; if it is 0 - the + path_swap output is equal to 2 port mode path swap input pin; if it is 1 + - the path_swap output is equal to bit[1] of this register; [1] - + Overwrite value. If bit[0] of this register is 1 this is the value that + receives the path_swap output. Reset on Hard reset. */ +#define MISC_REG_TWO_PORT_PATH_SWAP_OVWR 0xa72c +/* [RW 1] Set by the MCP to remember if one or more of the drivers is/are + loaded; 0-prepare; -unprepare */ +#define MISC_REG_UNPREPARED 0xa424 +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST (0x1<<0) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST (0x1<<1) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN (0x1<<4) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST (0x1<<2) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN (0x1<<3) +/* [RW 5] MDIO PHY Address. The WC uses this address to determine whether or + * not it is the recipient of the message on the MDIO interface. The value + * is compared to the value on ctrl_md_devad. Drives output + * misc_xgxs0_phy_addr. Global register. */ +#define MISC_REG_WC0_CTRL_PHY_ADDR 0xa9cc +/* [RW 2] XMAC Core port mode. Indicates the number of ports on the system + side. This should be less than or equal to phy_port_mode; if some of the + ports are not used. This enables reduction of frequency on the core side. + This is a strap input for the XMAC_MP core. 00 - Single Port Mode; 01 - + Dual Port Mode; 10 - Tri Port Mode; 11 - Quad Port Mode. This is a strap + input for the XMAC_MP core; and should be changed only while reset is + held low. Reset on Hard reset. */ +#define MISC_REG_XMAC_CORE_PORT_MODE 0xa964 +/* [RW 2] XMAC PHY port mode. Indicates the number of ports on the Warp + Core. This is a strap input for the XMAC_MP core. 00 - Single Port Mode; + 01 - Dual Port Mode; 1x - Quad Port Mode; This is a strap input for the + XMAC_MP core; and should be changed only while reset is held low. Reset + on Hard reset. */ +#define MISC_REG_XMAC_PHY_PORT_MODE 0xa960 +/* [RW 32] 1 [47] Packet Size = 64 Write to this register write bits 31:0. + * Reads from this register will clear bits 31:0. */ +#define MSTAT_REG_RX_STAT_GR64_LO 0x200 +/* [RW 32] 1 [00] Tx Good Packet Count Write to this register write bits + * 31:0. Reads from this register will clear bits 31:0. */ +#define MSTAT_REG_TX_STAT_GTXPOK_LO 0 +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_BRCST (0x1<<0) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_MLCST (0x1<<1) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_NO_VLAN (0x1<<4) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_UNCST (0x1<<2) +#define NIG_LLH0_BRB1_DRV_MASK_REG_LLH0_BRB1_DRV_MASK_VLAN (0x1<<3) +#define NIG_LLH0_XCM_MASK_REG_LLH0_XCM_MASK_BCN (0x1<<0) +#define NIG_LLH1_XCM_MASK_REG_LLH1_XCM_MASK_BCN (0x1<<0) +#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_EMAC0_MISC_MI_INT (0x1<<0) +#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_SERDES0_LINK_STATUS (0x1<<9) +#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK10G (0x1<<15) +#define NIG_MASK_INTERRUPT_PORT0_REG_MASK_XGXS0_LINK_STATUS (0xf<<18) +/* [RW 1] Input enable for RX_BMAC0 IF */ +#define NIG_REG_BMAC0_IN_EN 0x100ac +/* [RW 1] output enable for TX_BMAC0 IF */ +#define NIG_REG_BMAC0_OUT_EN 0x100e0 +/* [RW 1] output enable for TX BMAC pause port 0 IF */ +#define NIG_REG_BMAC0_PAUSE_OUT_EN 0x10110 +/* [RW 1] output enable for RX_BMAC0_REGS IF */ +#define NIG_REG_BMAC0_REGS_OUT_EN 0x100e8 +/* [RW 1] output enable for RX BRB1 port0 IF */ +#define NIG_REG_BRB0_OUT_EN 0x100f8 +/* [RW 1] Input enable for TX BRB1 pause port 0 IF */ +#define NIG_REG_BRB0_PAUSE_IN_EN 0x100c4 +/* [RW 1] output enable for RX BRB1 port1 IF */ +#define NIG_REG_BRB1_OUT_EN 0x100fc +/* [RW 1] Input enable for TX BRB1 pause port 1 IF */ +#define NIG_REG_BRB1_PAUSE_IN_EN 0x100c8 +/* [RW 1] output enable for RX BRB1 LP IF */ +#define NIG_REG_BRB_LB_OUT_EN 0x10100 +/* [WB_W 82] Debug packet to LP from RBC; Data spelling:[63:0] data; 64] + error; [67:65]eop_bvalid; [68]eop; [69]sop; [70]port_id; 71]flush; + 72:73]-vnic_num; 81:74]-sideband_info */ +#define NIG_REG_DEBUG_PACKET_LB 0x10800 +/* [RW 1] Input enable for TX Debug packet */ +#define NIG_REG_EGRESS_DEBUG_IN_EN 0x100dc +/* [RW 1] If 1 - egress drain mode for port0 is active. In this mode all + packets from PBFare not forwarded to the MAC and just deleted from FIFO. + First packet may be deleted from the middle. And last packet will be + always deleted till the end. */ +#define NIG_REG_EGRESS_DRAIN0_MODE 0x10060 +/* [RW 1] Output enable to EMAC0 */ +#define NIG_REG_EGRESS_EMAC0_OUT_EN 0x10120 +/* [RW 1] MAC configuration for packets of port0. If 1 - all packet outputs + to emac for port0; other way to bmac for port0 */ +#define NIG_REG_EGRESS_EMAC0_PORT 0x10058 +/* [RW 1] Input enable for TX PBF user packet port0 IF */ +#define NIG_REG_EGRESS_PBF0_IN_EN 0x100cc +/* [RW 1] Input enable for TX PBF user packet port1 IF */ +#define NIG_REG_EGRESS_PBF1_IN_EN 0x100d0 +/* [RW 1] Input enable for TX UMP management packet port0 IF */ +#define NIG_REG_EGRESS_UMP0_IN_EN 0x100d4 +/* [RW 1] Input enable for RX_EMAC0 IF */ +#define NIG_REG_EMAC0_IN_EN 0x100a4 +/* [RW 1] output enable for TX EMAC pause port 0 IF */ +#define NIG_REG_EMAC0_PAUSE_OUT_EN 0x10118 +/* [R 1] status from emac0. This bit is set when MDINT from either the + EXT_MDINT pin or from the Copper PHY is driven low. This condition must + be cleared in the attached PHY device that is driving the MINT pin. */ +#define NIG_REG_EMAC0_STATUS_MISC_MI_INT 0x10494 +/* [WB 48] This address space contains BMAC0 registers. The BMAC registers + are described in appendix A. In order to access the BMAC0 registers; the + base address; NIG_REGISTERS_INGRESS_BMAC0_MEM; Offset: 0x10c00; should be + added to each BMAC register offset */ +#define NIG_REG_INGRESS_BMAC0_MEM 0x10c00 +/* [WB 48] This address space contains BMAC1 registers. The BMAC registers + are described in appendix A. In order to access the BMAC0 registers; the + base address; NIG_REGISTERS_INGRESS_BMAC1_MEM; Offset: 0x11000; should be + added to each BMAC register offset */ +#define NIG_REG_INGRESS_BMAC1_MEM 0x11000 +/* [R 1] FIFO empty in EOP descriptor FIFO of LP in NIG_RX_EOP */ +#define NIG_REG_INGRESS_EOP_LB_EMPTY 0x104e0 +/* [RW 17] Debug only. RX_EOP_DSCR_lb_FIFO in NIG_RX_EOP. Data + packet_length[13:0]; mac_error[14]; trunc_error[15]; parity[16] */ +#define NIG_REG_INGRESS_EOP_LB_FIFO 0x104e4 +/* [RW 27] 0 - must be active for Everest A0; 1- for Everest B0 when latch + logic for interrupts must be used. Enable per bit of interrupt of + ~latch_status.latch_status */ +#define NIG_REG_LATCH_BC_0 0x16210 +/* [RW 27] Latch for each interrupt from Unicore.b[0] + status_emac0_misc_mi_int; b[1] status_emac0_misc_mi_complete; + b[2]status_emac0_misc_cfg_change; b[3]status_emac0_misc_link_status; + b[4]status_emac0_misc_link_change; b[5]status_emac0_misc_attn; + b[6]status_serdes0_mac_crs; b[7]status_serdes0_autoneg_complete; + b[8]status_serdes0_fiber_rxact; b[9]status_serdes0_link_status; + b[10]status_serdes0_mr_page_rx; b[11]status_serdes0_cl73_an_complete; + b[12]status_serdes0_cl73_mr_page_rx; b[13]status_serdes0_rx_sigdet; + b[14]status_xgxs0_remotemdioreq; b[15]status_xgxs0_link10g; + b[16]status_xgxs0_autoneg_complete; b[17]status_xgxs0_fiber_rxact; + b[21:18]status_xgxs0_link_status; b[22]status_xgxs0_mr_page_rx; + b[23]status_xgxs0_cl73_an_complete; b[24]status_xgxs0_cl73_mr_page_rx; + b[25]status_xgxs0_rx_sigdet; b[26]status_xgxs0_mac_crs */ +#define NIG_REG_LATCH_STATUS_0 0x18000 +/* [RW 1] led 10g for port 0 */ +#define NIG_REG_LED_10G_P0 0x10320 +/* [RW 1] led 10g for port 1 */ +#define NIG_REG_LED_10G_P1 0x10324 +/* [RW 1] Port0: This bit is set to enable the use of the + ~nig_registers_led_control_blink_rate_p0.led_control_blink_rate_p0 field + defined below. If this bit is cleared; then the blink rate will be about + 8Hz. */ +#define NIG_REG_LED_CONTROL_BLINK_RATE_ENA_P0 0x10318 +/* [RW 12] Port0: Specifies the period of each blink cycle (on + off) for + Traffic LED in milliseconds. Must be a non-zero value. This 12-bit field + is reset to 0x080; giving a default blink period of approximately 8Hz. */ +#define NIG_REG_LED_CONTROL_BLINK_RATE_P0 0x10310 +/* [RW 1] Port0: If set along with the + ~nig_registers_led_control_override_traffic_p0.led_control_override_traffic_p0 + bit and ~nig_registers_led_control_traffic_p0.led_control_traffic_p0 LED + bit; the Traffic LED will blink with the blink rate specified in + ~nig_registers_led_control_blink_rate_p0.led_control_blink_rate_p0 and + ~nig_registers_led_control_blink_rate_ena_p0.led_control_blink_rate_ena_p0 + fields. */ +#define NIG_REG_LED_CONTROL_BLINK_TRAFFIC_P0 0x10308 +/* [RW 1] Port0: If set overrides hardware control of the Traffic LED. The + Traffic LED will then be controlled via bit ~nig_registers_ + led_control_traffic_p0.led_control_traffic_p0 and bit + ~nig_registers_led_control_blink_traffic_p0.led_control_blink_traffic_p0 */ +#define NIG_REG_LED_CONTROL_OVERRIDE_TRAFFIC_P0 0x102f8 +/* [RW 1] Port0: If set along with the led_control_override_trafic_p0 bit; + turns on the Traffic LED. If the led_control_blink_traffic_p0 bit is also + set; the LED will blink with blink rate specified in + ~nig_registers_led_control_blink_rate_p0.led_control_blink_rate_p0 and + ~nig_regsters_led_control_blink_rate_ena_p0.led_control_blink_rate_ena_p0 + fields. */ +#define NIG_REG_LED_CONTROL_TRAFFIC_P0 0x10300 +/* [RW 4] led mode for port0: 0 MAC; 1-3 PHY1; 4 MAC2; 5-7 PHY4; 8-MAC3; + 9-11PHY7; 12 MAC4; 13-15 PHY10; */ +#define NIG_REG_LED_MODE_P0 0x102f0 +/* [RW 3] for port0 enable for llfc ppp and pause. b0 - brb1 enable; b1- + tsdm enable; b2- usdm enable */ +#define NIG_REG_LLFC_EGRESS_SRC_ENABLE_0 0x16070 +#define NIG_REG_LLFC_EGRESS_SRC_ENABLE_1 0x16074 +/* [RW 1] SAFC enable for port0. This register may get 1 only when + ~ppp_enable.ppp_enable = 0 and pause_enable.pause_enable =0 for the same + port */ +#define NIG_REG_LLFC_ENABLE_0 0x16208 +#define NIG_REG_LLFC_ENABLE_1 0x1620c +/* [RW 16] classes are high-priority for port0 */ +#define NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_0 0x16058 +#define NIG_REG_LLFC_HIGH_PRIORITY_CLASSES_1 0x1605c +/* [RW 16] classes are low-priority for port0 */ +#define NIG_REG_LLFC_LOW_PRIORITY_CLASSES_0 0x16060 +#define NIG_REG_LLFC_LOW_PRIORITY_CLASSES_1 0x16064 +/* [RW 1] Output enable of message to LLFC BMAC IF for port0 */ +#define NIG_REG_LLFC_OUT_EN_0 0x160c8 +#define NIG_REG_LLFC_OUT_EN_1 0x160cc +#define NIG_REG_LLH0_ACPI_PAT_0_CRC 0x1015c +#define NIG_REG_LLH0_ACPI_PAT_6_LEN 0x10154 +#define NIG_REG_LLH0_BRB1_DRV_MASK 0x10244 +#define NIG_REG_LLH0_BRB1_DRV_MASK_MF 0x16048 +/* [RW 1] send to BRB1 if no match on any of RMP rules. */ +#define NIG_REG_LLH0_BRB1_NOT_MCP 0x1025c +/* [RW 2] Determine the classification participants. 0: no classification.1: + classification upon VLAN id. 2: classification upon MAC address. 3: + classification upon both VLAN id & MAC addr. */ +#define NIG_REG_LLH0_CLS_TYPE 0x16080 +/* [RW 32] cm header for llh0 */ +#define NIG_REG_LLH0_CM_HEADER 0x1007c +#define NIG_REG_LLH0_DEST_IP_0_1 0x101dc +#define NIG_REG_LLH0_DEST_MAC_0_0 0x101c0 +/* [RW 16] destination TCP address 1. The LLH will look for this address in + all incoming packets. */ +#define NIG_REG_LLH0_DEST_TCP_0 0x10220 +/* [RW 16] destination UDP address 1 The LLH will look for this address in + all incoming packets. */ +#define NIG_REG_LLH0_DEST_UDP_0 0x10214 +#define NIG_REG_LLH0_ERROR_MASK 0x1008c +/* [RW 8] event id for llh0 */ +#define NIG_REG_LLH0_EVENT_ID 0x10084 +#define NIG_REG_LLH0_FUNC_EN 0x160fc +#define NIG_REG_LLH0_FUNC_MEM 0x16180 +#define NIG_REG_LLH0_FUNC_MEM_ENABLE 0x16140 +#define NIG_REG_LLH0_FUNC_VLAN_ID 0x16100 +/* [RW 1] Determine the IP version to look for in + ~nig_registers_llh0_dest_ip_0.llh0_dest_ip_0. 0 - IPv6; 1-IPv4 */ +#define NIG_REG_LLH0_IPV4_IPV6_0 0x10208 +/* [RW 1] t bit for llh0 */ +#define NIG_REG_LLH0_T_BIT 0x10074 +/* [RW 12] VLAN ID 1. In case of VLAN packet the LLH will look for this ID. */ +#define NIG_REG_LLH0_VLAN_ID_0 0x1022c +/* [RW 8] init credit counter for port0 in LLH */ +#define NIG_REG_LLH0_XCM_INIT_CREDIT 0x10554 +#define NIG_REG_LLH0_XCM_MASK 0x10130 +#define NIG_REG_LLH1_BRB1_DRV_MASK 0x10248 +/* [RW 1] send to BRB1 if no match on any of RMP rules. */ +#define NIG_REG_LLH1_BRB1_NOT_MCP 0x102dc +/* [RW 2] Determine the classification participants. 0: no classification.1: + classification upon VLAN id. 2: classification upon MAC address. 3: + classification upon both VLAN id & MAC addr. */ +#define NIG_REG_LLH1_CLS_TYPE 0x16084 +/* [RW 32] cm header for llh1 */ +#define NIG_REG_LLH1_CM_HEADER 0x10080 +#define NIG_REG_LLH1_ERROR_MASK 0x10090 +/* [RW 8] event id for llh1 */ +#define NIG_REG_LLH1_EVENT_ID 0x10088 +#define NIG_REG_LLH1_FUNC_MEM 0x161c0 +#define NIG_REG_LLH1_FUNC_MEM_ENABLE 0x16160 +#define NIG_REG_LLH1_FUNC_MEM_SIZE 16 +/* [RW 1] When this bit is set; the LLH will classify the packet before + * sending it to the BRB or calculating WoL on it. This bit controls port 1 + * only. The legacy llh_multi_function_mode bit controls port 0. */ +#define NIG_REG_LLH1_MF_MODE 0x18614 +/* [RW 8] init credit counter for port1 in LLH */ +#define NIG_REG_LLH1_XCM_INIT_CREDIT 0x10564 +#define NIG_REG_LLH1_XCM_MASK 0x10134 +/* [RW 1] When this bit is set; the LLH will expect all packets to be with + e1hov */ +#define NIG_REG_LLH_E1HOV_MODE 0x160d8 +/* [RW 1] When this bit is set; the LLH will classify the packet before + sending it to the BRB or calculating WoL on it. */ +#define NIG_REG_LLH_MF_MODE 0x16024 +#define NIG_REG_MASK_INTERRUPT_PORT0 0x10330 +#define NIG_REG_MASK_INTERRUPT_PORT1 0x10334 +/* [RW 1] Output signal from NIG to EMAC0. When set enables the EMAC0 block. */ +#define NIG_REG_NIG_EMAC0_EN 0x1003c +/* [RW 1] Output signal from NIG to EMAC1. When set enables the EMAC1 block. */ +#define NIG_REG_NIG_EMAC1_EN 0x10040 +/* [RW 1] Output signal from NIG to TX_EMAC0. When set indicates to the + EMAC0 to strip the CRC from the ingress packets. */ +#define NIG_REG_NIG_INGRESS_EMAC0_NO_CRC 0x10044 +/* [R 32] Interrupt register #0 read */ +#define NIG_REG_NIG_INT_STS_0 0x103b0 +#define NIG_REG_NIG_INT_STS_1 0x103c0 +/* [R 32] Legacy E1 and E1H location for parity error mask register. */ +#define NIG_REG_NIG_PRTY_MASK 0x103dc +/* [RW 32] Parity mask register #0 read/write */ +#define NIG_REG_NIG_PRTY_MASK_0 0x183c8 +#define NIG_REG_NIG_PRTY_MASK_1 0x183d8 +/* [R 32] Legacy E1 and E1H location for parity error status register. */ +#define NIG_REG_NIG_PRTY_STS 0x103d0 +/* [R 32] Parity register #0 read */ +#define NIG_REG_NIG_PRTY_STS_0 0x183bc +#define NIG_REG_NIG_PRTY_STS_1 0x183cc +/* [R 32] Legacy E1 and E1H location for parity error status clear register. */ +#define NIG_REG_NIG_PRTY_STS_CLR 0x103d4 +/* [RC 32] Parity register #0 read clear */ +#define NIG_REG_NIG_PRTY_STS_CLR_0 0x183c0 +#define NIG_REG_NIG_PRTY_STS_CLR_1 0x183d0 +#define MCPR_IMC_COMMAND_ENABLE (1L<<31) +#define MCPR_IMC_COMMAND_IMC_STATUS_BITSHIFT 16 +#define MCPR_IMC_COMMAND_OPERATION_BITSHIFT 28 +#define MCPR_IMC_COMMAND_TRANSFER_ADDRESS_BITSHIFT 8 +/* [RW 6] Bit-map indicating which L2 hdrs may appear after the basic + * Ethernet header. */ +#define NIG_REG_P0_HDRS_AFTER_BASIC 0x18038 +/* [RW 1] HW PFC enable bit. Set this bit to enable the PFC functionality in + * the NIG. Other flow control modes such as PAUSE and SAFC/LLFC should be + * disabled when this bit is set. */ +#define NIG_REG_P0_HWPFC_ENABLE 0x18078 +#define NIG_REG_P0_LLH_FUNC_MEM2 0x18480 +#define NIG_REG_P0_LLH_FUNC_MEM2_ENABLE 0x18440 +/* [RW 1] Input enable for RX MAC interface. */ +#define NIG_REG_P0_MAC_IN_EN 0x185ac +/* [RW 1] Output enable for TX MAC interface */ +#define NIG_REG_P0_MAC_OUT_EN 0x185b0 +/* [RW 1] Output enable for TX PAUSE signal to the MAC. */ +#define NIG_REG_P0_MAC_PAUSE_OUT_EN 0x185b4 +/* [RW 32] Eight 4-bit configurations for specifying which COS (0-15 for + * future expansion) each priorty is to be mapped to. Bits 3:0 specify the + * COS for priority 0. Bits 31:28 specify the COS for priority 7. The 3-bit + * priority field is extracted from the outer-most VLAN in receive packet. + * Only COS 0 and COS 1 are supported in E2. */ +#define NIG_REG_P0_PKT_PRIORITY_TO_COS 0x18054 +/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 0. A + * priority is mapped to COS 0 when the corresponding mask bit is 1. More + * than one bit may be set; allowing multiple priorities to be mapped to one + * COS. */ +#define NIG_REG_P0_RX_COS0_PRIORITY_MASK 0x18058 +/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 1. A + * priority is mapped to COS 1 when the corresponding mask bit is 1. More + * than one bit may be set; allowing multiple priorities to be mapped to one + * COS. */ +#define NIG_REG_P0_RX_COS1_PRIORITY_MASK 0x1805c +/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 2. A + * priority is mapped to COS 2 when the corresponding mask bit is 1. More + * than one bit may be set; allowing multiple priorities to be mapped to one + * COS. */ +#define NIG_REG_P0_RX_COS2_PRIORITY_MASK 0x186b0 +/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 3. A + * priority is mapped to COS 3 when the corresponding mask bit is 1. More + * than one bit may be set; allowing multiple priorities to be mapped to one + * COS. */ +#define NIG_REG_P0_RX_COS3_PRIORITY_MASK 0x186b4 +/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 4. A + * priority is mapped to COS 4 when the corresponding mask bit is 1. More + * than one bit may be set; allowing multiple priorities to be mapped to one + * COS. */ +#define NIG_REG_P0_RX_COS4_PRIORITY_MASK 0x186b8 +/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 5. A + * priority is mapped to COS 5 when the corresponding mask bit is 1. More + * than one bit may be set; allowing multiple priorities to be mapped to one + * COS. */ +#define NIG_REG_P0_RX_COS5_PRIORITY_MASK 0x186bc +/* [R 1] RX FIFO for receiving data from MAC is empty. */ +/* [RW 15] Specify which of the credit registers the client is to be mapped + * to. Bits[2:0] are for client 0; bits [14:12] are for client 4. For + * clients that are not subject to WFQ credit blocking - their + * specifications here are not used. */ +#define NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP 0x180f0 +/* [RW 32] Specify which of the credit registers the client is to be mapped + * to. This register specifies bits 31:0 of the 36-bit value. Bits[3:0] are + * for client 0; bits [35:32] are for client 8. For clients that are not + * subject to WFQ credit blocking - their specifications here are not used. + * This is a new register (with 2_) added in E3 B0 to accommodate the 9 + * input clients to ETS arbiter. The reset default is set for management and + * debug to use credit registers 6, 7, and 8, respectively, and COSes 0-5 to + * use credit registers 0-5 respectively (0x543210876). Note that credit + * registers can not be shared between clients. */ +#define NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_LSB 0x18688 +/* [RW 4] Specify which of the credit registers the client is to be mapped + * to. This register specifies bits 35:32 of the 36-bit value. Bits[3:0] are + * for client 0; bits [35:32] are for client 8. For clients that are not + * subject to WFQ credit blocking - their specifications here are not used. + * This is a new register (with 2_) added in E3 B0 to accommodate the 9 + * input clients to ETS arbiter. The reset default is set for management and + * debug to use credit registers 6, 7, and 8, respectively, and COSes 0-5 to + * use credit registers 0-5 respectively (0x543210876). Note that credit + * registers can not be shared between clients. */ +#define NIG_REG_P0_TX_ARB_CLIENT_CREDIT_MAP2_MSB 0x1868c +/* [RW 5] Specify whether the client competes directly in the strict + * priority arbiter. The bits are mapped according to client ID (client IDs + * are defined in tx_arb_priority_client). Default value is set to enable + * strict priorities for clients 0-2 -- management and debug traffic. */ +#define NIG_REG_P0_TX_ARB_CLIENT_IS_STRICT 0x180e8 +/* [RW 5] Specify whether the client is subject to WFQ credit blocking. The + * bits are mapped according to client ID (client IDs are defined in + * tx_arb_priority_client). Default value is 0 for not using WFQ credit + * blocking. */ +#define NIG_REG_P0_TX_ARB_CLIENT_IS_SUBJECT2WFQ 0x180ec +/* [RW 32] Specify the upper bound that credit register 0 is allowed to + * reach. */ +#define NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_0 0x1810c +#define NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_1 0x18110 +#define NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_2 0x18114 +#define NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_3 0x18118 +#define NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_4 0x1811c +#define NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_5 0x186a0 +#define NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_6 0x186a4 +#define NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_7 0x186a8 +#define NIG_REG_P0_TX_ARB_CREDIT_UPPER_BOUND_8 0x186ac +/* [RW 32] Specify the weight (in bytes) to be added to credit register 0 + * when it is time to increment. */ +#define NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_0 0x180f8 +#define NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_1 0x180fc +#define NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_2 0x18100 +#define NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_3 0x18104 +#define NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_4 0x18108 +#define NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_5 0x18690 +#define NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_6 0x18694 +#define NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_7 0x18698 +#define NIG_REG_P0_TX_ARB_CREDIT_WEIGHT_8 0x1869c +/* [RW 12] Specify the number of strict priority arbitration slots between + * two round-robin arbitration slots to avoid starvation. A value of 0 means + * no strict priority cycles - the strict priority with anti-starvation + * arbiter becomes a round-robin arbiter. */ +#define NIG_REG_P0_TX_ARB_NUM_STRICT_ARB_SLOTS 0x180f4 +/* [RW 15] Specify the client number to be assigned to each priority of the + * strict priority arbiter. Priority 0 is the highest priority. Bits [2:0] + * are for priority 0 client; bits [14:12] are for priority 4 client. The + * clients are assigned the following IDs: 0-management; 1-debug traffic + * from this port; 2-debug traffic from other port; 3-COS0 traffic; 4-COS1 + * traffic. The reset value[14:0] is set to 0x4688 (15'b100_011_010_001_000) + * for management at priority 0; debug traffic at priorities 1 and 2; COS0 + * traffic at priority 3; and COS1 traffic at priority 4. */ +#define NIG_REG_P0_TX_ARB_PRIORITY_CLIENT 0x180e4 +/* [RW 6] Bit-map indicating which L2 hdrs may appear after the basic + * Ethernet header. */ +#define NIG_REG_P1_HDRS_AFTER_BASIC 0x1818c +#define NIG_REG_P1_LLH_FUNC_MEM2 0x184c0 +#define NIG_REG_P1_LLH_FUNC_MEM2_ENABLE 0x18460 +/* [RW 32] Specify the client number to be assigned to each priority of the + * strict priority arbiter. This register specifies bits 31:0 of the 36-bit + * value. Priority 0 is the highest priority. Bits [3:0] are for priority 0 + * client; bits [35-32] are for priority 8 client. The clients are assigned + * the following IDs: 0-management; 1-debug traffic from this port; 2-debug + * traffic from other port; 3-COS0 traffic; 4-COS1 traffic; 5-COS2 traffic; + * 6-COS3 traffic; 7-COS4 traffic; 8-COS5 traffic. The reset value[35:0] is + * set to 0x345678021. This is a new register (with 2_) added in E3 B0 to + * accommodate the 9 input clients to ETS arbiter. */ +#define NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_LSB 0x18680 +/* [RW 4] Specify the client number to be assigned to each priority of the + * strict priority arbiter. This register specifies bits 35:32 of the 36-bit + * value. Priority 0 is the highest priority. Bits [3:0] are for priority 0 + * client; bits [35-32] are for priority 8 client. The clients are assigned + * the following IDs: 0-management; 1-debug traffic from this port; 2-debug + * traffic from other port; 3-COS0 traffic; 4-COS1 traffic; 5-COS2 traffic; + * 6-COS3 traffic; 7-COS4 traffic; 8-COS5 traffic. The reset value[35:0] is + * set to 0x345678021. This is a new register (with 2_) added in E3 B0 to + * accommodate the 9 input clients to ETS arbiter. */ +#define NIG_REG_P0_TX_ARB_PRIORITY_CLIENT2_MSB 0x18684 +#define NIG_REG_P1_MAC_IN_EN 0x185c0 +/* [RW 1] Output enable for TX MAC interface */ +#define NIG_REG_P1_MAC_OUT_EN 0x185c4 +/* [RW 1] Output enable for TX PAUSE signal to the MAC. */ +#define NIG_REG_P1_MAC_PAUSE_OUT_EN 0x185c8 +/* [RW 32] Eight 4-bit configurations for specifying which COS (0-15 for + * future expansion) each priorty is to be mapped to. Bits 3:0 specify the + * COS for priority 0. Bits 31:28 specify the COS for priority 7. The 3-bit + * priority field is extracted from the outer-most VLAN in receive packet. + * Only COS 0 and COS 1 are supported in E2. */ +#define NIG_REG_P1_PKT_PRIORITY_TO_COS 0x181a8 +/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 0. A + * priority is mapped to COS 0 when the corresponding mask bit is 1. More + * than one bit may be set; allowing multiple priorities to be mapped to one + * COS. */ +#define NIG_REG_P1_RX_COS0_PRIORITY_MASK 0x181ac +/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 1. A + * priority is mapped to COS 1 when the corresponding mask bit is 1. More + * than one bit may be set; allowing multiple priorities to be mapped to one + * COS. */ +#define NIG_REG_P1_RX_COS1_PRIORITY_MASK 0x181b0 +/* [RW 16] Bit-map indicating which SAFC/PFC priorities to map to COS 2. A + * priority is mapped to COS 2 when the corresponding mask bit is 1. More + * than one bit may be set; allowing multiple priorities to be mapped to one + * COS. */ +#define NIG_REG_P1_RX_COS2_PRIORITY_MASK 0x186f8 +/* [R 1] RX FIFO for receiving data from MAC is empty. */ +#define NIG_REG_P1_RX_MACFIFO_EMPTY 0x1858c +/* [R 1] TLLH FIFO is empty. */ +#define NIG_REG_P1_TLLH_FIFO_EMPTY 0x18338 +/* [RW 32] Specify which of the credit registers the client is to be mapped + * to. This register specifies bits 31:0 of the 36-bit value. Bits[3:0] are + * for client 0; bits [35:32] are for client 8. For clients that are not + * subject to WFQ credit blocking - their specifications here are not used. + * This is a new register (with 2_) added in E3 B0 to accommodate the 9 + * input clients to ETS arbiter. The reset default is set for management and + * debug to use credit registers 6, 7, and 8, respectively, and COSes 0-5 to + * use credit registers 0-5 respectively (0x543210876). Note that credit + * registers can not be shared between clients. Note also that there are + * only COS0-2 in port 1- there is a total of 6 clients in port 1. Only + * credit registers 0-5 are valid. This register should be configured + * appropriately before enabling WFQ. */ +#define NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_LSB 0x186e8 +/* [RW 4] Specify which of the credit registers the client is to be mapped + * to. This register specifies bits 35:32 of the 36-bit value. Bits[3:0] are + * for client 0; bits [35:32] are for client 8. For clients that are not + * subject to WFQ credit blocking - their specifications here are not used. + * This is a new register (with 2_) added in E3 B0 to accommodate the 9 + * input clients to ETS arbiter. The reset default is set for management and + * debug to use credit registers 6, 7, and 8, respectively, and COSes 0-5 to + * use credit registers 0-5 respectively (0x543210876). Note that credit + * registers can not be shared between clients. Note also that there are + * only COS0-2 in port 1- there is a total of 6 clients in port 1. Only + * credit registers 0-5 are valid. This register should be configured + * appropriately before enabling WFQ. */ +#define NIG_REG_P1_TX_ARB_CLIENT_CREDIT_MAP2_MSB 0x186ec +/* [RW 9] Specify whether the client competes directly in the strict + * priority arbiter. The bits are mapped according to client ID (client IDs + * are defined in tx_arb_priority_client2): 0-management; 1-debug traffic + * from this port; 2-debug traffic from other port; 3-COS0 traffic; 4-COS1 + * traffic; 5-COS2 traffic; 6-COS3 traffic; 7-COS4 traffic; 8-COS5 traffic. + * Default value is set to enable strict priorities for all clients. */ +#define NIG_REG_P1_TX_ARB_CLIENT_IS_STRICT 0x18234 +/* [RW 9] Specify whether the client is subject to WFQ credit blocking. The + * bits are mapped according to client ID (client IDs are defined in + * tx_arb_priority_client2): 0-management; 1-debug traffic from this port; + * 2-debug traffic from other port; 3-COS0 traffic; 4-COS1 traffic; 5-COS2 + * traffic; 6-COS3 traffic; 7-COS4 traffic; 8-COS5 traffic. Default value is + * 0 for not using WFQ credit blocking. */ +#define NIG_REG_P1_TX_ARB_CLIENT_IS_SUBJECT2WFQ 0x18238 +#define NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_0 0x18258 +#define NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_1 0x1825c +#define NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_2 0x18260 +#define NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_3 0x18264 +#define NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_4 0x18268 +#define NIG_REG_P1_TX_ARB_CREDIT_UPPER_BOUND_5 0x186f4 +/* [RW 32] Specify the weight (in bytes) to be added to credit register 0 + * when it is time to increment. */ +#define NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_0 0x18244 +#define NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_1 0x18248 +#define NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_2 0x1824c +#define NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_3 0x18250 +#define NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_4 0x18254 +#define NIG_REG_P1_TX_ARB_CREDIT_WEIGHT_5 0x186f0 +/* [RW 12] Specify the number of strict priority arbitration slots between + two round-robin arbitration slots to avoid starvation. A value of 0 means + no strict priority cycles - the strict priority with anti-starvation + arbiter becomes a round-robin arbiter. */ +#define NIG_REG_P1_TX_ARB_NUM_STRICT_ARB_SLOTS 0x18240 +/* [RW 32] Specify the client number to be assigned to each priority of the + strict priority arbiter. This register specifies bits 31:0 of the 36-bit + value. Priority 0 is the highest priority. Bits [3:0] are for priority 0 + client; bits [35-32] are for priority 8 client. The clients are assigned + the following IDs: 0-management; 1-debug traffic from this port; 2-debug + traffic from other port; 3-COS0 traffic; 4-COS1 traffic; 5-COS2 traffic; + 6-COS3 traffic; 7-COS4 traffic; 8-COS5 traffic. The reset value[35:0] is + set to 0x345678021. This is a new register (with 2_) added in E3 B0 to + accommodate the 9 input clients to ETS arbiter. Note that this register + is the same as the one for port 0, except that port 1 only has COS 0-2 + traffic. There is no traffic for COS 3-5 of port 1. */ +#define NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_LSB 0x186e0 +/* [RW 4] Specify the client number to be assigned to each priority of the + strict priority arbiter. This register specifies bits 35:32 of the 36-bit + value. Priority 0 is the highest priority. Bits [3:0] are for priority 0 + client; bits [35-32] are for priority 8 client. The clients are assigned + the following IDs: 0-management; 1-debug traffic from this port; 2-debug + traffic from other port; 3-COS0 traffic; 4-COS1 traffic; 5-COS2 traffic; + 6-COS3 traffic; 7-COS4 traffic; 8-COS5 traffic. The reset value[35:0] is + set to 0x345678021. This is a new register (with 2_) added in E3 B0 to + accommodate the 9 input clients to ETS arbiter. Note that this register + is the same as the one for port 0, except that port 1 only has COS 0-2 + traffic. There is no traffic for COS 3-5 of port 1. */ +#define NIG_REG_P1_TX_ARB_PRIORITY_CLIENT2_MSB 0x186e4 +/* [R 1] TX FIFO for transmitting data to MAC is empty. */ +#define NIG_REG_P1_TX_MACFIFO_EMPTY 0x18594 +/* [R 1] FIFO empty status of the MCP TX FIFO used for storing MCP packets + forwarded to the host. */ +#define NIG_REG_P1_TX_MNG_HOST_FIFO_EMPTY 0x182b8 +/* [RW 32] Specify the upper bound that credit register 0 is allowed to + * reach. */ +/* [RW 1] Pause enable for port0. This register may get 1 only when + ~safc_enable.safc_enable = 0 and ppp_enable.ppp_enable =0 for the same + port */ +#define NIG_REG_PAUSE_ENABLE_0 0x160c0 +#define NIG_REG_PAUSE_ENABLE_1 0x160c4 +/* [RW 1] Input enable for RX PBF LP IF */ +#define NIG_REG_PBF_LB_IN_EN 0x100b4 +/* [RW 1] Value of this register will be transmitted to port swap when + ~nig_registers_strap_override.strap_override =1 */ +#define NIG_REG_PORT_SWAP 0x10394 +/* [RW 1] PPP enable for port0. This register may get 1 only when + * ~safc_enable.safc_enable = 0 and pause_enable.pause_enable =0 for the + * same port */ +#define NIG_REG_PPP_ENABLE_0 0x160b0 +#define NIG_REG_PPP_ENABLE_1 0x160b4 +/* [RW 1] output enable for RX parser descriptor IF */ +#define NIG_REG_PRS_EOP_OUT_EN 0x10104 +/* [RW 1] Input enable for RX parser request IF */ +#define NIG_REG_PRS_REQ_IN_EN 0x100b8 +/* [RW 5] control to serdes - CL45 DEVAD */ +#define NIG_REG_SERDES0_CTRL_MD_DEVAD 0x10370 +/* [RW 1] control to serdes; 0 - clause 45; 1 - clause 22 */ +#define NIG_REG_SERDES0_CTRL_MD_ST 0x1036c +/* [RW 5] control to serdes - CL22 PHY_ADD and CL45 PRTAD */ +#define NIG_REG_SERDES0_CTRL_PHY_ADDR 0x10374 +/* [R 1] status from serdes0 that inputs to interrupt logic of link status */ +#define NIG_REG_SERDES0_STATUS_LINK_STATUS 0x10578 +/* [R 32] Rx statistics : In user packets discarded due to BRB backpressure + for port0 */ +#define NIG_REG_STAT0_BRB_DISCARD 0x105f0 +/* [R 32] Rx statistics : In user packets truncated due to BRB backpressure + for port0 */ +#define NIG_REG_STAT0_BRB_TRUNCATE 0x105f8 +/* [WB_R 36] Tx statistics : Number of packets from emac0 or bmac0 that + between 1024 and 1522 bytes for port0 */ +#define NIG_REG_STAT0_EGRESS_MAC_PKT0 0x10750 +/* [WB_R 36] Tx statistics : Number of packets from emac0 or bmac0 that + between 1523 bytes and above for port0 */ +#define NIG_REG_STAT0_EGRESS_MAC_PKT1 0x10760 +/* [R 32] Rx statistics : In user packets discarded due to BRB backpressure + for port1 */ +#define NIG_REG_STAT1_BRB_DISCARD 0x10628 +/* [WB_R 36] Tx statistics : Number of packets from emac1 or bmac1 that + between 1024 and 1522 bytes for port1 */ +#define NIG_REG_STAT1_EGRESS_MAC_PKT0 0x107a0 +/* [WB_R 36] Tx statistics : Number of packets from emac1 or bmac1 that + between 1523 bytes and above for port1 */ +#define NIG_REG_STAT1_EGRESS_MAC_PKT1 0x107b0 +/* [WB_R 64] Rx statistics : User octets received for LP */ +#define NIG_REG_STAT2_BRB_OCTET 0x107e0 +#define NIG_REG_STATUS_INTERRUPT_PORT0 0x10328 +#define NIG_REG_STATUS_INTERRUPT_PORT1 0x1032c +/* [RW 1] port swap mux selection. If this register equal to 0 then port + swap is equal to SPIO pin that inputs from ifmux_serdes_swap. If 1 then + ort swap is equal to ~nig_registers_port_swap.port_swap */ +#define NIG_REG_STRAP_OVERRIDE 0x10398 +/* [RW 1] output enable for RX_XCM0 IF */ +#define NIG_REG_XCM0_OUT_EN 0x100f0 +/* [RW 1] output enable for RX_XCM1 IF */ +#define NIG_REG_XCM1_OUT_EN 0x100f4 +/* [RW 1] control to xgxs - remote PHY in-band MDIO */ +#define NIG_REG_XGXS0_CTRL_EXTREMOTEMDIOST 0x10348 +/* [RW 5] control to xgxs - CL45 DEVAD */ +#define NIG_REG_XGXS0_CTRL_MD_DEVAD 0x1033c +/* [RW 1] control to xgxs; 0 - clause 45; 1 - clause 22 */ +#define NIG_REG_XGXS0_CTRL_MD_ST 0x10338 +/* [RW 5] control to xgxs - CL22 PHY_ADD and CL45 PRTAD */ +#define NIG_REG_XGXS0_CTRL_PHY_ADDR 0x10340 +/* [R 1] status from xgxs0 that inputs to interrupt logic of link10g. */ +#define NIG_REG_XGXS0_STATUS_LINK10G 0x10680 +/* [R 4] status from xgxs0 that inputs to interrupt logic of link status */ +#define NIG_REG_XGXS0_STATUS_LINK_STATUS 0x10684 +/* [RW 2] selection for XGXS lane of port 0 in NIG_MUX block */ +#define NIG_REG_XGXS_LANE_SEL_P0 0x102e8 +/* [RW 1] selection for port0 for NIG_MUX block : 0 = SerDes; 1 = XGXS */ +#define NIG_REG_XGXS_SERDES0_MODE_SEL 0x102e0 +#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_EMAC0_MISC_MI_INT (0x1<<0) +#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_SERDES0_LINK_STATUS (0x1<<9) +#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK10G (0x1<<15) +#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS (0xf<<18) +#define NIG_STATUS_INTERRUPT_PORT0_REG_STATUS_XGXS0_LINK_STATUS_SIZE 18 +/* [RW 31] The upper bound of the weight of COS0 in the ETS command arbiter. */ +#define PBF_REG_COS0_UPPER_BOUND 0x15c05c +/* [RW 31] The upper bound of the weight of COS0 in the ETS command arbiter + * of port 0. */ +#define PBF_REG_COS0_UPPER_BOUND_P0 0x15c2cc +/* [RW 31] The upper bound of the weight of COS0 in the ETS command arbiter + * of port 1. */ +#define PBF_REG_COS0_UPPER_BOUND_P1 0x15c2e4 +/* [RW 31] The weight of COS0 in the ETS command arbiter. */ +#define PBF_REG_COS0_WEIGHT 0x15c054 +/* [RW 31] The weight of COS0 in port 0 ETS command arbiter. */ +#define PBF_REG_COS0_WEIGHT_P0 0x15c2a8 +/* [RW 31] The weight of COS0 in port 1 ETS command arbiter. */ +#define PBF_REG_COS0_WEIGHT_P1 0x15c2c0 +/* [RW 31] The upper bound of the weight of COS1 in the ETS command arbiter. */ +#define PBF_REG_COS1_UPPER_BOUND 0x15c060 +/* [RW 31] The weight of COS1 in the ETS command arbiter. */ +#define PBF_REG_COS1_WEIGHT 0x15c058 +/* [RW 31] The weight of COS1 in port 0 ETS command arbiter. */ +#define PBF_REG_COS1_WEIGHT_P0 0x15c2ac +/* [RW 31] The weight of COS1 in port 1 ETS command arbiter. */ +#define PBF_REG_COS1_WEIGHT_P1 0x15c2c4 +/* [RW 31] The weight of COS2 in port 0 ETS command arbiter. */ +#define PBF_REG_COS2_WEIGHT_P0 0x15c2b0 +/* [RW 31] The weight of COS2 in port 1 ETS command arbiter. */ +#define PBF_REG_COS2_WEIGHT_P1 0x15c2c8 +/* [RW 31] The weight of COS3 in port 0 ETS command arbiter. */ +#define PBF_REG_COS3_WEIGHT_P0 0x15c2b4 +/* [RW 31] The weight of COS4 in port 0 ETS command arbiter. */ +#define PBF_REG_COS4_WEIGHT_P0 0x15c2b8 +/* [RW 31] The weight of COS5 in port 0 ETS command arbiter. */ +#define PBF_REG_COS5_WEIGHT_P0 0x15c2bc +/* [R 11] Current credit for the LB queue in the tx port buffers in 16 byte + * lines. */ +#define PBF_REG_CREDIT_LB_Q 0x140338 +/* [R 11] Current credit for queue 0 in the tx port buffers in 16 byte + * lines. */ +#define PBF_REG_CREDIT_Q0 0x14033c +/* [R 11] Current credit for queue 1 in the tx port buffers in 16 byte + * lines. */ +#define PBF_REG_CREDIT_Q1 0x140340 +/* [RW 1] Disable processing further tasks from port 0 (after ending the + current task in process). */ +#define PBF_REG_DISABLE_NEW_TASK_PROC_P0 0x14005c +/* [RW 1] Disable processing further tasks from port 1 (after ending the + current task in process). */ +#define PBF_REG_DISABLE_NEW_TASK_PROC_P1 0x140060 +/* [RW 1] Disable processing further tasks from port 4 (after ending the + current task in process). */ +#define PBF_REG_DISABLE_NEW_TASK_PROC_P4 0x14006c +#define PBF_REG_DISABLE_PF 0x1402e8 +/* [RW 18] For port 0: For each client that is subject to WFQ (the + * corresponding bit is 1); indicates to which of the credit registers this + * client is mapped. For clients which are not credit blocked; their mapping + * is dont care. */ +#define PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P0 0x15c288 +/* [RW 9] For port 1: For each client that is subject to WFQ (the + * corresponding bit is 1); indicates to which of the credit registers this + * client is mapped. For clients which are not credit blocked; their mapping + * is dont care. */ +#define PBF_REG_ETS_ARB_CLIENT_CREDIT_MAP_P1 0x15c28c +/* [RW 6] For port 0: Bit per client to indicate if the client competes in + * the strict priority arbiter directly (corresponding bit = 1); or first + * goes to the RR arbiter (corresponding bit = 0); and then competes in the + * lowest priority in the strict-priority arbiter. */ +#define PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P0 0x15c278 +/* [RW 3] For port 1: Bit per client to indicate if the client competes in + * the strict priority arbiter directly (corresponding bit = 1); or first + * goes to the RR arbiter (corresponding bit = 0); and then competes in the + * lowest priority in the strict-priority arbiter. */ +#define PBF_REG_ETS_ARB_CLIENT_IS_STRICT_P1 0x15c27c +/* [RW 6] For port 0: Bit per client to indicate if the client is subject to + * WFQ credit blocking (corresponding bit = 1). */ +#define PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P0 0x15c280 +/* [RW 3] For port 0: Bit per client to indicate if the client is subject to + * WFQ credit blocking (corresponding bit = 1). */ +#define PBF_REG_ETS_ARB_CLIENT_IS_SUBJECT2WFQ_P1 0x15c284 +/* [RW 16] For port 0: The number of strict priority arbitration slots + * between 2 RR arbitration slots. A value of 0 means no strict priority + * cycles; i.e. the strict-priority w/ anti-starvation arbiter is a RR + * arbiter. */ +#define PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P0 0x15c2a0 +/* [RW 16] For port 1: The number of strict priority arbitration slots + * between 2 RR arbitration slots. A value of 0 means no strict priority + * cycles; i.e. the strict-priority w/ anti-starvation arbiter is a RR + * arbiter. */ +#define PBF_REG_ETS_ARB_NUM_STRICT_ARB_SLOTS_P1 0x15c2a4 +/* [RW 18] For port 0: Indicates which client is connected to each priority + * in the strict-priority arbiter. Priority 0 is the highest priority, and + * priority 5 is the lowest; to which the RR output is connected to (this is + * not configurable). */ +#define PBF_REG_ETS_ARB_PRIORITY_CLIENT_P0 0x15c270 +/* [RW 9] For port 1: Indicates which client is connected to each priority + * in the strict-priority arbiter. Priority 0 is the highest priority, and + * priority 5 is the lowest; to which the RR output is connected to (this is + * not configurable). */ +#define PBF_REG_ETS_ARB_PRIORITY_CLIENT_P1 0x15c274 +/* [RW 1] Indicates that ETS is performed between the COSes in the command + * arbiter. If reset strict priority w/ anti-starvation will be performed + * w/o WFQ. */ +#define PBF_REG_ETS_ENABLED 0x15c050 +/* [RW 6] Bit-map indicating which L2 hdrs may appear after the basic + * Ethernet header. */ +#define PBF_REG_HDRS_AFTER_BASIC 0x15c0a8 +/* [RW 6] Bit-map indicating which L2 hdrs may appear after L2 tag 0 */ +#define PBF_REG_HDRS_AFTER_TAG_0 0x15c0b8 +/* [R 1] Removed for E3 B0 - Indicates which COS is conncted to the highest + * priority in the command arbiter. */ +#define PBF_REG_HIGH_PRIORITY_COS_NUM 0x15c04c +#define PBF_REG_IF_ENABLE_REG 0x140044 +/* [RW 1] Init bit. When set the initial credits are copied to the credit + registers (except the port credits). Should be set and then reset after + the configuration of the block has ended. */ +#define PBF_REG_INIT 0x140000 +/* [RW 11] Initial credit for the LB queue in the tx port buffers in 16 byte + * lines. */ +#define PBF_REG_INIT_CRD_LB_Q 0x15c248 +/* [RW 11] Initial credit for queue 0 in the tx port buffers in 16 byte + * lines. */ +#define PBF_REG_INIT_CRD_Q0 0x15c230 +/* [RW 11] Initial credit for queue 1 in the tx port buffers in 16 byte + * lines. */ +#define PBF_REG_INIT_CRD_Q1 0x15c234 +/* [RW 1] Init bit for port 0. When set the initial credit of port 0 is + copied to the credit register. Should be set and then reset after the + configuration of the port has ended. */ +#define PBF_REG_INIT_P0 0x140004 +/* [RW 1] Init bit for port 1. When set the initial credit of port 1 is + copied to the credit register. Should be set and then reset after the + configuration of the port has ended. */ +#define PBF_REG_INIT_P1 0x140008 +/* [RW 1] Init bit for port 4. When set the initial credit of port 4 is + copied to the credit register. Should be set and then reset after the + configuration of the port has ended. */ +#define PBF_REG_INIT_P4 0x14000c +/* [R 32] Cyclic counter for the amount credits in 16 bytes lines added for + * the LB queue. Reset upon init. */ +#define PBF_REG_INTERNAL_CRD_FREED_CNT_LB_Q 0x140354 +/* [R 32] Cyclic counter for the amount credits in 16 bytes lines added for + * queue 0. Reset upon init. */ +#define PBF_REG_INTERNAL_CRD_FREED_CNT_Q0 0x140358 +/* [R 32] Cyclic counter for the amount credits in 16 bytes lines added for + * queue 1. Reset upon init. */ +#define PBF_REG_INTERNAL_CRD_FREED_CNT_Q1 0x14035c +/* [RW 1] Enable for mac interface 0. */ +#define PBF_REG_MAC_IF0_ENABLE 0x140030 +/* [RW 1] Enable for mac interface 1. */ +#define PBF_REG_MAC_IF1_ENABLE 0x140034 +/* [RW 1] Enable for the loopback interface. */ +#define PBF_REG_MAC_LB_ENABLE 0x140040 +/* [RW 6] Bit-map indicating which headers must appear in the packet */ +#define PBF_REG_MUST_HAVE_HDRS 0x15c0c4 +/* [RW 16] The number of strict priority arbitration slots between 2 RR + * arbitration slots. A value of 0 means no strict priority cycles; i.e. the + * strict-priority w/ anti-starvation arbiter is a RR arbiter. */ +#define PBF_REG_NUM_STRICT_ARB_SLOTS 0x15c064 +/* [RW 10] Port 0 threshold used by arbiter in 16 byte lines used when pause + not suppoterd. */ +#define PBF_REG_P0_ARB_THRSH 0x1400e4 +/* [R 11] Current credit for port 0 in the tx port buffers in 16 byte lines. */ +#define PBF_REG_P0_CREDIT 0x140200 +/* [RW 11] Initial credit for port 0 in the tx port buffers in 16 byte + lines. */ +#define PBF_REG_P0_INIT_CRD 0x1400d0 +/* [R 32] Cyclic counter for the amount credits in 16 bytes lines added for + * port 0. Reset upon init. */ +#define PBF_REG_P0_INTERNAL_CRD_FREED_CNT 0x140308 +/* [R 1] Removed for E3 B0 - Indication that pause is enabled for port 0. */ +#define PBF_REG_P0_PAUSE_ENABLE 0x140014 +/* [R 8] Removed for E3 B0 - Number of tasks in port 0 task queue. */ +#define PBF_REG_P0_TASK_CNT 0x140204 +/* [R 32] Removed for E3 B0 - Cyclic counter for number of 8 byte lines + * freed from the task queue of port 0. Reset upon init. */ +#define PBF_REG_P0_TQ_LINES_FREED_CNT 0x1402f0 +/* [R 12] Number of 8 bytes lines occupied in the task queue of port 0. */ +#define PBF_REG_P0_TQ_OCCUPANCY 0x1402fc +/* [R 11] Removed for E3 B0 - Current credit for port 1 in the tx port + * buffers in 16 byte lines. */ +#define PBF_REG_P1_CREDIT 0x140208 +/* [R 11] Removed for E3 B0 - Initial credit for port 0 in the tx port + * buffers in 16 byte lines. */ +#define PBF_REG_P1_INIT_CRD 0x1400d4 +/* [R 32] Cyclic counter for the amount credits in 16 bytes lines added for + * port 1. Reset upon init. */ +#define PBF_REG_P1_INTERNAL_CRD_FREED_CNT 0x14030c +/* [R 8] Removed for E3 B0 - Number of tasks in port 1 task queue. */ +#define PBF_REG_P1_TASK_CNT 0x14020c +/* [R 32] Removed for E3 B0 - Cyclic counter for number of 8 byte lines + * freed from the task queue of port 1. Reset upon init. */ +#define PBF_REG_P1_TQ_LINES_FREED_CNT 0x1402f4 +/* [R 12] Number of 8 bytes lines occupied in the task queue of port 1. */ +#define PBF_REG_P1_TQ_OCCUPANCY 0x140300 +/* [R 11] Current credit for port 4 in the tx port buffers in 16 byte lines. */ +#define PBF_REG_P4_CREDIT 0x140210 +/* [RW 11] Initial credit for port 4 in the tx port buffers in 16 byte + lines. */ +#define PBF_REG_P4_INIT_CRD 0x1400e0 +/* [R 32] Cyclic counter for the amount credits in 16 bytes lines added for + * port 4. Reset upon init. */ +#define PBF_REG_P4_INTERNAL_CRD_FREED_CNT 0x140310 +/* [R 8] Removed for E3 B0 - Number of tasks in port 4 task queue. */ +#define PBF_REG_P4_TASK_CNT 0x140214 +/* [R 32] Removed for E3 B0 - Cyclic counter for number of 8 byte lines + * freed from the task queue of port 4. Reset upon init. */ +#define PBF_REG_P4_TQ_LINES_FREED_CNT 0x1402f8 +/* [R 12] Number of 8 bytes lines occupied in the task queue of port 4. */ +#define PBF_REG_P4_TQ_OCCUPANCY 0x140304 +/* [RW 5] Interrupt mask register #0 read/write */ +#define PBF_REG_PBF_INT_MASK 0x1401d4 +/* [R 5] Interrupt register #0 read */ +#define PBF_REG_PBF_INT_STS 0x1401c8 +/* [RW 20] Parity mask register #0 read/write */ +#define PBF_REG_PBF_PRTY_MASK 0x1401e4 +/* [RC 20] Parity register #0 read clear */ +#define PBF_REG_PBF_PRTY_STS_CLR 0x1401dc +/* [RW 16] The Ethernet type value for L2 tag 0 */ +#define PBF_REG_TAG_ETHERTYPE_0 0x15c090 +/* [RW 4] The length of the info field for L2 tag 0. The length is between + * 2B and 14B; in 2B granularity */ +#define PBF_REG_TAG_LEN_0 0x15c09c +/* [R 32] Cyclic counter for number of 8 byte lines freed from the LB task + * queue. Reset upon init. */ +#define PBF_REG_TQ_LINES_FREED_CNT_LB_Q 0x14038c +/* [R 32] Cyclic counter for number of 8 byte lines freed from the task + * queue 0. Reset upon init. */ +#define PBF_REG_TQ_LINES_FREED_CNT_Q0 0x140390 +/* [R 32] Cyclic counter for number of 8 byte lines freed from task queue 1. + * Reset upon init. */ +#define PBF_REG_TQ_LINES_FREED_CNT_Q1 0x140394 +/* [R 13] Number of 8 bytes lines occupied in the task queue of the LB + * queue. */ +#define PBF_REG_TQ_OCCUPANCY_LB_Q 0x1403a8 +/* [R 13] Number of 8 bytes lines occupied in the task queue of queue 0. */ +#define PBF_REG_TQ_OCCUPANCY_Q0 0x1403ac +/* [R 13] Number of 8 bytes lines occupied in the task queue of queue 1. */ +#define PBF_REG_TQ_OCCUPANCY_Q1 0x1403b0 +#define PB_REG_CONTROL 0 +/* [RW 2] Interrupt mask register #0 read/write */ +#define PB_REG_PB_INT_MASK 0x28 +/* [R 2] Interrupt register #0 read */ +#define PB_REG_PB_INT_STS 0x1c +/* [RW 4] Parity mask register #0 read/write */ +#define PB_REG_PB_PRTY_MASK 0x38 +/* [R 4] Parity register #0 read */ +#define PB_REG_PB_PRTY_STS 0x2c +/* [RC 4] Parity register #0 read clear */ +#define PB_REG_PB_PRTY_STS_CLR 0x30 +#define PGLUE_B_PGLUE_B_INT_STS_REG_ADDRESS_ERROR (0x1<<0) +#define PGLUE_B_PGLUE_B_INT_STS_REG_CSSNOOP_FIFO_OVERFLOW (0x1<<8) +#define PGLUE_B_PGLUE_B_INT_STS_REG_INCORRECT_RCV_BEHAVIOR (0x1<<1) +#define PGLUE_B_PGLUE_B_INT_STS_REG_TCPL_ERROR_ATTN (0x1<<6) +#define PGLUE_B_PGLUE_B_INT_STS_REG_TCPL_IN_TWO_RCBS_ATTN (0x1<<7) +#define PGLUE_B_PGLUE_B_INT_STS_REG_VF_GRC_SPACE_VIOLATION_ATTN (0x1<<4) +#define PGLUE_B_PGLUE_B_INT_STS_REG_VF_LENGTH_VIOLATION_ATTN (0x1<<3) +#define PGLUE_B_PGLUE_B_INT_STS_REG_VF_MSIX_BAR_VIOLATION_ATTN (0x1<<5) +#define PGLUE_B_PGLUE_B_INT_STS_REG_WAS_ERROR_ATTN (0x1<<2) +/* [R 8] Config space A attention dirty bits. Each bit indicates that the + * corresponding PF generates config space A attention. Set by PXP. Reset by + * MCP writing 1 to icfg_space_a_request_clr. Note: register contains bits + * from both paths. */ +#define PGLUE_B_REG_CFG_SPACE_A_REQUEST 0x9010 +/* [R 8] Config space B attention dirty bits. Each bit indicates that the + * corresponding PF generates config space B attention. Set by PXP. Reset by + * MCP writing 1 to icfg_space_b_request_clr. Note: register contains bits + * from both paths. */ +#define PGLUE_B_REG_CFG_SPACE_B_REQUEST 0x9014 +/* [RW 1] Type A PF enable inbound interrupt table for CSDM. 0 - disable; 1 + * - enable. */ +#define PGLUE_B_REG_CSDM_INB_INT_A_PF_ENABLE 0x9194 +/* [RW 18] Type B VF inbound interrupt table for CSDM: bits[17:9]-mask; + * its[8:0]-address. Bits [1:0] must be zero (DW resolution address). */ +#define PGLUE_B_REG_CSDM_INB_INT_B_VF 0x916c +/* [RW 1] Type B VF enable inbound interrupt table for CSDM. 0 - disable; 1 + * - enable. */ +#define PGLUE_B_REG_CSDM_INB_INT_B_VF_ENABLE 0x919c +/* [RW 16] Start offset of CSDM zone A (queue zone) in the internal RAM */ +#define PGLUE_B_REG_CSDM_START_OFFSET_A 0x9100 +/* [RW 16] Start offset of CSDM zone B (legacy zone) in the internal RAM */ +#define PGLUE_B_REG_CSDM_START_OFFSET_B 0x9108 +/* [RW 5] VF Shift of CSDM zone B (legacy zone) in the internal RAM */ +#define PGLUE_B_REG_CSDM_VF_SHIFT_B 0x9110 +/* [RW 1] 0 - Zone A size is 136x32B; 1 - Zone A size is 152x32B. */ +#define PGLUE_B_REG_CSDM_ZONE_A_SIZE_PF 0x91ac +/* [R 8] FLR request attention dirty bits for PFs 0 to 7. Each bit indicates + * that the FLR register of the corresponding PF was set. Set by PXP. Reset + * by MCP writing 1 to flr_request_pf_7_0_clr. Note: register contains bits + * from both paths. */ +#define PGLUE_B_REG_FLR_REQUEST_PF_7_0 0x9028 +/* [W 8] FLR request attention dirty bits clear for PFs 0 to 7. MCP writes 1 + * to a bit in this register in order to clear the corresponding bit in + * flr_request_pf_7_0 register. Note: register contains bits from both + * paths. */ +#define PGLUE_B_REG_FLR_REQUEST_PF_7_0_CLR 0x9418 +/* [R 32] FLR request attention dirty bits for VFs 96 to 127. Each bit + * indicates that the FLR register of the corresponding VF was set. Set by + * PXP. Reset by MCP writing 1 to flr_request_vf_127_96_clr. */ +#define PGLUE_B_REG_FLR_REQUEST_VF_127_96 0x9024 +/* [R 32] FLR request attention dirty bits for VFs 0 to 31. Each bit + * indicates that the FLR register of the corresponding VF was set. Set by + * PXP. Reset by MCP writing 1 to flr_request_vf_31_0_clr. */ +#define PGLUE_B_REG_FLR_REQUEST_VF_31_0 0x9018 +/* [R 32] FLR request attention dirty bits for VFs 32 to 63. Each bit + * indicates that the FLR register of the corresponding VF was set. Set by + * PXP. Reset by MCP writing 1 to flr_request_vf_63_32_clr. */ +#define PGLUE_B_REG_FLR_REQUEST_VF_63_32 0x901c +/* [R 32] FLR request attention dirty bits for VFs 64 to 95. Each bit + * indicates that the FLR register of the corresponding VF was set. Set by + * PXP. Reset by MCP writing 1 to flr_request_vf_95_64_clr. */ +#define PGLUE_B_REG_FLR_REQUEST_VF_95_64 0x9020 +/* [R 8] Each bit indicates an incorrect behavior in user RX interface. Bit + * 0 - Target memory read arrived with a correctable error. Bit 1 - Target + * memory read arrived with an uncorrectable error. Bit 2 - Configuration RW + * arrived with a correctable error. Bit 3 - Configuration RW arrived with + * an uncorrectable error. Bit 4 - Completion with Configuration Request + * Retry Status. Bit 5 - Expansion ROM access received with a write request. + * Bit 6 - Completion with pcie_rx_err of 0000; CMPL_STATUS of non-zero; and + * pcie_rx_last not asserted. Bit 7 - Completion with pcie_rx_err of 1010; + * and pcie_rx_last not asserted. */ +#define PGLUE_B_REG_INCORRECT_RCV_DETAILS 0x9068 +#define PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER 0x942c +#define PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_READ 0x9430 +#define PGLUE_B_REG_INTERNAL_PFID_ENABLE_TARGET_WRITE 0x9434 +#define PGLUE_B_REG_INTERNAL_VFID_ENABLE 0x9438 +/* [R 9] Interrupt register #0 read */ +#define PGLUE_B_REG_PGLUE_B_INT_STS 0x9298 +/* [RC 9] Interrupt register #0 read clear */ +#define PGLUE_B_REG_PGLUE_B_INT_STS_CLR 0x929c +/* [RW 2] Parity mask register #0 read/write */ +#define PGLUE_B_REG_PGLUE_B_PRTY_MASK 0x92b4 +/* [R 2] Parity register #0 read */ +#define PGLUE_B_REG_PGLUE_B_PRTY_STS 0x92a8 +/* [RC 2] Parity register #0 read clear */ +#define PGLUE_B_REG_PGLUE_B_PRTY_STS_CLR 0x92ac +/* [R 13] Details of first request received with error. [2:0] - PFID. [3] - + * VF_VALID. [9:4] - VFID. [11:10] - Error Code - 0 - Indicates Completion + * Timeout of a User Tx non-posted request. 1 - unsupported request. 2 - + * completer abort. 3 - Illegal value for this field. [12] valid - indicates + * if there was a completion error since the last time this register was + * cleared. */ +#define PGLUE_B_REG_RX_ERR_DETAILS 0x9080 +/* [R 18] Details of first ATS Translation Completion request received with + * error. [2:0] - PFID. [3] - VF_VALID. [9:4] - VFID. [11:10] - Error Code - + * 0 - Indicates Completion Timeout of a User Tx non-posted request. 1 - + * unsupported request. 2 - completer abort. 3 - Illegal value for this + * field. [16:12] - ATC OTB EntryID. [17] valid - indicates if there was a + * completion error since the last time this register was cleared. */ +#define PGLUE_B_REG_RX_TCPL_ERR_DETAILS 0x9084 +/* [W 8] Debug only - Shadow BME bits clear for PFs 0 to 7. MCP writes 1 to + * a bit in this register in order to clear the corresponding bit in + * shadow_bme_pf_7_0 register. MCP should never use this unless a + * work-around is needed. Note: register contains bits from both paths. */ +#define PGLUE_B_REG_SHADOW_BME_PF_7_0_CLR 0x9458 +/* [R 8] SR IOV disabled attention dirty bits. Each bit indicates that the + * VF enable register of the corresponding PF is written to 0 and was + * previously 1. Set by PXP. Reset by MCP writing 1 to + * sr_iov_disabled_request_clr. Note: register contains bits from both + * paths. */ +#define PGLUE_B_REG_SR_IOV_DISABLED_REQUEST 0x9030 +/* [R 32] Indicates the status of tags 32-63. 0 - tags is used - read + * completion did not return yet. 1 - tag is unused. Same functionality as + * pxp2_registers_pgl_exp_rom_data2 for tags 0-31. */ +#define PGLUE_B_REG_TAGS_63_32 0x9244 +/* [RW 1] Type A PF enable inbound interrupt table for TSDM. 0 - disable; 1 + * - enable. */ +#define PGLUE_B_REG_TSDM_INB_INT_A_PF_ENABLE 0x9170 +/* [RW 16] Start offset of TSDM zone A (queue zone) in the internal RAM */ +#define PGLUE_B_REG_TSDM_START_OFFSET_A 0x90c4 +/* [RW 16] Start offset of TSDM zone B (legacy zone) in the internal RAM */ +#define PGLUE_B_REG_TSDM_START_OFFSET_B 0x90cc +/* [RW 5] VF Shift of TSDM zone B (legacy zone) in the internal RAM */ +#define PGLUE_B_REG_TSDM_VF_SHIFT_B 0x90d4 +/* [RW 1] 0 - Zone A size is 136x32B; 1 - Zone A size is 152x32B. */ +#define PGLUE_B_REG_TSDM_ZONE_A_SIZE_PF 0x91a0 +/* [R 32] Address [31:0] of first read request not submitted due to error */ +#define PGLUE_B_REG_TX_ERR_RD_ADD_31_0 0x9098 +/* [R 32] Address [63:32] of first read request not submitted due to error */ +#define PGLUE_B_REG_TX_ERR_RD_ADD_63_32 0x909c +/* [R 31] Details of first read request not submitted due to error. [4:0] + * VQID. [5] TREQ. 1 - Indicates the request is a Translation Request. + * [20:8] - Length in bytes. [23:21] - PFID. [24] - VF_VALID. [30:25] - + * VFID. */ +#define PGLUE_B_REG_TX_ERR_RD_DETAILS 0x90a0 +/* [R 26] Details of first read request not submitted due to error. [15:0] + * Request ID. [19:16] client ID. [20] - last SR. [24:21] - Error type - + * [21] - Indicates was_error was set; [22] - Indicates BME was cleared; + * [23] - Indicates FID_enable was cleared; [24] - Indicates VF with parent + * PF FLR_request or IOV_disable_request dirty bit is set. [25] valid - + * indicates if there was a request not submitted due to error since the + * last time this register was cleared. */ +#define PGLUE_B_REG_TX_ERR_RD_DETAILS2 0x90a4 +/* [R 32] Address [31:0] of first write request not submitted due to error */ +#define PGLUE_B_REG_TX_ERR_WR_ADD_31_0 0x9088 +/* [R 32] Address [63:32] of first write request not submitted due to error */ +#define PGLUE_B_REG_TX_ERR_WR_ADD_63_32 0x908c +/* [R 31] Details of first write request not submitted due to error. [4:0] + * VQID. [20:8] - Length in bytes. [23:21] - PFID. [24] - VF_VALID. [30:25] + * - VFID. */ +#define PGLUE_B_REG_TX_ERR_WR_DETAILS 0x9090 +/* [R 26] Details of first write request not submitted due to error. [15:0] + * Request ID. [19:16] client ID. [20] - last SR. [24:21] - Error type - + * [21] - Indicates was_error was set; [22] - Indicates BME was cleared; + * [23] - Indicates FID_enable was cleared; [24] - Indicates VF with parent + * PF FLR_request or IOV_disable_request dirty bit is set. [25] valid - + * indicates if there was a request not submitted due to error since the + * last time this register was cleared. */ +#define PGLUE_B_REG_TX_ERR_WR_DETAILS2 0x9094 +/* [RW 10] Type A PF/VF inbound interrupt table for USDM: bits[9:5]-mask; + * its[4:0]-address relative to start_offset_a. Bits [1:0] can have any + * value (Byte resolution address). */ +#define PGLUE_B_REG_USDM_INB_INT_A_0 0x9128 +#define PGLUE_B_REG_USDM_INB_INT_A_1 0x912c +#define PGLUE_B_REG_USDM_INB_INT_A_2 0x9130 +#define PGLUE_B_REG_USDM_INB_INT_A_3 0x9134 +#define PGLUE_B_REG_USDM_INB_INT_A_4 0x9138 +#define PGLUE_B_REG_USDM_INB_INT_A_5 0x913c +#define PGLUE_B_REG_USDM_INB_INT_A_6 0x9140 +/* [RW 1] Type A PF enable inbound interrupt table for USDM. 0 - disable; 1 + * - enable. */ +#define PGLUE_B_REG_USDM_INB_INT_A_PF_ENABLE 0x917c +/* [RW 1] Type A VF enable inbound interrupt table for USDM. 0 - disable; 1 + * - enable. */ +#define PGLUE_B_REG_USDM_INB_INT_A_VF_ENABLE 0x9180 +/* [RW 1] Type B VF enable inbound interrupt table for USDM. 0 - disable; 1 + * - enable. */ +#define PGLUE_B_REG_USDM_INB_INT_B_VF_ENABLE 0x9184 +/* [RW 16] Start offset of USDM zone A (queue zone) in the internal RAM */ +#define PGLUE_B_REG_USDM_START_OFFSET_A 0x90d8 +/* [RW 16] Start offset of USDM zone B (legacy zone) in the internal RAM */ +#define PGLUE_B_REG_USDM_START_OFFSET_B 0x90e0 +/* [RW 5] VF Shift of USDM zone B (legacy zone) in the internal RAM */ +#define PGLUE_B_REG_USDM_VF_SHIFT_B 0x90e8 +/* [RW 1] 0 - Zone A size is 136x32B; 1 - Zone A size is 152x32B. */ +#define PGLUE_B_REG_USDM_ZONE_A_SIZE_PF 0x91a4 +/* [R 26] Details of first target VF request accessing VF GRC space that + * failed permission check. [14:0] Address. [15] w_nr: 0 - Read; 1 - Write. + * [21:16] VFID. [24:22] - PFID. [25] valid - indicates if there was a + * request accessing VF GRC space that failed permission check since the + * last time this register was cleared. Permission checks are: function + * permission; R/W permission; address range permission. */ +#define PGLUE_B_REG_VF_GRC_SPACE_VIOLATION_DETAILS 0x9234 +/* [R 31] Details of first target VF request with length violation (too many + * DWs) accessing BAR0. [12:0] Address in DWs (bits [14:2] of byte address). + * [14:13] BAR. [20:15] VFID. [23:21] - PFID. [29:24] - Length in DWs. [30] + * valid - indicates if there was a request with length violation since the + * last time this register was cleared. Length violations: length of more + * than 2DWs; length of 2DWs and address not QW aligned; window is GRC and + * length is more than 1 DW. */ +#define PGLUE_B_REG_VF_LENGTH_VIOLATION_DETAILS 0x9230 +/* [R 8] Was_error indication dirty bits for PFs 0 to 7. Each bit indicates + * that there was a completion with uncorrectable error for the + * corresponding PF. Set by PXP. Reset by MCP writing 1 to + * was_error_pf_7_0_clr. */ +#define PGLUE_B_REG_WAS_ERROR_PF_7_0 0x907c +/* [W 8] Was_error indication dirty bits clear for PFs 0 to 7. MCP writes 1 + * to a bit in this register in order to clear the corresponding bit in + * flr_request_pf_7_0 register. */ +#define PGLUE_B_REG_WAS_ERROR_PF_7_0_CLR 0x9470 +/* [R 32] Was_error indication dirty bits for VFs 96 to 127. Each bit + * indicates that there was a completion with uncorrectable error for the + * corresponding VF. Set by PXP. Reset by MCP writing 1 to + * was_error_vf_127_96_clr. */ +#define PGLUE_B_REG_WAS_ERROR_VF_127_96 0x9078 +/* [W 32] Was_error indication dirty bits clear for VFs 96 to 127. MCP + * writes 1 to a bit in this register in order to clear the corresponding + * bit in was_error_vf_127_96 register. */ +#define PGLUE_B_REG_WAS_ERROR_VF_127_96_CLR 0x9474 +/* [R 32] Was_error indication dirty bits for VFs 0 to 31. Each bit + * indicates that there was a completion with uncorrectable error for the + * corresponding VF. Set by PXP. Reset by MCP writing 1 to + * was_error_vf_31_0_clr. */ +#define PGLUE_B_REG_WAS_ERROR_VF_31_0 0x906c +/* [W 32] Was_error indication dirty bits clear for VFs 0 to 31. MCP writes + * 1 to a bit in this register in order to clear the corresponding bit in + * was_error_vf_31_0 register. */ +#define PGLUE_B_REG_WAS_ERROR_VF_31_0_CLR 0x9478 +/* [R 32] Was_error indication dirty bits for VFs 32 to 63. Each bit + * indicates that there was a completion with uncorrectable error for the + * corresponding VF. Set by PXP. Reset by MCP writing 1 to + * was_error_vf_63_32_clr. */ +#define PGLUE_B_REG_WAS_ERROR_VF_63_32 0x9070 +/* [W 32] Was_error indication dirty bits clear for VFs 32 to 63. MCP writes + * 1 to a bit in this register in order to clear the corresponding bit in + * was_error_vf_63_32 register. */ +#define PGLUE_B_REG_WAS_ERROR_VF_63_32_CLR 0x947c +/* [R 32] Was_error indication dirty bits for VFs 64 to 95. Each bit + * indicates that there was a completion with uncorrectable error for the + * corresponding VF. Set by PXP. Reset by MCP writing 1 to + * was_error_vf_95_64_clr. */ +#define PGLUE_B_REG_WAS_ERROR_VF_95_64 0x9074 +/* [W 32] Was_error indication dirty bits clear for VFs 64 to 95. MCP writes + * 1 to a bit in this register in order to clear the corresponding bit in + * was_error_vf_95_64 register. */ +#define PGLUE_B_REG_WAS_ERROR_VF_95_64_CLR 0x9480 +/* [RW 1] Type A PF enable inbound interrupt table for XSDM. 0 - disable; 1 + * - enable. */ +#define PGLUE_B_REG_XSDM_INB_INT_A_PF_ENABLE 0x9188 +/* [RW 16] Start offset of XSDM zone A (queue zone) in the internal RAM */ +#define PGLUE_B_REG_XSDM_START_OFFSET_A 0x90ec +/* [RW 16] Start offset of XSDM zone B (legacy zone) in the internal RAM */ +#define PGLUE_B_REG_XSDM_START_OFFSET_B 0x90f4 +/* [RW 5] VF Shift of XSDM zone B (legacy zone) in the internal RAM */ +#define PGLUE_B_REG_XSDM_VF_SHIFT_B 0x90fc +/* [RW 1] 0 - Zone A size is 136x32B; 1 - Zone A size is 152x32B. */ +#define PGLUE_B_REG_XSDM_ZONE_A_SIZE_PF 0x91a8 +#define PRS_REG_A_PRSU_20 0x40134 +/* [R 8] debug only: CFC load request current credit. Transaction based. */ +#define PRS_REG_CFC_LD_CURRENT_CREDIT 0x40164 +/* [R 8] debug only: CFC search request current credit. Transaction based. */ +#define PRS_REG_CFC_SEARCH_CURRENT_CREDIT 0x40168 +/* [RW 6] The initial credit for the search message to the CFC interface. + Credit is transaction based. */ +#define PRS_REG_CFC_SEARCH_INITIAL_CREDIT 0x4011c +/* [RW 24] CID for port 0 if no match */ +#define PRS_REG_CID_PORT_0 0x400fc +/* [RW 32] The CM header for flush message where 'load existed' bit in CFC + load response is reset and packet type is 0. Used in packet start message + to TCM. */ +#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_0 0x400dc +#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_1 0x400e0 +#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_2 0x400e4 +#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_3 0x400e8 +#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_4 0x400ec +#define PRS_REG_CM_HDR_FLUSH_LOAD_TYPE_5 0x400f0 +/* [RW 32] The CM header for flush message where 'load existed' bit in CFC + load response is set and packet type is 0. Used in packet start message + to TCM. */ +#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_0 0x400bc +#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_1 0x400c0 +#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_2 0x400c4 +#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_3 0x400c8 +#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_4 0x400cc +#define PRS_REG_CM_HDR_FLUSH_NO_LOAD_TYPE_5 0x400d0 +/* [RW 32] The CM header for a match and packet type 1 for loopback port. + Used in packet start message to TCM. */ +#define PRS_REG_CM_HDR_LOOPBACK_TYPE_1 0x4009c +#define PRS_REG_CM_HDR_LOOPBACK_TYPE_2 0x400a0 +#define PRS_REG_CM_HDR_LOOPBACK_TYPE_3 0x400a4 +#define PRS_REG_CM_HDR_LOOPBACK_TYPE_4 0x400a8 +/* [RW 32] The CM header for a match and packet type 0. Used in packet start + message to TCM. */ +#define PRS_REG_CM_HDR_TYPE_0 0x40078 +#define PRS_REG_CM_HDR_TYPE_1 0x4007c +#define PRS_REG_CM_HDR_TYPE_2 0x40080 +#define PRS_REG_CM_HDR_TYPE_3 0x40084 +#define PRS_REG_CM_HDR_TYPE_4 0x40088 +/* [RW 32] The CM header in case there was not a match on the connection */ +#define PRS_REG_CM_NO_MATCH_HDR 0x400b8 +/* [RW 1] Indicates if in e1hov mode. 0=non-e1hov mode; 1=e1hov mode. */ +#define PRS_REG_E1HOV_MODE 0x401c8 +/* [RW 8] The 8-bit event ID for a match and packet type 1. Used in packet + start message to TCM. */ +#define PRS_REG_EVENT_ID_1 0x40054 +#define PRS_REG_EVENT_ID_2 0x40058 +#define PRS_REG_EVENT_ID_3 0x4005c +/* [RW 16] The Ethernet type value for FCoE */ +#define PRS_REG_FCOE_TYPE 0x401d0 +/* [RW 8] Context region for flush packet with packet type 0. Used in CFC + load request message. */ +#define PRS_REG_FLUSH_REGIONS_TYPE_0 0x40004 +#define PRS_REG_FLUSH_REGIONS_TYPE_1 0x40008 +#define PRS_REG_FLUSH_REGIONS_TYPE_2 0x4000c +#define PRS_REG_FLUSH_REGIONS_TYPE_3 0x40010 +#define PRS_REG_FLUSH_REGIONS_TYPE_4 0x40014 +#define PRS_REG_FLUSH_REGIONS_TYPE_5 0x40018 +#define PRS_REG_FLUSH_REGIONS_TYPE_6 0x4001c +#define PRS_REG_FLUSH_REGIONS_TYPE_7 0x40020 +/* [RW 6] Bit-map indicating which L2 hdrs may appear after the basic + * Ethernet header. */ +#define PRS_REG_HDRS_AFTER_BASIC 0x40238 +/* [RW 6] Bit-map indicating which L2 hdrs may appear after the basic + * Ethernet header for port 0 packets. */ +#define PRS_REG_HDRS_AFTER_BASIC_PORT_0 0x40270 +#define PRS_REG_HDRS_AFTER_BASIC_PORT_1 0x40290 +/* [R 6] Bit-map indicating which L2 hdrs may appear after L2 tag 0 */ +#define PRS_REG_HDRS_AFTER_TAG_0 0x40248 +/* [RW 6] Bit-map indicating which L2 hdrs may appear after L2 tag 0 for + * port 0 packets */ +#define PRS_REG_HDRS_AFTER_TAG_0_PORT_0 0x40280 +#define PRS_REG_HDRS_AFTER_TAG_0_PORT_1 0x402a0 +/* [RW 4] The increment value to send in the CFC load request message */ +#define PRS_REG_INC_VALUE 0x40048 +/* [RW 6] Bit-map indicating which headers must appear in the packet */ +#define PRS_REG_MUST_HAVE_HDRS 0x40254 +/* [RW 6] Bit-map indicating which headers must appear in the packet for + * port 0 packets */ +#define PRS_REG_MUST_HAVE_HDRS_PORT_0 0x4028c +#define PRS_REG_MUST_HAVE_HDRS_PORT_1 0x402ac +#define PRS_REG_NIC_MODE 0x40138 +/* [RW 8] The 8-bit event ID for cases where there is no match on the + connection. Used in packet start message to TCM. */ +#define PRS_REG_NO_MATCH_EVENT_ID 0x40070 +/* [ST 24] The number of input CFC flush packets */ +#define PRS_REG_NUM_OF_CFC_FLUSH_MESSAGES 0x40128 +/* [ST 32] The number of cycles the Parser halted its operation since it + could not allocate the next serial number */ +#define PRS_REG_NUM_OF_DEAD_CYCLES 0x40130 +/* [ST 24] The number of input packets */ +#define PRS_REG_NUM_OF_PACKETS 0x40124 +/* [ST 24] The number of input transparent flush packets */ +#define PRS_REG_NUM_OF_TRANSPARENT_FLUSH_MESSAGES 0x4012c +/* [RW 8] Context region for received Ethernet packet with a match and + packet type 0. Used in CFC load request message */ +#define PRS_REG_PACKET_REGIONS_TYPE_0 0x40028 +#define PRS_REG_PACKET_REGIONS_TYPE_1 0x4002c +#define PRS_REG_PACKET_REGIONS_TYPE_2 0x40030 +#define PRS_REG_PACKET_REGIONS_TYPE_3 0x40034 +#define PRS_REG_PACKET_REGIONS_TYPE_4 0x40038 +#define PRS_REG_PACKET_REGIONS_TYPE_5 0x4003c +#define PRS_REG_PACKET_REGIONS_TYPE_6 0x40040 +#define PRS_REG_PACKET_REGIONS_TYPE_7 0x40044 +/* [R 2] debug only: Number of pending requests for CAC on port 0. */ +#define PRS_REG_PENDING_BRB_CAC0_RQ 0x40174 +/* [R 2] debug only: Number of pending requests for header parsing. */ +#define PRS_REG_PENDING_BRB_PRS_RQ 0x40170 +/* [R 1] Interrupt register #0 read */ +#define PRS_REG_PRS_INT_STS 0x40188 +/* [RW 8] Parity mask register #0 read/write */ +#define PRS_REG_PRS_PRTY_MASK 0x401a4 +/* [R 8] Parity register #0 read */ +#define PRS_REG_PRS_PRTY_STS 0x40198 +/* [RC 8] Parity register #0 read clear */ +#define PRS_REG_PRS_PRTY_STS_CLR 0x4019c +/* [RW 8] Context region for pure acknowledge packets. Used in CFC load + request message */ +#define PRS_REG_PURE_REGIONS 0x40024 +/* [R 32] debug only: Serial number status lsb 32 bits. '1' indicates this + serail number was released by SDM but cannot be used because a previous + serial number was not released. */ +#define PRS_REG_SERIAL_NUM_STATUS_LSB 0x40154 +/* [R 32] debug only: Serial number status msb 32 bits. '1' indicates this + serail number was released by SDM but cannot be used because a previous + serial number was not released. */ +#define PRS_REG_SERIAL_NUM_STATUS_MSB 0x40158 +/* [R 4] debug only: SRC current credit. Transaction based. */ +#define PRS_REG_SRC_CURRENT_CREDIT 0x4016c +/* [RW 16] The Ethernet type value for L2 tag 0 */ +#define PRS_REG_TAG_ETHERTYPE_0 0x401d4 +/* [RW 4] The length of the info field for L2 tag 0. The length is between + * 2B and 14B; in 2B granularity */ +#define PRS_REG_TAG_LEN_0 0x4022c +/* [R 8] debug only: TCM current credit. Cycle based. */ +#define PRS_REG_TCM_CURRENT_CREDIT 0x40160 +/* [R 8] debug only: TSDM current credit. Transaction based. */ +#define PRS_REG_TSDM_CURRENT_CREDIT 0x4015c +#define PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_AFT (0x1<<19) +#define PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_OF (0x1<<20) +#define PXP2_PXP2_INT_MASK_0_REG_PGL_PCIE_ATTN (0x1<<22) +#define PXP2_PXP2_INT_MASK_0_REG_PGL_READ_BLOCKED (0x1<<23) +#define PXP2_PXP2_INT_MASK_0_REG_PGL_WRITE_BLOCKED (0x1<<24) +#define PXP2_PXP2_INT_STS_0_REG_WR_PGLUE_EOP_ERROR (0x1<<7) +#define PXP2_PXP2_INT_STS_CLR_0_REG_WR_PGLUE_EOP_ERROR (0x1<<7) +/* [R 6] Debug only: Number of used entries in the data FIFO */ +#define PXP2_REG_HST_DATA_FIFO_STATUS 0x12047c +/* [R 7] Debug only: Number of used entries in the header FIFO */ +#define PXP2_REG_HST_HEADER_FIFO_STATUS 0x120478 +#define PXP2_REG_PGL_ADDR_88_F0 0x120534 +#define PXP2_REG_PGL_ADDR_8C_F0 0x120538 +#define PXP2_REG_PGL_ADDR_90_F0 0x12053c +#define PXP2_REG_PGL_ADDR_94_F0 0x120540 +#define PXP2_REG_PGL_CONTROL0 0x120490 +#define PXP2_REG_PGL_CONTROL1 0x120514 +#define PXP2_REG_PGL_DEBUG 0x120520 +/* [RW 32] third dword data of expansion rom request. this register is + special. reading from it provides a vector outstanding read requests. if + a bit is zero it means that a read request on the corresponding tag did + not finish yet (not all completions have arrived for it) */ +#define PXP2_REG_PGL_EXP_ROM2 0x120808 +/* [RW 32] Inbound interrupt table for CSDM: bits[31:16]-mask; + its[15:0]-address */ +#define PXP2_REG_PGL_INT_CSDM_0 0x1204f4 +#define PXP2_REG_PGL_INT_CSDM_1 0x1204f8 +#define PXP2_REG_PGL_INT_CSDM_2 0x1204fc +#define PXP2_REG_PGL_INT_CSDM_3 0x120500 +#define PXP2_REG_PGL_INT_CSDM_4 0x120504 +#define PXP2_REG_PGL_INT_CSDM_5 0x120508 +#define PXP2_REG_PGL_INT_CSDM_6 0x12050c +#define PXP2_REG_PGL_INT_CSDM_7 0x120510 +/* [RW 32] Inbound interrupt table for TSDM: bits[31:16]-mask; + its[15:0]-address */ +#define PXP2_REG_PGL_INT_TSDM_0 0x120494 +#define PXP2_REG_PGL_INT_TSDM_1 0x120498 +#define PXP2_REG_PGL_INT_TSDM_2 0x12049c +#define PXP2_REG_PGL_INT_TSDM_3 0x1204a0 +#define PXP2_REG_PGL_INT_TSDM_4 0x1204a4 +#define PXP2_REG_PGL_INT_TSDM_5 0x1204a8 +#define PXP2_REG_PGL_INT_TSDM_6 0x1204ac +#define PXP2_REG_PGL_INT_TSDM_7 0x1204b0 +/* [RW 32] Inbound interrupt table for USDM: bits[31:16]-mask; + its[15:0]-address */ +#define PXP2_REG_PGL_INT_USDM_0 0x1204b4 +#define PXP2_REG_PGL_INT_USDM_1 0x1204b8 +#define PXP2_REG_PGL_INT_USDM_2 0x1204bc +#define PXP2_REG_PGL_INT_USDM_3 0x1204c0 +#define PXP2_REG_PGL_INT_USDM_4 0x1204c4 +#define PXP2_REG_PGL_INT_USDM_5 0x1204c8 +#define PXP2_REG_PGL_INT_USDM_6 0x1204cc +#define PXP2_REG_PGL_INT_USDM_7 0x1204d0 +/* [RW 32] Inbound interrupt table for XSDM: bits[31:16]-mask; + its[15:0]-address */ +#define PXP2_REG_PGL_INT_XSDM_0 0x1204d4 +#define PXP2_REG_PGL_INT_XSDM_1 0x1204d8 +#define PXP2_REG_PGL_INT_XSDM_2 0x1204dc +#define PXP2_REG_PGL_INT_XSDM_3 0x1204e0 +#define PXP2_REG_PGL_INT_XSDM_4 0x1204e4 +#define PXP2_REG_PGL_INT_XSDM_5 0x1204e8 +#define PXP2_REG_PGL_INT_XSDM_6 0x1204ec +#define PXP2_REG_PGL_INT_XSDM_7 0x1204f0 +/* [RW 3] this field allows one function to pretend being another function + when accessing any BAR mapped resource within the device. the value of + the field is the number of the function that will be accessed + effectively. after software write to this bit it must read it in order to + know that the new value is updated */ +#define PXP2_REG_PGL_PRETEND_FUNC_F0 0x120674 +#define PXP2_REG_PGL_PRETEND_FUNC_F1 0x120678 +#define PXP2_REG_PGL_PRETEND_FUNC_F2 0x12067c +#define PXP2_REG_PGL_PRETEND_FUNC_F3 0x120680 +#define PXP2_REG_PGL_PRETEND_FUNC_F4 0x120684 +#define PXP2_REG_PGL_PRETEND_FUNC_F5 0x120688 +#define PXP2_REG_PGL_PRETEND_FUNC_F6 0x12068c +#define PXP2_REG_PGL_PRETEND_FUNC_F7 0x120690 +/* [R 1] this bit indicates that a read request was blocked because of + bus_master_en was deasserted */ +#define PXP2_REG_PGL_READ_BLOCKED 0x120568 +#define PXP2_REG_PGL_TAGS_LIMIT 0x1205a8 +/* [R 18] debug only */ +#define PXP2_REG_PGL_TXW_CDTS 0x12052c +/* [R 1] this bit indicates that a write request was blocked because of + bus_master_en was deasserted */ +#define PXP2_REG_PGL_WRITE_BLOCKED 0x120564 +#define PXP2_REG_PSWRQ_BW_ADD1 0x1201c0 +#define PXP2_REG_PSWRQ_BW_ADD10 0x1201e4 +#define PXP2_REG_PSWRQ_BW_ADD11 0x1201e8 +#define PXP2_REG_PSWRQ_BW_ADD2 0x1201c4 +#define PXP2_REG_PSWRQ_BW_ADD28 0x120228 +#define PXP2_REG_PSWRQ_BW_ADD3 0x1201c8 +#define PXP2_REG_PSWRQ_BW_ADD6 0x1201d4 +#define PXP2_REG_PSWRQ_BW_ADD7 0x1201d8 +#define PXP2_REG_PSWRQ_BW_ADD8 0x1201dc +#define PXP2_REG_PSWRQ_BW_ADD9 0x1201e0 +#define PXP2_REG_PSWRQ_BW_CREDIT 0x12032c +#define PXP2_REG_PSWRQ_BW_L1 0x1202b0 +#define PXP2_REG_PSWRQ_BW_L10 0x1202d4 +#define PXP2_REG_PSWRQ_BW_L11 0x1202d8 +#define PXP2_REG_PSWRQ_BW_L2 0x1202b4 +#define PXP2_REG_PSWRQ_BW_L28 0x120318 +#define PXP2_REG_PSWRQ_BW_L3 0x1202b8 +#define PXP2_REG_PSWRQ_BW_L6 0x1202c4 +#define PXP2_REG_PSWRQ_BW_L7 0x1202c8 +#define PXP2_REG_PSWRQ_BW_L8 0x1202cc +#define PXP2_REG_PSWRQ_BW_L9 0x1202d0 +#define PXP2_REG_PSWRQ_BW_RD 0x120324 +#define PXP2_REG_PSWRQ_BW_UB1 0x120238 +#define PXP2_REG_PSWRQ_BW_UB10 0x12025c +#define PXP2_REG_PSWRQ_BW_UB11 0x120260 +#define PXP2_REG_PSWRQ_BW_UB2 0x12023c +#define PXP2_REG_PSWRQ_BW_UB28 0x1202a0 +#define PXP2_REG_PSWRQ_BW_UB3 0x120240 +#define PXP2_REG_PSWRQ_BW_UB6 0x12024c +#define PXP2_REG_PSWRQ_BW_UB7 0x120250 +#define PXP2_REG_PSWRQ_BW_UB8 0x120254 +#define PXP2_REG_PSWRQ_BW_UB9 0x120258 +#define PXP2_REG_PSWRQ_BW_WR 0x120328 +#define PXP2_REG_PSWRQ_CDU0_L2P 0x120000 +#define PXP2_REG_PSWRQ_QM0_L2P 0x120038 +#define PXP2_REG_PSWRQ_SRC0_L2P 0x120054 +#define PXP2_REG_PSWRQ_TM0_L2P 0x12001c +#define PXP2_REG_PSWRQ_TSDM0_L2P 0x1200e0 +/* [RW 32] Interrupt mask register #0 read/write */ +#define PXP2_REG_PXP2_INT_MASK_0 0x120578 +/* [R 32] Interrupt register #0 read */ +#define PXP2_REG_PXP2_INT_STS_0 0x12056c +#define PXP2_REG_PXP2_INT_STS_1 0x120608 +/* [RC 32] Interrupt register #0 read clear */ +#define PXP2_REG_PXP2_INT_STS_CLR_0 0x120570 +/* [RW 32] Parity mask register #0 read/write */ +#define PXP2_REG_PXP2_PRTY_MASK_0 0x120588 +#define PXP2_REG_PXP2_PRTY_MASK_1 0x120598 +/* [R 32] Parity register #0 read */ +#define PXP2_REG_PXP2_PRTY_STS_0 0x12057c +#define PXP2_REG_PXP2_PRTY_STS_1 0x12058c +/* [RC 32] Parity register #0 read clear */ +#define PXP2_REG_PXP2_PRTY_STS_CLR_0 0x120580 +#define PXP2_REG_PXP2_PRTY_STS_CLR_1 0x120590 +/* [R 1] Debug only: The 'almost full' indication from each fifo (gives + indication about backpressure) */ +#define PXP2_REG_RD_ALMOST_FULL_0 0x120424 +/* [R 8] Debug only: The blocks counter - number of unused block ids */ +#define PXP2_REG_RD_BLK_CNT 0x120418 +/* [RW 8] Debug only: Total number of available blocks in Tetris Buffer. + Must be bigger than 6. Normally should not be changed. */ +#define PXP2_REG_RD_BLK_NUM_CFG 0x12040c +/* [RW 2] CDU byte swapping mode configuration for master read requests */ +#define PXP2_REG_RD_CDURD_SWAP_MODE 0x120404 +/* [RW 1] When '1'; inputs to the PSWRD block are ignored */ +#define PXP2_REG_RD_DISABLE_INPUTS 0x120374 +/* [R 1] PSWRD internal memories initialization is done */ +#define PXP2_REG_RD_INIT_DONE 0x120370 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq10 */ +#define PXP2_REG_RD_MAX_BLKS_VQ10 0x1203a0 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq11 */ +#define PXP2_REG_RD_MAX_BLKS_VQ11 0x1203a4 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq17 */ +#define PXP2_REG_RD_MAX_BLKS_VQ17 0x1203bc +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq18 */ +#define PXP2_REG_RD_MAX_BLKS_VQ18 0x1203c0 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq19 */ +#define PXP2_REG_RD_MAX_BLKS_VQ19 0x1203c4 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq22 */ +#define PXP2_REG_RD_MAX_BLKS_VQ22 0x1203d0 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq25 */ +#define PXP2_REG_RD_MAX_BLKS_VQ25 0x1203dc +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq6 */ +#define PXP2_REG_RD_MAX_BLKS_VQ6 0x120390 +/* [RW 8] The maximum number of blocks in Tetris Buffer that can be + allocated for vq9 */ +#define PXP2_REG_RD_MAX_BLKS_VQ9 0x12039c +/* [RW 2] PBF byte swapping mode configuration for master read requests */ +#define PXP2_REG_RD_PBF_SWAP_MODE 0x1203f4 +/* [R 1] Debug only: Indication if delivery ports are idle */ +#define PXP2_REG_RD_PORT_IS_IDLE_0 0x12041c +#define PXP2_REG_RD_PORT_IS_IDLE_1 0x120420 +/* [RW 2] QM byte swapping mode configuration for master read requests */ +#define PXP2_REG_RD_QM_SWAP_MODE 0x1203f8 +/* [R 7] Debug only: The SR counter - number of unused sub request ids */ +#define PXP2_REG_RD_SR_CNT 0x120414 +/* [RW 2] SRC byte swapping mode configuration for master read requests */ +#define PXP2_REG_RD_SRC_SWAP_MODE 0x120400 +/* [RW 7] Debug only: Total number of available PCI read sub-requests. Must + be bigger than 1. Normally should not be changed. */ +#define PXP2_REG_RD_SR_NUM_CFG 0x120408 +/* [RW 1] Signals the PSWRD block to start initializing internal memories */ +#define PXP2_REG_RD_START_INIT 0x12036c +/* [RW 2] TM byte swapping mode configuration for master read requests */ +#define PXP2_REG_RD_TM_SWAP_MODE 0x1203fc +/* [RW 10] Bandwidth addition to VQ0 write requests */ +#define PXP2_REG_RQ_BW_RD_ADD0 0x1201bc +/* [RW 10] Bandwidth addition to VQ12 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD12 0x1201ec +/* [RW 10] Bandwidth addition to VQ13 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD13 0x1201f0 +/* [RW 10] Bandwidth addition to VQ14 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD14 0x1201f4 +/* [RW 10] Bandwidth addition to VQ15 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD15 0x1201f8 +/* [RW 10] Bandwidth addition to VQ16 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD16 0x1201fc +/* [RW 10] Bandwidth addition to VQ17 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD17 0x120200 +/* [RW 10] Bandwidth addition to VQ18 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD18 0x120204 +/* [RW 10] Bandwidth addition to VQ19 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD19 0x120208 +/* [RW 10] Bandwidth addition to VQ20 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD20 0x12020c +/* [RW 10] Bandwidth addition to VQ22 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD22 0x120210 +/* [RW 10] Bandwidth addition to VQ23 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD23 0x120214 +/* [RW 10] Bandwidth addition to VQ24 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD24 0x120218 +/* [RW 10] Bandwidth addition to VQ25 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD25 0x12021c +/* [RW 10] Bandwidth addition to VQ26 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD26 0x120220 +/* [RW 10] Bandwidth addition to VQ27 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD27 0x120224 +/* [RW 10] Bandwidth addition to VQ4 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD4 0x1201cc +/* [RW 10] Bandwidth addition to VQ5 read requests */ +#define PXP2_REG_RQ_BW_RD_ADD5 0x1201d0 +/* [RW 10] Bandwidth Typical L for VQ0 Read requests */ +#define PXP2_REG_RQ_BW_RD_L0 0x1202ac +/* [RW 10] Bandwidth Typical L for VQ12 Read requests */ +#define PXP2_REG_RQ_BW_RD_L12 0x1202dc +/* [RW 10] Bandwidth Typical L for VQ13 Read requests */ +#define PXP2_REG_RQ_BW_RD_L13 0x1202e0 +/* [RW 10] Bandwidth Typical L for VQ14 Read requests */ +#define PXP2_REG_RQ_BW_RD_L14 0x1202e4 +/* [RW 10] Bandwidth Typical L for VQ15 Read requests */ +#define PXP2_REG_RQ_BW_RD_L15 0x1202e8 +/* [RW 10] Bandwidth Typical L for VQ16 Read requests */ +#define PXP2_REG_RQ_BW_RD_L16 0x1202ec +/* [RW 10] Bandwidth Typical L for VQ17 Read requests */ +#define PXP2_REG_RQ_BW_RD_L17 0x1202f0 +/* [RW 10] Bandwidth Typical L for VQ18 Read requests */ +#define PXP2_REG_RQ_BW_RD_L18 0x1202f4 +/* [RW 10] Bandwidth Typical L for VQ19 Read requests */ +#define PXP2_REG_RQ_BW_RD_L19 0x1202f8 +/* [RW 10] Bandwidth Typical L for VQ20 Read requests */ +#define PXP2_REG_RQ_BW_RD_L20 0x1202fc +/* [RW 10] Bandwidth Typical L for VQ22 Read requests */ +#define PXP2_REG_RQ_BW_RD_L22 0x120300 +/* [RW 10] Bandwidth Typical L for VQ23 Read requests */ +#define PXP2_REG_RQ_BW_RD_L23 0x120304 +/* [RW 10] Bandwidth Typical L for VQ24 Read requests */ +#define PXP2_REG_RQ_BW_RD_L24 0x120308 +/* [RW 10] Bandwidth Typical L for VQ25 Read requests */ +#define PXP2_REG_RQ_BW_RD_L25 0x12030c +/* [RW 10] Bandwidth Typical L for VQ26 Read requests */ +#define PXP2_REG_RQ_BW_RD_L26 0x120310 +/* [RW 10] Bandwidth Typical L for VQ27 Read requests */ +#define PXP2_REG_RQ_BW_RD_L27 0x120314 +/* [RW 10] Bandwidth Typical L for VQ4 Read requests */ +#define PXP2_REG_RQ_BW_RD_L4 0x1202bc +/* [RW 10] Bandwidth Typical L for VQ5 Read- currently not used */ +#define PXP2_REG_RQ_BW_RD_L5 0x1202c0 +/* [RW 7] Bandwidth upper bound for VQ0 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND0 0x120234 +/* [RW 7] Bandwidth upper bound for VQ12 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND12 0x120264 +/* [RW 7] Bandwidth upper bound for VQ13 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND13 0x120268 +/* [RW 7] Bandwidth upper bound for VQ14 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND14 0x12026c +/* [RW 7] Bandwidth upper bound for VQ15 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND15 0x120270 +/* [RW 7] Bandwidth upper bound for VQ16 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND16 0x120274 +/* [RW 7] Bandwidth upper bound for VQ17 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND17 0x120278 +/* [RW 7] Bandwidth upper bound for VQ18 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND18 0x12027c +/* [RW 7] Bandwidth upper bound for VQ19 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND19 0x120280 +/* [RW 7] Bandwidth upper bound for VQ20 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND20 0x120284 +/* [RW 7] Bandwidth upper bound for VQ22 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND22 0x120288 +/* [RW 7] Bandwidth upper bound for VQ23 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND23 0x12028c +/* [RW 7] Bandwidth upper bound for VQ24 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND24 0x120290 +/* [RW 7] Bandwidth upper bound for VQ25 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND25 0x120294 +/* [RW 7] Bandwidth upper bound for VQ26 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND26 0x120298 +/* [RW 7] Bandwidth upper bound for VQ27 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND27 0x12029c +/* [RW 7] Bandwidth upper bound for VQ4 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND4 0x120244 +/* [RW 7] Bandwidth upper bound for VQ5 read requests */ +#define PXP2_REG_RQ_BW_RD_UBOUND5 0x120248 +/* [RW 10] Bandwidth addition to VQ29 write requests */ +#define PXP2_REG_RQ_BW_WR_ADD29 0x12022c +/* [RW 10] Bandwidth addition to VQ30 write requests */ +#define PXP2_REG_RQ_BW_WR_ADD30 0x120230 +/* [RW 10] Bandwidth Typical L for VQ29 Write requests */ +#define PXP2_REG_RQ_BW_WR_L29 0x12031c +/* [RW 10] Bandwidth Typical L for VQ30 Write requests */ +#define PXP2_REG_RQ_BW_WR_L30 0x120320 +/* [RW 7] Bandwidth upper bound for VQ29 */ +#define PXP2_REG_RQ_BW_WR_UBOUND29 0x1202a4 +/* [RW 7] Bandwidth upper bound for VQ30 */ +#define PXP2_REG_RQ_BW_WR_UBOUND30 0x1202a8 +/* [RW 18] external first_mem_addr field in L2P table for CDU module port 0 */ +#define PXP2_REG_RQ_CDU0_EFIRST_MEM_ADDR 0x120008 +/* [RW 2] Endian mode for cdu */ +#define PXP2_REG_RQ_CDU_ENDIAN_M 0x1201a0 +#define PXP2_REG_RQ_CDU_FIRST_ILT 0x12061c +#define PXP2_REG_RQ_CDU_LAST_ILT 0x120620 +/* [RW 3] page size in L2P table for CDU module; -4k; -8k; -16k; -32k; -64k; + -128k */ +#define PXP2_REG_RQ_CDU_P_SIZE 0x120018 +/* [R 1] 1' indicates that the requester has finished its internal + configuration */ +#define PXP2_REG_RQ_CFG_DONE 0x1201b4 +/* [RW 2] Endian mode for debug */ +#define PXP2_REG_RQ_DBG_ENDIAN_M 0x1201a4 +/* [RW 1] When '1'; requests will enter input buffers but wont get out + towards the glue */ +#define PXP2_REG_RQ_DISABLE_INPUTS 0x120330 +/* [RW 4] Determines alignment of write SRs when a request is split into + * several SRs. 0 - 8B aligned. 1 - 64B aligned. 2 - 128B aligned. 3 - 256B + * aligned. 4 - 512B aligned. */ +#define PXP2_REG_RQ_DRAM_ALIGN 0x1205b0 +/* [RW 4] Determines alignment of read SRs when a request is split into + * several SRs. 0 - 8B aligned. 1 - 64B aligned. 2 - 128B aligned. 3 - 256B + * aligned. 4 - 512B aligned. */ +#define PXP2_REG_RQ_DRAM_ALIGN_RD 0x12092c +/* [RW 1] when set the new alignment method (E2) will be applied; when reset + * the original alignment method (E1 E1H) will be applied */ +#define PXP2_REG_RQ_DRAM_ALIGN_SEL 0x120930 +/* [RW 1] If 1 ILT failiue will not result in ELT access; An interrupt will + be asserted */ +#define PXP2_REG_RQ_ELT_DISABLE 0x12066c +/* [RW 2] Endian mode for hc */ +#define PXP2_REG_RQ_HC_ENDIAN_M 0x1201a8 +/* [RW 1] when '0' ILT logic will work as in A0; otherwise B0; for back + compatibility needs; Note that different registers are used per mode */ +#define PXP2_REG_RQ_ILT_MODE 0x1205b4 +/* [WB 53] Onchip address table */ +#define PXP2_REG_RQ_ONCHIP_AT 0x122000 +/* [WB 53] Onchip address table - B0 */ +#define PXP2_REG_RQ_ONCHIP_AT_B0 0x128000 +/* [RW 13] Pending read limiter threshold; in Dwords */ +#define PXP2_REG_RQ_PDR_LIMIT 0x12033c +/* [RW 2] Endian mode for qm */ +#define PXP2_REG_RQ_QM_ENDIAN_M 0x120194 +#define PXP2_REG_RQ_QM_FIRST_ILT 0x120634 +#define PXP2_REG_RQ_QM_LAST_ILT 0x120638 +/* [RW 3] page size in L2P table for QM module; -4k; -8k; -16k; -32k; -64k; + -128k */ +#define PXP2_REG_RQ_QM_P_SIZE 0x120050 +/* [RW 1] 1' indicates that the RBC has finished configuring the PSWRQ */ +#define PXP2_REG_RQ_RBC_DONE 0x1201b0 +/* [RW 3] Max burst size filed for read requests port 0; 000 - 128B; + 001:256B; 010: 512B; 11:1K:100:2K; 01:4K */ +#define PXP2_REG_RQ_RD_MBS0 0x120160 +/* [RW 3] Max burst size filed for read requests port 1; 000 - 128B; + 001:256B; 010: 512B; 11:1K:100:2K; 01:4K */ +#define PXP2_REG_RQ_RD_MBS1 0x120168 +/* [RW 2] Endian mode for src */ +#define PXP2_REG_RQ_SRC_ENDIAN_M 0x12019c +#define PXP2_REG_RQ_SRC_FIRST_ILT 0x12063c +#define PXP2_REG_RQ_SRC_LAST_ILT 0x120640 +/* [RW 3] page size in L2P table for SRC module; -4k; -8k; -16k; -32k; -64k; + -128k */ +#define PXP2_REG_RQ_SRC_P_SIZE 0x12006c +/* [RW 2] Endian mode for tm */ +#define PXP2_REG_RQ_TM_ENDIAN_M 0x120198 +#define PXP2_REG_RQ_TM_FIRST_ILT 0x120644 +#define PXP2_REG_RQ_TM_LAST_ILT 0x120648 +/* [RW 3] page size in L2P table for TM module; -4k; -8k; -16k; -32k; -64k; + -128k */ +#define PXP2_REG_RQ_TM_P_SIZE 0x120034 +/* [R 5] Number of entries in the ufifo; his fifo has l2p completions */ +#define PXP2_REG_RQ_UFIFO_NUM_OF_ENTRY 0x12080c +/* [RW 18] external first_mem_addr field in L2P table for USDM module port 0 */ +#define PXP2_REG_RQ_USDM0_EFIRST_MEM_ADDR 0x120094 +/* [R 8] Number of entries occupied by vq 0 in pswrq memory */ +#define PXP2_REG_RQ_VQ0_ENTRY_CNT 0x120810 +/* [R 8] Number of entries occupied by vq 10 in pswrq memory */ +#define PXP2_REG_RQ_VQ10_ENTRY_CNT 0x120818 +/* [R 8] Number of entries occupied by vq 11 in pswrq memory */ +#define PXP2_REG_RQ_VQ11_ENTRY_CNT 0x120820 +/* [R 8] Number of entries occupied by vq 12 in pswrq memory */ +#define PXP2_REG_RQ_VQ12_ENTRY_CNT 0x120828 +/* [R 8] Number of entries occupied by vq 13 in pswrq memory */ +#define PXP2_REG_RQ_VQ13_ENTRY_CNT 0x120830 +/* [R 8] Number of entries occupied by vq 14 in pswrq memory */ +#define PXP2_REG_RQ_VQ14_ENTRY_CNT 0x120838 +/* [R 8] Number of entries occupied by vq 15 in pswrq memory */ +#define PXP2_REG_RQ_VQ15_ENTRY_CNT 0x120840 +/* [R 8] Number of entries occupied by vq 16 in pswrq memory */ +#define PXP2_REG_RQ_VQ16_ENTRY_CNT 0x120848 +/* [R 8] Number of entries occupied by vq 17 in pswrq memory */ +#define PXP2_REG_RQ_VQ17_ENTRY_CNT 0x120850 +/* [R 8] Number of entries occupied by vq 18 in pswrq memory */ +#define PXP2_REG_RQ_VQ18_ENTRY_CNT 0x120858 +/* [R 8] Number of entries occupied by vq 19 in pswrq memory */ +#define PXP2_REG_RQ_VQ19_ENTRY_CNT 0x120860 +/* [R 8] Number of entries occupied by vq 1 in pswrq memory */ +#define PXP2_REG_RQ_VQ1_ENTRY_CNT 0x120868 +/* [R 8] Number of entries occupied by vq 20 in pswrq memory */ +#define PXP2_REG_RQ_VQ20_ENTRY_CNT 0x120870 +/* [R 8] Number of entries occupied by vq 21 in pswrq memory */ +#define PXP2_REG_RQ_VQ21_ENTRY_CNT 0x120878 +/* [R 8] Number of entries occupied by vq 22 in pswrq memory */ +#define PXP2_REG_RQ_VQ22_ENTRY_CNT 0x120880 +/* [R 8] Number of entries occupied by vq 23 in pswrq memory */ +#define PXP2_REG_RQ_VQ23_ENTRY_CNT 0x120888 +/* [R 8] Number of entries occupied by vq 24 in pswrq memory */ +#define PXP2_REG_RQ_VQ24_ENTRY_CNT 0x120890 +/* [R 8] Number of entries occupied by vq 25 in pswrq memory */ +#define PXP2_REG_RQ_VQ25_ENTRY_CNT 0x120898 +/* [R 8] Number of entries occupied by vq 26 in pswrq memory */ +#define PXP2_REG_RQ_VQ26_ENTRY_CNT 0x1208a0 +/* [R 8] Number of entries occupied by vq 27 in pswrq memory */ +#define PXP2_REG_RQ_VQ27_ENTRY_CNT 0x1208a8 +/* [R 8] Number of entries occupied by vq 28 in pswrq memory */ +#define PXP2_REG_RQ_VQ28_ENTRY_CNT 0x1208b0 +/* [R 8] Number of entries occupied by vq 29 in pswrq memory */ +#define PXP2_REG_RQ_VQ29_ENTRY_CNT 0x1208b8 +/* [R 8] Number of entries occupied by vq 2 in pswrq memory */ +#define PXP2_REG_RQ_VQ2_ENTRY_CNT 0x1208c0 +/* [R 8] Number of entries occupied by vq 30 in pswrq memory */ +#define PXP2_REG_RQ_VQ30_ENTRY_CNT 0x1208c8 +/* [R 8] Number of entries occupied by vq 31 in pswrq memory */ +#define PXP2_REG_RQ_VQ31_ENTRY_CNT 0x1208d0 +/* [R 8] Number of entries occupied by vq 3 in pswrq memory */ +#define PXP2_REG_RQ_VQ3_ENTRY_CNT 0x1208d8 +/* [R 8] Number of entries occupied by vq 4 in pswrq memory */ +#define PXP2_REG_RQ_VQ4_ENTRY_CNT 0x1208e0 +/* [R 8] Number of entries occupied by vq 5 in pswrq memory */ +#define PXP2_REG_RQ_VQ5_ENTRY_CNT 0x1208e8 +/* [R 8] Number of entries occupied by vq 6 in pswrq memory */ +#define PXP2_REG_RQ_VQ6_ENTRY_CNT 0x1208f0 +/* [R 8] Number of entries occupied by vq 7 in pswrq memory */ +#define PXP2_REG_RQ_VQ7_ENTRY_CNT 0x1208f8 +/* [R 8] Number of entries occupied by vq 8 in pswrq memory */ +#define PXP2_REG_RQ_VQ8_ENTRY_CNT 0x120900 +/* [R 8] Number of entries occupied by vq 9 in pswrq memory */ +#define PXP2_REG_RQ_VQ9_ENTRY_CNT 0x120908 +/* [RW 3] Max burst size filed for write requests port 0; 000 - 128B; + 001:256B; 010: 512B; */ +#define PXP2_REG_RQ_WR_MBS0 0x12015c +/* [RW 3] Max burst size filed for write requests port 1; 000 - 128B; + 001:256B; 010: 512B; */ +#define PXP2_REG_RQ_WR_MBS1 0x120164 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_CDU_MPS 0x1205f0 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_CSDM_MPS 0x1205d0 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_DBG_MPS 0x1205e8 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_DMAE_MPS 0x1205ec +/* [RW 10] if Number of entries in dmae fifo will be higher than this + threshold then has_payload indication will be asserted; the default value + should be equal to > write MBS size! */ +#define PXP2_REG_WR_DMAE_TH 0x120368 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_HC_MPS 0x1205c8 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_QM_MPS 0x1205dc +/* [RW 1] 0 - working in A0 mode; - working in B0 mode */ +#define PXP2_REG_WR_REV_MODE 0x120670 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_SRC_MPS 0x1205e4 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_TM_MPS 0x1205e0 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_TSDM_MPS 0x1205d4 +/* [RW 10] if Number of entries in usdmdp fifo will be higher than this + threshold then has_payload indication will be asserted; the default value + should be equal to > write MBS size! */ +#define PXP2_REG_WR_USDMDP_TH 0x120348 +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_USDM_MPS 0x1205cc +/* [RW 2] 0 - 128B; - 256B; - 512B; - 1024B; when the payload in the + buffer reaches this number has_payload will be asserted */ +#define PXP2_REG_WR_XSDM_MPS 0x1205d8 +/* [R 1] debug only: Indication if PSWHST arbiter is idle */ +#define PXP_REG_HST_ARB_IS_IDLE 0x103004 +/* [R 8] debug only: A bit mask for all PSWHST arbiter clients. '1' means + this client is waiting for the arbiter. */ +#define PXP_REG_HST_CLIENTS_WAITING_TO_ARB 0x103008 +/* [RW 1] When 1; doorbells are discarded and not passed to doorbell queue + block. Should be used for close the gates. */ +#define PXP_REG_HST_DISCARD_DOORBELLS 0x1030a4 +/* [R 1] debug only: '1' means this PSWHST is discarding doorbells. This bit + should update according to 'hst_discard_doorbells' register when the state + machine is idle */ +#define PXP_REG_HST_DISCARD_DOORBELLS_STATUS 0x1030a0 +/* [RW 1] When 1; new internal writes arriving to the block are discarded. + Should be used for close the gates. */ +#define PXP_REG_HST_DISCARD_INTERNAL_WRITES 0x1030a8 +/* [R 6] debug only: A bit mask for all PSWHST internal write clients. '1' + means this PSWHST is discarding inputs from this client. Each bit should + update according to 'hst_discard_internal_writes' register when the state + machine is idle. */ +#define PXP_REG_HST_DISCARD_INTERNAL_WRITES_STATUS 0x10309c +/* [WB 160] Used for initialization of the inbound interrupts memory */ +#define PXP_REG_HST_INBOUND_INT 0x103800 +/* [RW 32] Interrupt mask register #0 read/write */ +#define PXP_REG_PXP_INT_MASK_0 0x103074 +#define PXP_REG_PXP_INT_MASK_1 0x103084 +/* [R 32] Interrupt register #0 read */ +#define PXP_REG_PXP_INT_STS_0 0x103068 +#define PXP_REG_PXP_INT_STS_1 0x103078 +/* [RC 32] Interrupt register #0 read clear */ +#define PXP_REG_PXP_INT_STS_CLR_0 0x10306c +#define PXP_REG_PXP_INT_STS_CLR_1 0x10307c +/* [RW 27] Parity mask register #0 read/write */ +#define PXP_REG_PXP_PRTY_MASK 0x103094 +/* [R 26] Parity register #0 read */ +#define PXP_REG_PXP_PRTY_STS 0x103088 +/* [RC 27] Parity register #0 read clear */ +#define PXP_REG_PXP_PRTY_STS_CLR 0x10308c +/* [RW 4] The activity counter initial increment value sent in the load + request */ +#define QM_REG_ACTCTRINITVAL_0 0x168040 +#define QM_REG_ACTCTRINITVAL_1 0x168044 +#define QM_REG_ACTCTRINITVAL_2 0x168048 +#define QM_REG_ACTCTRINITVAL_3 0x16804c +/* [RW 32] The base logical address (in bytes) of each physical queue. The + index I represents the physical queue number. The 12 lsbs are ignore and + considered zero so practically there are only 20 bits in this register; + queues 63-0 */ +#define QM_REG_BASEADDR 0x168900 +/* [RW 32] The base logical address (in bytes) of each physical queue. The + index I represents the physical queue number. The 12 lsbs are ignore and + considered zero so practically there are only 20 bits in this register; + queues 127-64 */ +#define QM_REG_BASEADDR_EXT_A 0x16e100 +/* [RW 16] The byte credit cost for each task. This value is for both ports */ +#define QM_REG_BYTECRDCOST 0x168234 +/* [RW 16] The initial byte credit value for both ports. */ +#define QM_REG_BYTECRDINITVAL 0x168238 +/* [RW 32] A bit per physical queue. If the bit is cleared then the physical + queue uses port 0 else it uses port 1; queues 31-0 */ +#define QM_REG_BYTECRDPORT_LSB 0x168228 +/* [RW 32] A bit per physical queue. If the bit is cleared then the physical + queue uses port 0 else it uses port 1; queues 95-64 */ +#define QM_REG_BYTECRDPORT_LSB_EXT_A 0x16e520 +/* [RW 32] A bit per physical queue. If the bit is cleared then the physical + queue uses port 0 else it uses port 1; queues 63-32 */ +#define QM_REG_BYTECRDPORT_MSB 0x168224 +/* [RW 32] A bit per physical queue. If the bit is cleared then the physical + queue uses port 0 else it uses port 1; queues 127-96 */ +#define QM_REG_BYTECRDPORT_MSB_EXT_A 0x16e51c +/* [RW 16] The byte credit value that if above the QM is considered almost + full */ +#define QM_REG_BYTECREDITAFULLTHR 0x168094 +/* [RW 4] The initial credit for interface */ +#define QM_REG_CMINITCRD_0 0x1680cc +#define QM_REG_BYTECRDCMDQ_0 0x16e6e8 +#define QM_REG_CMINITCRD_1 0x1680d0 +#define QM_REG_CMINITCRD_2 0x1680d4 +#define QM_REG_CMINITCRD_3 0x1680d8 +#define QM_REG_CMINITCRD_4 0x1680dc +#define QM_REG_CMINITCRD_5 0x1680e0 +#define QM_REG_CMINITCRD_6 0x1680e4 +#define QM_REG_CMINITCRD_7 0x1680e8 +/* [RW 8] A mask bit per CM interface. If this bit is 0 then this interface + is masked */ +#define QM_REG_CMINTEN 0x1680ec +/* [RW 12] A bit vector which indicates which one of the queues are tied to + interface 0 */ +#define QM_REG_CMINTVOQMASK_0 0x1681f4 +#define QM_REG_CMINTVOQMASK_1 0x1681f8 +#define QM_REG_CMINTVOQMASK_2 0x1681fc +#define QM_REG_CMINTVOQMASK_3 0x168200 +#define QM_REG_CMINTVOQMASK_4 0x168204 +#define QM_REG_CMINTVOQMASK_5 0x168208 +#define QM_REG_CMINTVOQMASK_6 0x16820c +#define QM_REG_CMINTVOQMASK_7 0x168210 +/* [RW 20] The number of connections divided by 16 which dictates the size + of each queue which belongs to even function number. */ +#define QM_REG_CONNNUM_0 0x168020 +/* [R 6] Keep the fill level of the fifo from write client 4 */ +#define QM_REG_CQM_WRC_FIFOLVL 0x168018 +/* [RW 8] The context regions sent in the CFC load request */ +#define QM_REG_CTXREG_0 0x168030 +#define QM_REG_CTXREG_1 0x168034 +#define QM_REG_CTXREG_2 0x168038 +#define QM_REG_CTXREG_3 0x16803c +/* [RW 12] The VOQ mask used to select the VOQs which needs to be full for + bypass enable */ +#define QM_REG_ENBYPVOQMASK 0x16823c +/* [RW 32] A bit mask per each physical queue. If a bit is set then the + physical queue uses the byte credit; queues 31-0 */ +#define QM_REG_ENBYTECRD_LSB 0x168220 +/* [RW 32] A bit mask per each physical queue. If a bit is set then the + physical queue uses the byte credit; queues 95-64 */ +#define QM_REG_ENBYTECRD_LSB_EXT_A 0x16e518 +/* [RW 32] A bit mask per each physical queue. If a bit is set then the + physical queue uses the byte credit; queues 63-32 */ +#define QM_REG_ENBYTECRD_MSB 0x16821c +/* [RW 32] A bit mask per each physical queue. If a bit is set then the + physical queue uses the byte credit; queues 127-96 */ +#define QM_REG_ENBYTECRD_MSB_EXT_A 0x16e514 +/* [RW 4] If cleared then the secondary interface will not be served by the + RR arbiter */ +#define QM_REG_ENSEC 0x1680f0 +/* [RW 32] NA */ +#define QM_REG_FUNCNUMSEL_LSB 0x168230 +/* [RW 32] NA */ +#define QM_REG_FUNCNUMSEL_MSB 0x16822c +/* [RW 32] A mask register to mask the Almost empty signals which will not + be use for the almost empty indication to the HW block; queues 31:0 */ +#define QM_REG_HWAEMPTYMASK_LSB 0x168218 +/* [RW 32] A mask register to mask the Almost empty signals which will not + be use for the almost empty indication to the HW block; queues 95-64 */ +#define QM_REG_HWAEMPTYMASK_LSB_EXT_A 0x16e510 +/* [RW 32] A mask register to mask the Almost empty signals which will not + be use for the almost empty indication to the HW block; queues 63:32 */ +#define QM_REG_HWAEMPTYMASK_MSB 0x168214 +/* [RW 32] A mask register to mask the Almost empty signals which will not + be use for the almost empty indication to the HW block; queues 127-96 */ +#define QM_REG_HWAEMPTYMASK_MSB_EXT_A 0x16e50c +/* [RW 4] The number of outstanding request to CFC */ +#define QM_REG_OUTLDREQ 0x168804 +/* [RC 1] A flag to indicate that overflow error occurred in one of the + queues. */ +#define QM_REG_OVFERROR 0x16805c +/* [RC 7] the Q where the overflow occurs */ +#define QM_REG_OVFQNUM 0x168058 +/* [R 16] Pause state for physical queues 15-0 */ +#define QM_REG_PAUSESTATE0 0x168410 +/* [R 16] Pause state for physical queues 31-16 */ +#define QM_REG_PAUSESTATE1 0x168414 +/* [R 16] Pause state for physical queues 47-32 */ +#define QM_REG_PAUSESTATE2 0x16e684 +/* [R 16] Pause state for physical queues 63-48 */ +#define QM_REG_PAUSESTATE3 0x16e688 +/* [R 16] Pause state for physical queues 79-64 */ +#define QM_REG_PAUSESTATE4 0x16e68c +/* [R 16] Pause state for physical queues 95-80 */ +#define QM_REG_PAUSESTATE5 0x16e690 +/* [R 16] Pause state for physical queues 111-96 */ +#define QM_REG_PAUSESTATE6 0x16e694 +/* [R 16] Pause state for physical queues 127-112 */ +#define QM_REG_PAUSESTATE7 0x16e698 +/* [RW 2] The PCI attributes field used in the PCI request. */ +#define QM_REG_PCIREQAT 0x168054 +#define QM_REG_PF_EN 0x16e70c +/* [R 24] The number of tasks stored in the QM for the PF. only even + * functions are valid in E2 (odd I registers will be hard wired to 0) */ +#define QM_REG_PF_USG_CNT_0 0x16e040 +/* [R 16] NOT USED */ +#define QM_REG_PORT0BYTECRD 0x168300 +/* [R 16] The byte credit of port 1 */ +#define QM_REG_PORT1BYTECRD 0x168304 +/* [RW 3] pci function number of queues 15-0 */ +#define QM_REG_PQ2PCIFUNC_0 0x16e6bc +#define QM_REG_PQ2PCIFUNC_1 0x16e6c0 +#define QM_REG_PQ2PCIFUNC_2 0x16e6c4 +#define QM_REG_PQ2PCIFUNC_3 0x16e6c8 +#define QM_REG_PQ2PCIFUNC_4 0x16e6cc +#define QM_REG_PQ2PCIFUNC_5 0x16e6d0 +#define QM_REG_PQ2PCIFUNC_6 0x16e6d4 +#define QM_REG_PQ2PCIFUNC_7 0x16e6d8 +/* [WB 54] Pointer Table Memory for queues 63-0; The mapping is as follow: + ptrtbl[53:30] read pointer; ptrtbl[29:6] write pointer; ptrtbl[5:4] read + bank0; ptrtbl[3:2] read bank 1; ptrtbl[1:0] write bank; */ +#define QM_REG_PTRTBL 0x168a00 +/* [WB 54] Pointer Table Memory for queues 127-64; The mapping is as follow: + ptrtbl[53:30] read pointer; ptrtbl[29:6] write pointer; ptrtbl[5:4] read + bank0; ptrtbl[3:2] read bank 1; ptrtbl[1:0] write bank; */ +#define QM_REG_PTRTBL_EXT_A 0x16e200 +/* [RW 2] Interrupt mask register #0 read/write */ +#define QM_REG_QM_INT_MASK 0x168444 +/* [R 2] Interrupt register #0 read */ +#define QM_REG_QM_INT_STS 0x168438 +/* [RW 12] Parity mask register #0 read/write */ +#define QM_REG_QM_PRTY_MASK 0x168454 +/* [R 12] Parity register #0 read */ +#define QM_REG_QM_PRTY_STS 0x168448 +/* [RC 12] Parity register #0 read clear */ +#define QM_REG_QM_PRTY_STS_CLR 0x16844c +/* [R 32] Current queues in pipeline: Queues from 32 to 63 */ +#define QM_REG_QSTATUS_HIGH 0x16802c +/* [R 32] Current queues in pipeline: Queues from 96 to 127 */ +#define QM_REG_QSTATUS_HIGH_EXT_A 0x16e408 +/* [R 32] Current queues in pipeline: Queues from 0 to 31 */ +#define QM_REG_QSTATUS_LOW 0x168028 +/* [R 32] Current queues in pipeline: Queues from 64 to 95 */ +#define QM_REG_QSTATUS_LOW_EXT_A 0x16e404 +/* [R 24] The number of tasks queued for each queue; queues 63-0 */ +#define QM_REG_QTASKCTR_0 0x168308 +/* [R 24] The number of tasks queued for each queue; queues 127-64 */ +#define QM_REG_QTASKCTR_EXT_A_0 0x16e584 +/* [RW 4] Queue tied to VOQ */ +#define QM_REG_QVOQIDX_0 0x1680f4 +#define QM_REG_QVOQIDX_10 0x16811c +#define QM_REG_QVOQIDX_100 0x16e49c +#define QM_REG_QVOQIDX_101 0x16e4a0 +#define QM_REG_QVOQIDX_102 0x16e4a4 +#define QM_REG_QVOQIDX_103 0x16e4a8 +#define QM_REG_QVOQIDX_104 0x16e4ac +#define QM_REG_QVOQIDX_105 0x16e4b0 +#define QM_REG_QVOQIDX_106 0x16e4b4 +#define QM_REG_QVOQIDX_107 0x16e4b8 +#define QM_REG_QVOQIDX_108 0x16e4bc +#define QM_REG_QVOQIDX_109 0x16e4c0 +#define QM_REG_QVOQIDX_11 0x168120 +#define QM_REG_QVOQIDX_110 0x16e4c4 +#define QM_REG_QVOQIDX_111 0x16e4c8 +#define QM_REG_QVOQIDX_112 0x16e4cc +#define QM_REG_QVOQIDX_113 0x16e4d0 +#define QM_REG_QVOQIDX_114 0x16e4d4 +#define QM_REG_QVOQIDX_115 0x16e4d8 +#define QM_REG_QVOQIDX_116 0x16e4dc +#define QM_REG_QVOQIDX_117 0x16e4e0 +#define QM_REG_QVOQIDX_118 0x16e4e4 +#define QM_REG_QVOQIDX_119 0x16e4e8 +#define QM_REG_QVOQIDX_12 0x168124 +#define QM_REG_QVOQIDX_120 0x16e4ec +#define QM_REG_QVOQIDX_121 0x16e4f0 +#define QM_REG_QVOQIDX_122 0x16e4f4 +#define QM_REG_QVOQIDX_123 0x16e4f8 +#define QM_REG_QVOQIDX_124 0x16e4fc +#define QM_REG_QVOQIDX_125 0x16e500 +#define QM_REG_QVOQIDX_126 0x16e504 +#define QM_REG_QVOQIDX_127 0x16e508 +#define QM_REG_QVOQIDX_13 0x168128 +#define QM_REG_QVOQIDX_14 0x16812c +#define QM_REG_QVOQIDX_15 0x168130 +#define QM_REG_QVOQIDX_16 0x168134 +#define QM_REG_QVOQIDX_17 0x168138 +#define QM_REG_QVOQIDX_21 0x168148 +#define QM_REG_QVOQIDX_22 0x16814c +#define QM_REG_QVOQIDX_23 0x168150 +#define QM_REG_QVOQIDX_24 0x168154 +#define QM_REG_QVOQIDX_25 0x168158 +#define QM_REG_QVOQIDX_26 0x16815c +#define QM_REG_QVOQIDX_27 0x168160 +#define QM_REG_QVOQIDX_28 0x168164 +#define QM_REG_QVOQIDX_29 0x168168 +#define QM_REG_QVOQIDX_30 0x16816c +#define QM_REG_QVOQIDX_31 0x168170 +#define QM_REG_QVOQIDX_32 0x168174 +#define QM_REG_QVOQIDX_33 0x168178 +#define QM_REG_QVOQIDX_34 0x16817c +#define QM_REG_QVOQIDX_35 0x168180 +#define QM_REG_QVOQIDX_36 0x168184 +#define QM_REG_QVOQIDX_37 0x168188 +#define QM_REG_QVOQIDX_38 0x16818c +#define QM_REG_QVOQIDX_39 0x168190 +#define QM_REG_QVOQIDX_40 0x168194 +#define QM_REG_QVOQIDX_41 0x168198 +#define QM_REG_QVOQIDX_42 0x16819c +#define QM_REG_QVOQIDX_43 0x1681a0 +#define QM_REG_QVOQIDX_44 0x1681a4 +#define QM_REG_QVOQIDX_45 0x1681a8 +#define QM_REG_QVOQIDX_46 0x1681ac +#define QM_REG_QVOQIDX_47 0x1681b0 +#define QM_REG_QVOQIDX_48 0x1681b4 +#define QM_REG_QVOQIDX_49 0x1681b8 +#define QM_REG_QVOQIDX_5 0x168108 +#define QM_REG_QVOQIDX_50 0x1681bc +#define QM_REG_QVOQIDX_51 0x1681c0 +#define QM_REG_QVOQIDX_52 0x1681c4 +#define QM_REG_QVOQIDX_53 0x1681c8 +#define QM_REG_QVOQIDX_54 0x1681cc +#define QM_REG_QVOQIDX_55 0x1681d0 +#define QM_REG_QVOQIDX_56 0x1681d4 +#define QM_REG_QVOQIDX_57 0x1681d8 +#define QM_REG_QVOQIDX_58 0x1681dc +#define QM_REG_QVOQIDX_59 0x1681e0 +#define QM_REG_QVOQIDX_6 0x16810c +#define QM_REG_QVOQIDX_60 0x1681e4 +#define QM_REG_QVOQIDX_61 0x1681e8 +#define QM_REG_QVOQIDX_62 0x1681ec +#define QM_REG_QVOQIDX_63 0x1681f0 +#define QM_REG_QVOQIDX_64 0x16e40c +#define QM_REG_QVOQIDX_65 0x16e410 +#define QM_REG_QVOQIDX_69 0x16e420 +#define QM_REG_QVOQIDX_7 0x168110 +#define QM_REG_QVOQIDX_70 0x16e424 +#define QM_REG_QVOQIDX_71 0x16e428 +#define QM_REG_QVOQIDX_72 0x16e42c +#define QM_REG_QVOQIDX_73 0x16e430 +#define QM_REG_QVOQIDX_74 0x16e434 +#define QM_REG_QVOQIDX_75 0x16e438 +#define QM_REG_QVOQIDX_76 0x16e43c +#define QM_REG_QVOQIDX_77 0x16e440 +#define QM_REG_QVOQIDX_78 0x16e444 +#define QM_REG_QVOQIDX_79 0x16e448 +#define QM_REG_QVOQIDX_8 0x168114 +#define QM_REG_QVOQIDX_80 0x16e44c +#define QM_REG_QVOQIDX_81 0x16e450 +#define QM_REG_QVOQIDX_85 0x16e460 +#define QM_REG_QVOQIDX_86 0x16e464 +#define QM_REG_QVOQIDX_87 0x16e468 +#define QM_REG_QVOQIDX_88 0x16e46c +#define QM_REG_QVOQIDX_89 0x16e470 +#define QM_REG_QVOQIDX_9 0x168118 +#define QM_REG_QVOQIDX_90 0x16e474 +#define QM_REG_QVOQIDX_91 0x16e478 +#define QM_REG_QVOQIDX_92 0x16e47c +#define QM_REG_QVOQIDX_93 0x16e480 +#define QM_REG_QVOQIDX_94 0x16e484 +#define QM_REG_QVOQIDX_95 0x16e488 +#define QM_REG_QVOQIDX_96 0x16e48c +#define QM_REG_QVOQIDX_97 0x16e490 +#define QM_REG_QVOQIDX_98 0x16e494 +#define QM_REG_QVOQIDX_99 0x16e498 +/* [RW 1] Initialization bit command */ +#define QM_REG_SOFT_RESET 0x168428 +/* [RW 8] The credit cost per every task in the QM. A value per each VOQ */ +#define QM_REG_TASKCRDCOST_0 0x16809c +#define QM_REG_TASKCRDCOST_1 0x1680a0 +#define QM_REG_TASKCRDCOST_2 0x1680a4 +#define QM_REG_TASKCRDCOST_4 0x1680ac +#define QM_REG_TASKCRDCOST_5 0x1680b0 +/* [R 6] Keep the fill level of the fifo from write client 3 */ +#define QM_REG_TQM_WRC_FIFOLVL 0x168010 +/* [R 6] Keep the fill level of the fifo from write client 2 */ +#define QM_REG_UQM_WRC_FIFOLVL 0x168008 +/* [RC 32] Credit update error register */ +#define QM_REG_VOQCRDERRREG 0x168408 +/* [R 16] The credit value for each VOQ */ +#define QM_REG_VOQCREDIT_0 0x1682d0 +#define QM_REG_VOQCREDIT_1 0x1682d4 +#define QM_REG_VOQCREDIT_4 0x1682e0 +/* [RW 16] The credit value that if above the QM is considered almost full */ +#define QM_REG_VOQCREDITAFULLTHR 0x168090 +/* [RW 16] The init and maximum credit for each VoQ */ +#define QM_REG_VOQINITCREDIT_0 0x168060 +#define QM_REG_VOQINITCREDIT_1 0x168064 +#define QM_REG_VOQINITCREDIT_2 0x168068 +#define QM_REG_VOQINITCREDIT_4 0x168070 +#define QM_REG_VOQINITCREDIT_5 0x168074 +/* [RW 1] The port of which VOQ belongs */ +#define QM_REG_VOQPORT_0 0x1682a0 +#define QM_REG_VOQPORT_1 0x1682a4 +#define QM_REG_VOQPORT_2 0x1682a8 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_0_LSB 0x168240 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_0_LSB_EXT_A 0x16e524 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_0_MSB 0x168244 +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_0_MSB_EXT_A 0x16e528 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_10_LSB 0x168290 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_10_LSB_EXT_A 0x16e574 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_10_MSB 0x168294 +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_10_MSB_EXT_A 0x16e578 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_11_LSB 0x168298 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_11_LSB_EXT_A 0x16e57c +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_11_MSB 0x16829c +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_11_MSB_EXT_A 0x16e580 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_1_LSB 0x168248 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_1_LSB_EXT_A 0x16e52c +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_1_MSB 0x16824c +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_1_MSB_EXT_A 0x16e530 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_2_LSB 0x168250 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_2_LSB_EXT_A 0x16e534 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_2_MSB 0x168254 +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_2_MSB_EXT_A 0x16e538 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_3_LSB 0x168258 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_3_LSB_EXT_A 0x16e53c +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_3_MSB_EXT_A 0x16e540 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_4_LSB 0x168260 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_4_LSB_EXT_A 0x16e544 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_4_MSB 0x168264 +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_4_MSB_EXT_A 0x16e548 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_5_LSB 0x168268 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_5_LSB_EXT_A 0x16e54c +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_5_MSB 0x16826c +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_5_MSB_EXT_A 0x16e550 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_6_LSB 0x168270 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_6_LSB_EXT_A 0x16e554 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_6_MSB 0x168274 +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_6_MSB_EXT_A 0x16e558 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_7_LSB 0x168278 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_7_LSB_EXT_A 0x16e55c +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_7_MSB 0x16827c +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_7_MSB_EXT_A 0x16e560 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_8_LSB 0x168280 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_8_LSB_EXT_A 0x16e564 +/* [RW 32] The physical queue number associated with each VOQ; queues 63-32 */ +#define QM_REG_VOQQMASK_8_MSB 0x168284 +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_8_MSB_EXT_A 0x16e568 +/* [RW 32] The physical queue number associated with each VOQ; queues 31-0 */ +#define QM_REG_VOQQMASK_9_LSB 0x168288 +/* [RW 32] The physical queue number associated with each VOQ; queues 95-64 */ +#define QM_REG_VOQQMASK_9_LSB_EXT_A 0x16e56c +/* [RW 32] The physical queue number associated with each VOQ; queues 127-96 */ +#define QM_REG_VOQQMASK_9_MSB_EXT_A 0x16e570 +/* [RW 32] Wrr weights */ +#define QM_REG_WRRWEIGHTS_0 0x16880c +#define QM_REG_WRRWEIGHTS_1 0x168810 +#define QM_REG_WRRWEIGHTS_10 0x168814 +#define QM_REG_WRRWEIGHTS_11 0x168818 +#define QM_REG_WRRWEIGHTS_12 0x16881c +#define QM_REG_WRRWEIGHTS_13 0x168820 +#define QM_REG_WRRWEIGHTS_14 0x168824 +#define QM_REG_WRRWEIGHTS_15 0x168828 +#define QM_REG_WRRWEIGHTS_16 0x16e000 +#define QM_REG_WRRWEIGHTS_17 0x16e004 +#define QM_REG_WRRWEIGHTS_18 0x16e008 +#define QM_REG_WRRWEIGHTS_19 0x16e00c +#define QM_REG_WRRWEIGHTS_2 0x16882c +#define QM_REG_WRRWEIGHTS_20 0x16e010 +#define QM_REG_WRRWEIGHTS_21 0x16e014 +#define QM_REG_WRRWEIGHTS_22 0x16e018 +#define QM_REG_WRRWEIGHTS_23 0x16e01c +#define QM_REG_WRRWEIGHTS_24 0x16e020 +#define QM_REG_WRRWEIGHTS_25 0x16e024 +#define QM_REG_WRRWEIGHTS_26 0x16e028 +#define QM_REG_WRRWEIGHTS_27 0x16e02c +#define QM_REG_WRRWEIGHTS_28 0x16e030 +#define QM_REG_WRRWEIGHTS_29 0x16e034 +#define QM_REG_WRRWEIGHTS_3 0x168830 +#define QM_REG_WRRWEIGHTS_30 0x16e038 +#define QM_REG_WRRWEIGHTS_31 0x16e03c +#define QM_REG_WRRWEIGHTS_4 0x168834 +#define QM_REG_WRRWEIGHTS_5 0x168838 +#define QM_REG_WRRWEIGHTS_6 0x16883c +#define QM_REG_WRRWEIGHTS_7 0x168840 +#define QM_REG_WRRWEIGHTS_8 0x168844 +#define QM_REG_WRRWEIGHTS_9 0x168848 +/* [R 6] Keep the fill level of the fifo from write client 1 */ +#define QM_REG_XQM_WRC_FIFOLVL 0x168000 +/* [W 1] reset to parity interrupt */ +#define SEM_FAST_REG_PARITY_RST 0x18840 +#define SRC_REG_COUNTFREE0 0x40500 +/* [RW 1] If clr the searcher is compatible to E1 A0 - support only two + ports. If set the searcher support 8 functions. */ +#define SRC_REG_E1HMF_ENABLE 0x404cc +#define SRC_REG_FIRSTFREE0 0x40510 +#define SRC_REG_KEYRSS0_0 0x40408 +#define SRC_REG_KEYRSS0_7 0x40424 +#define SRC_REG_KEYRSS1_9 0x40454 +#define SRC_REG_KEYSEARCH_0 0x40458 +#define SRC_REG_KEYSEARCH_1 0x4045c +#define SRC_REG_KEYSEARCH_2 0x40460 +#define SRC_REG_KEYSEARCH_3 0x40464 +#define SRC_REG_KEYSEARCH_4 0x40468 +#define SRC_REG_KEYSEARCH_5 0x4046c +#define SRC_REG_KEYSEARCH_6 0x40470 +#define SRC_REG_KEYSEARCH_7 0x40474 +#define SRC_REG_KEYSEARCH_8 0x40478 +#define SRC_REG_KEYSEARCH_9 0x4047c +#define SRC_REG_LASTFREE0 0x40530 +#define SRC_REG_NUMBER_HASH_BITS0 0x40400 +/* [RW 1] Reset internal state machines. */ +#define SRC_REG_SOFT_RST 0x4049c +/* [R 3] Interrupt register #0 read */ +#define SRC_REG_SRC_INT_STS 0x404ac +/* [RW 3] Parity mask register #0 read/write */ +#define SRC_REG_SRC_PRTY_MASK 0x404c8 +/* [R 3] Parity register #0 read */ +#define SRC_REG_SRC_PRTY_STS 0x404bc +/* [RC 3] Parity register #0 read clear */ +#define SRC_REG_SRC_PRTY_STS_CLR 0x404c0 +/* [R 4] Used to read the value of the XX protection CAM occupancy counter. */ +#define TCM_REG_CAM_OCCUP 0x5017c +/* [RW 1] CDU AG read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define TCM_REG_CDU_AG_RD_IFEN 0x50034 +/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input + are disregarded; all other signals are treated as usual; if 1 - normal + activity. */ +#define TCM_REG_CDU_AG_WR_IFEN 0x50030 +/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define TCM_REG_CDU_SM_RD_IFEN 0x5003c +/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid + input is disregarded; all other signals are treated as usual; if 1 - + normal activity. */ +#define TCM_REG_CDU_SM_WR_IFEN 0x50038 +/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 1 at start-up. */ +#define TCM_REG_CFC_INIT_CRD 0x50204 +/* [RW 3] The weight of the CP input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_CP_WEIGHT 0x500c0 +/* [RW 1] Input csem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define TCM_REG_CSEM_IFEN 0x5002c +/* [RC 1] Message length mismatch (relative to last indication) at the In#9 + interface. */ +#define TCM_REG_CSEM_LENGTH_MIS 0x50174 +/* [RW 3] The weight of the input csem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_CSEM_WEIGHT 0x500bc +/* [RW 8] The Event ID in case of ErrorFlg is set in the input message. */ +#define TCM_REG_ERR_EVNT_ID 0x500a0 +/* [RW 28] The CM erroneous header for QM and Timers formatting. */ +#define TCM_REG_ERR_TCM_HDR 0x5009c +/* [RW 8] The Event ID for Timers expiration. */ +#define TCM_REG_EXPR_EVNT_ID 0x500a4 +/* [RW 8] FIC0 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define TCM_REG_FIC0_INIT_CRD 0x5020c +/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define TCM_REG_FIC1_INIT_CRD 0x50210 +/* [RW 1] Arbitration between Input Arbiter groups: 0 - fair Round-Robin; 1 + - strict priority defined by ~tcm_registers_gr_ag_pr.gr_ag_pr; + ~tcm_registers_gr_ld0_pr.gr_ld0_pr and + ~tcm_registers_gr_ld1_pr.gr_ld1_pr. */ +#define TCM_REG_GR_ARB_TYPE 0x50114 +/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Store channel is the + compliment of the other 3 groups. */ +#define TCM_REG_GR_LD0_PR 0x5011c +/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Store channel is the + compliment of the other 3 groups. */ +#define TCM_REG_GR_LD1_PR 0x50120 +/* [RW 4] The number of double REG-pairs; loaded from the STORM context and + sent to STORM; for a specific connection type. The double REG-pairs are + used to align to STORM context row size of 128 bits. The offset of these + data in the STORM context is always 0. Index _i stands for the connection + type (one of 16). */ +#define TCM_REG_N_SM_CTX_LD_0 0x50050 +#define TCM_REG_N_SM_CTX_LD_1 0x50054 +#define TCM_REG_N_SM_CTX_LD_2 0x50058 +#define TCM_REG_N_SM_CTX_LD_3 0x5005c +#define TCM_REG_N_SM_CTX_LD_4 0x50060 +#define TCM_REG_N_SM_CTX_LD_5 0x50064 +/* [RW 1] Input pbf Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_PBF_IFEN 0x50024 +/* [RC 1] Message length mismatch (relative to last indication) at the In#7 + interface. */ +#define TCM_REG_PBF_LENGTH_MIS 0x5016c +/* [RW 3] The weight of the input pbf in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_PBF_WEIGHT 0x500b4 +#define TCM_REG_PHYS_QNUM0_0 0x500e0 +#define TCM_REG_PHYS_QNUM0_1 0x500e4 +#define TCM_REG_PHYS_QNUM1_0 0x500e8 +#define TCM_REG_PHYS_QNUM1_1 0x500ec +#define TCM_REG_PHYS_QNUM2_0 0x500f0 +#define TCM_REG_PHYS_QNUM2_1 0x500f4 +#define TCM_REG_PHYS_QNUM3_0 0x500f8 +#define TCM_REG_PHYS_QNUM3_1 0x500fc +/* [RW 1] Input prs Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_PRS_IFEN 0x50020 +/* [RC 1] Message length mismatch (relative to last indication) at the In#6 + interface. */ +#define TCM_REG_PRS_LENGTH_MIS 0x50168 +/* [RW 3] The weight of the input prs in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_PRS_WEIGHT 0x500b0 +/* [RW 8] The Event ID for Timers formatting in case of stop done. */ +#define TCM_REG_STOP_EVNT_ID 0x500a8 +/* [RC 1] Message length mismatch (relative to last indication) at the STORM + interface. */ +#define TCM_REG_STORM_LENGTH_MIS 0x50160 +/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define TCM_REG_STORM_TCM_IFEN 0x50010 +/* [RW 3] The weight of the STORM input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_STORM_WEIGHT 0x500ac +/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TCM_CFC_IFEN 0x50040 +/* [RW 11] Interrupt mask register #0 read/write */ +#define TCM_REG_TCM_INT_MASK 0x501dc +/* [R 11] Interrupt register #0 read */ +#define TCM_REG_TCM_INT_STS 0x501d0 +/* [RW 27] Parity mask register #0 read/write */ +#define TCM_REG_TCM_PRTY_MASK 0x501ec +/* [R 27] Parity register #0 read */ +#define TCM_REG_TCM_PRTY_STS 0x501e0 +/* [RC 27] Parity register #0 read clear */ +#define TCM_REG_TCM_PRTY_STS_CLR 0x501e4 +/* [RW 3] The size of AG context region 0 in REG-pairs. Designates the MS + REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). + Is used to determine the number of the AG context REG-pairs written back; + when the input message Reg1WbFlg isn't set. */ +#define TCM_REG_TCM_REG0_SZ 0x500d8 +/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TCM_STORM0_IFEN 0x50004 +/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TCM_STORM1_IFEN 0x50008 +/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TCM_TQM_IFEN 0x5000c +/* [RW 1] If set the Q index; received from the QM is inserted to event ID. */ +#define TCM_REG_TCM_TQM_USE_Q 0x500d4 +/* [RW 28] The CM header for Timers expiration command. */ +#define TCM_REG_TM_TCM_HDR 0x50098 +/* [RW 1] Timers - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define TCM_REG_TM_TCM_IFEN 0x5001c +/* [RW 3] The weight of the Timers input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_TM_WEIGHT 0x500d0 +/* [RW 6] QM output initial credit. Max credit available - 32.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 32 at start-up. */ +#define TCM_REG_TQM_INIT_CRD 0x5021c +/* [RW 3] The weight of the QM (primary) input in the WRR mechanism. 0 + stands for weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_TQM_P_WEIGHT 0x500c8 +/* [RW 3] The weight of the QM (secondary) input in the WRR mechanism. 0 + stands for weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_TQM_S_WEIGHT 0x500cc +/* [RW 28] The CM header value for QM request (primary). */ +#define TCM_REG_TQM_TCM_HDR_P 0x50090 +/* [RW 28] The CM header value for QM request (secondary). */ +#define TCM_REG_TQM_TCM_HDR_S 0x50094 +/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TQM_TCM_IFEN 0x50014 +/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define TCM_REG_TSDM_IFEN 0x50018 +/* [RC 1] Message length mismatch (relative to last indication) at the SDM + interface. */ +#define TCM_REG_TSDM_LENGTH_MIS 0x50164 +/* [RW 3] The weight of the SDM input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_TSDM_WEIGHT 0x500c4 +/* [RW 1] Input usem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define TCM_REG_USEM_IFEN 0x50028 +/* [RC 1] Message length mismatch (relative to last indication) at the In#8 + interface. */ +#define TCM_REG_USEM_LENGTH_MIS 0x50170 +/* [RW 3] The weight of the input usem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define TCM_REG_USEM_WEIGHT 0x500b8 +/* [RW 21] Indirect access to the descriptor table of the XX protection + mechanism. The fields are: [5:0] - length of the message; 15:6] - message + pointer; 20:16] - next pointer. */ +#define TCM_REG_XX_DESCR_TABLE 0x50280 +#define TCM_REG_XX_DESCR_TABLE_SIZE 29 +/* [R 6] Use to read the value of XX protection Free counter. */ +#define TCM_REG_XX_FREE 0x50178 +/* [RW 6] Initial value for the credit counter; responsible for fulfilling + of the Input Stage XX protection buffer by the XX protection pending + messages. Max credit available - 127.Write writes the initial credit + value; read returns the current value of the credit counter. Must be + initialized to 19 at start-up. */ +#define TCM_REG_XX_INIT_CRD 0x50220 +/* [RW 6] Maximum link list size (messages locked) per connection in the XX + protection. */ +#define TCM_REG_XX_MAX_LL_SZ 0x50044 +/* [RW 6] The maximum number of pending messages; which may be stored in XX + protection. ~tcm_registers_xx_free.xx_free is read on read. */ +#define TCM_REG_XX_MSG_NUM 0x50224 +/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */ +#define TCM_REG_XX_OVFL_EVNT_ID 0x50048 +/* [RW 16] Indirect access to the XX table of the XX protection mechanism. + The fields are:[4:0] - tail pointer; [10:5] - Link List size; 15:11] - + header pointer. */ +#define TCM_REG_XX_TABLE 0x50240 +/* [RW 4] Load value for cfc ac credit cnt. */ +#define TM_REG_CFC_AC_CRDCNT_VAL 0x164208 +/* [RW 4] Load value for cfc cld credit cnt. */ +#define TM_REG_CFC_CLD_CRDCNT_VAL 0x164210 +/* [RW 8] Client0 context region. */ +#define TM_REG_CL0_CONT_REGION 0x164030 +/* [RW 8] Client1 context region. */ +#define TM_REG_CL1_CONT_REGION 0x164034 +/* [RW 8] Client2 context region. */ +#define TM_REG_CL2_CONT_REGION 0x164038 +/* [RW 2] Client in High priority client number. */ +#define TM_REG_CLIN_PRIOR0_CLIENT 0x164024 +/* [RW 4] Load value for clout0 cred cnt. */ +#define TM_REG_CLOUT_CRDCNT0_VAL 0x164220 +/* [RW 4] Load value for clout1 cred cnt. */ +#define TM_REG_CLOUT_CRDCNT1_VAL 0x164228 +/* [RW 4] Load value for clout2 cred cnt. */ +#define TM_REG_CLOUT_CRDCNT2_VAL 0x164230 +/* [RW 1] Enable client0 input. */ +#define TM_REG_EN_CL0_INPUT 0x164008 +/* [RW 1] Enable client1 input. */ +#define TM_REG_EN_CL1_INPUT 0x16400c +/* [RW 1] Enable client2 input. */ +#define TM_REG_EN_CL2_INPUT 0x164010 +#define TM_REG_EN_LINEAR0_TIMER 0x164014 +/* [RW 1] Enable real time counter. */ +#define TM_REG_EN_REAL_TIME_CNT 0x1640d8 +/* [RW 1] Enable for Timers state machines. */ +#define TM_REG_EN_TIMERS 0x164000 +/* [RW 4] Load value for expiration credit cnt. CFC max number of + outstanding load requests for timers (expiration) context loading. */ +#define TM_REG_EXP_CRDCNT_VAL 0x164238 +/* [RW 32] Linear0 logic address. */ +#define TM_REG_LIN0_LOGIC_ADDR 0x164240 +/* [RW 18] Linear0 Max active cid (in banks of 32 entries). */ +#define TM_REG_LIN0_MAX_ACTIVE_CID 0x164048 +/* [ST 16] Linear0 Number of scans counter. */ +#define TM_REG_LIN0_NUM_SCANS 0x1640a0 +/* [WB 64] Linear0 phy address. */ +#define TM_REG_LIN0_PHY_ADDR 0x164270 +/* [RW 1] Linear0 physical address valid. */ +#define TM_REG_LIN0_PHY_ADDR_VALID 0x164248 +#define TM_REG_LIN0_SCAN_ON 0x1640d0 +/* [RW 24] Linear0 array scan timeout. */ +#define TM_REG_LIN0_SCAN_TIME 0x16403c +#define TM_REG_LIN0_VNIC_UC 0x164128 +/* [RW 32] Linear1 logic address. */ +#define TM_REG_LIN1_LOGIC_ADDR 0x164250 +/* [WB 64] Linear1 phy address. */ +#define TM_REG_LIN1_PHY_ADDR 0x164280 +/* [RW 1] Linear1 physical address valid. */ +#define TM_REG_LIN1_PHY_ADDR_VALID 0x164258 +/* [RW 6] Linear timer set_clear fifo threshold. */ +#define TM_REG_LIN_SETCLR_FIFO_ALFULL_THR 0x164070 +/* [RW 2] Load value for pci arbiter credit cnt. */ +#define TM_REG_PCIARB_CRDCNT_VAL 0x164260 +/* [RW 20] The amount of hardware cycles for each timer tick. */ +#define TM_REG_TIMER_TICK_SIZE 0x16401c +/* [RW 8] Timers Context region. */ +#define TM_REG_TM_CONTEXT_REGION 0x164044 +/* [RW 1] Interrupt mask register #0 read/write */ +#define TM_REG_TM_INT_MASK 0x1640fc +/* [R 1] Interrupt register #0 read */ +#define TM_REG_TM_INT_STS 0x1640f0 +/* [RW 7] Parity mask register #0 read/write */ +#define TM_REG_TM_PRTY_MASK 0x16410c +/* [RC 7] Parity register #0 read clear */ +#define TM_REG_TM_PRTY_STS_CLR 0x164104 +/* [RW 8] The event id for aggregated interrupt 0 */ +#define TSDM_REG_AGG_INT_EVENT_0 0x42038 +#define TSDM_REG_AGG_INT_EVENT_1 0x4203c +#define TSDM_REG_AGG_INT_EVENT_2 0x42040 +#define TSDM_REG_AGG_INT_EVENT_3 0x42044 +#define TSDM_REG_AGG_INT_EVENT_4 0x42048 +/* [RW 1] The T bit for aggregated interrupt 0 */ +#define TSDM_REG_AGG_INT_T_0 0x420b8 +#define TSDM_REG_AGG_INT_T_1 0x420bc +/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ +#define TSDM_REG_CFC_RSP_START_ADDR 0x42008 +/* [RW 16] The maximum value of the completion counter #0 */ +#define TSDM_REG_CMP_COUNTER_MAX0 0x4201c +/* [RW 16] The maximum value of the completion counter #1 */ +#define TSDM_REG_CMP_COUNTER_MAX1 0x42020 +/* [RW 16] The maximum value of the completion counter #2 */ +#define TSDM_REG_CMP_COUNTER_MAX2 0x42024 +/* [RW 16] The maximum value of the completion counter #3 */ +#define TSDM_REG_CMP_COUNTER_MAX3 0x42028 +/* [RW 13] The start address in the internal RAM for the completion + counters. */ +#define TSDM_REG_CMP_COUNTER_START_ADDR 0x4200c +#define TSDM_REG_ENABLE_IN1 0x42238 +#define TSDM_REG_ENABLE_IN2 0x4223c +#define TSDM_REG_ENABLE_OUT1 0x42240 +#define TSDM_REG_ENABLE_OUT2 0x42244 +/* [RW 4] The initial number of messages that can be sent to the pxp control + interface without receiving any ACK. */ +#define TSDM_REG_INIT_CREDIT_PXP_CTRL 0x424bc +/* [ST 32] The number of ACK after placement messages received */ +#define TSDM_REG_NUM_OF_ACK_AFTER_PLACE 0x4227c +/* [ST 32] The number of packet end messages received from the parser */ +#define TSDM_REG_NUM_OF_PKT_END_MSG 0x42274 +/* [ST 32] The number of requests received from the pxp async if */ +#define TSDM_REG_NUM_OF_PXP_ASYNC_REQ 0x42278 +/* [ST 32] The number of commands received in queue 0 */ +#define TSDM_REG_NUM_OF_Q0_CMD 0x42248 +/* [ST 32] The number of commands received in queue 10 */ +#define TSDM_REG_NUM_OF_Q10_CMD 0x4226c +/* [ST 32] The number of commands received in queue 11 */ +#define TSDM_REG_NUM_OF_Q11_CMD 0x42270 +/* [ST 32] The number of commands received in queue 1 */ +#define TSDM_REG_NUM_OF_Q1_CMD 0x4224c +/* [ST 32] The number of commands received in queue 3 */ +#define TSDM_REG_NUM_OF_Q3_CMD 0x42250 +/* [ST 32] The number of commands received in queue 4 */ +#define TSDM_REG_NUM_OF_Q4_CMD 0x42254 +/* [ST 32] The number of commands received in queue 5 */ +#define TSDM_REG_NUM_OF_Q5_CMD 0x42258 +/* [ST 32] The number of commands received in queue 6 */ +#define TSDM_REG_NUM_OF_Q6_CMD 0x4225c +/* [ST 32] The number of commands received in queue 7 */ +#define TSDM_REG_NUM_OF_Q7_CMD 0x42260 +/* [ST 32] The number of commands received in queue 8 */ +#define TSDM_REG_NUM_OF_Q8_CMD 0x42264 +/* [ST 32] The number of commands received in queue 9 */ +#define TSDM_REG_NUM_OF_Q9_CMD 0x42268 +/* [RW 13] The start address in the internal RAM for the packet end message */ +#define TSDM_REG_PCK_END_MSG_START_ADDR 0x42014 +/* [RW 13] The start address in the internal RAM for queue counters */ +#define TSDM_REG_Q_COUNTER_START_ADDR 0x42010 +/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */ +#define TSDM_REG_RSP_PXP_CTRL_RDATA_EMPTY 0x42548 +/* [R 1] parser fifo empty in sdm_sync block */ +#define TSDM_REG_SYNC_PARSER_EMPTY 0x42550 +/* [R 1] parser serial fifo empty in sdm_sync block */ +#define TSDM_REG_SYNC_SYNC_EMPTY 0x42558 +/* [RW 32] Tick for timer counter. Applicable only when + ~tsdm_registers_timer_tick_enable.timer_tick_enable =1 */ +#define TSDM_REG_TIMER_TICK 0x42000 +/* [RW 32] Interrupt mask register #0 read/write */ +#define TSDM_REG_TSDM_INT_MASK_0 0x4229c +#define TSDM_REG_TSDM_INT_MASK_1 0x422ac +/* [R 32] Interrupt register #0 read */ +#define TSDM_REG_TSDM_INT_STS_0 0x42290 +#define TSDM_REG_TSDM_INT_STS_1 0x422a0 +/* [RW 11] Parity mask register #0 read/write */ +#define TSDM_REG_TSDM_PRTY_MASK 0x422bc +/* [R 11] Parity register #0 read */ +#define TSDM_REG_TSDM_PRTY_STS 0x422b0 +/* [RC 11] Parity register #0 read clear */ +#define TSDM_REG_TSDM_PRTY_STS_CLR 0x422b4 +/* [RW 5] The number of time_slots in the arbitration cycle */ +#define TSEM_REG_ARB_CYCLE_SIZE 0x180034 +/* [RW 3] The source that is associated with arbitration element 0. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2 */ +#define TSEM_REG_ARB_ELEMENT0 0x180020 +/* [RW 3] The source that is associated with arbitration element 1. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~tsem_registers_arb_element0.arb_element0 */ +#define TSEM_REG_ARB_ELEMENT1 0x180024 +/* [RW 3] The source that is associated with arbitration element 2. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~tsem_registers_arb_element0.arb_element0 + and ~tsem_registers_arb_element1.arb_element1 */ +#define TSEM_REG_ARB_ELEMENT2 0x180028 +/* [RW 3] The source that is associated with arbitration element 3. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2.Could + not be equal to register ~tsem_registers_arb_element0.arb_element0 and + ~tsem_registers_arb_element1.arb_element1 and + ~tsem_registers_arb_element2.arb_element2 */ +#define TSEM_REG_ARB_ELEMENT3 0x18002c +/* [RW 3] The source that is associated with arbitration element 4. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~tsem_registers_arb_element0.arb_element0 + and ~tsem_registers_arb_element1.arb_element1 and + ~tsem_registers_arb_element2.arb_element2 and + ~tsem_registers_arb_element3.arb_element3 */ +#define TSEM_REG_ARB_ELEMENT4 0x180030 +#define TSEM_REG_ENABLE_IN 0x1800a4 +#define TSEM_REG_ENABLE_OUT 0x1800a8 +/* [RW 32] This address space contains all registers and memories that are + placed in SEM_FAST block. The SEM_FAST registers are described in + appendix B. In order to access the sem_fast registers the base address + ~fast_memory.fast_memory should be added to eachsem_fast register offset. */ +#define TSEM_REG_FAST_MEMORY 0x1a0000 +/* [RW 1] Disables input messages from FIC0 May be updated during run_time + by the microcode */ +#define TSEM_REG_FIC0_DISABLE 0x180224 +/* [RW 1] Disables input messages from FIC1 May be updated during run_time + by the microcode */ +#define TSEM_REG_FIC1_DISABLE 0x180234 +/* [RW 15] Interrupt table Read and write access to it is not possible in + the middle of the work */ +#define TSEM_REG_INT_TABLE 0x180400 +/* [ST 24] Statistics register. The number of messages that entered through + FIC0 */ +#define TSEM_REG_MSG_NUM_FIC0 0x180000 +/* [ST 24] Statistics register. The number of messages that entered through + FIC1 */ +#define TSEM_REG_MSG_NUM_FIC1 0x180004 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC0 */ +#define TSEM_REG_MSG_NUM_FOC0 0x180008 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC1 */ +#define TSEM_REG_MSG_NUM_FOC1 0x18000c +/* [ST 24] Statistics register. The number of messages that were sent to + FOC2 */ +#define TSEM_REG_MSG_NUM_FOC2 0x180010 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC3 */ +#define TSEM_REG_MSG_NUM_FOC3 0x180014 +/* [RW 1] Disables input messages from the passive buffer May be updated + during run_time by the microcode */ +#define TSEM_REG_PAS_DISABLE 0x18024c +/* [WB 128] Debug only. Passive buffer memory */ +#define TSEM_REG_PASSIVE_BUFFER 0x181000 +/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */ +#define TSEM_REG_PRAM 0x1c0000 +/* [R 8] Valid sleeping threads indication have bit per thread */ +#define TSEM_REG_SLEEP_THREADS_VALID 0x18026c +/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */ +#define TSEM_REG_SLOW_EXT_STORE_EMPTY 0x1802a0 +/* [RW 8] List of free threads . There is a bit per thread. */ +#define TSEM_REG_THREADS_LIST 0x1802e4 +/* [RC 32] Parity register #0 read clear */ +#define TSEM_REG_TSEM_PRTY_STS_CLR_0 0x180118 +#define TSEM_REG_TSEM_PRTY_STS_CLR_1 0x180128 +/* [RW 3] The arbitration scheme of time_slot 0 */ +#define TSEM_REG_TS_0_AS 0x180038 +/* [RW 3] The arbitration scheme of time_slot 10 */ +#define TSEM_REG_TS_10_AS 0x180060 +/* [RW 3] The arbitration scheme of time_slot 11 */ +#define TSEM_REG_TS_11_AS 0x180064 +/* [RW 3] The arbitration scheme of time_slot 12 */ +#define TSEM_REG_TS_12_AS 0x180068 +/* [RW 3] The arbitration scheme of time_slot 13 */ +#define TSEM_REG_TS_13_AS 0x18006c +/* [RW 3] The arbitration scheme of time_slot 14 */ +#define TSEM_REG_TS_14_AS 0x180070 +/* [RW 3] The arbitration scheme of time_slot 15 */ +#define TSEM_REG_TS_15_AS 0x180074 +/* [RW 3] The arbitration scheme of time_slot 16 */ +#define TSEM_REG_TS_16_AS 0x180078 +/* [RW 3] The arbitration scheme of time_slot 17 */ +#define TSEM_REG_TS_17_AS 0x18007c +/* [RW 3] The arbitration scheme of time_slot 18 */ +#define TSEM_REG_TS_18_AS 0x180080 +/* [RW 3] The arbitration scheme of time_slot 1 */ +#define TSEM_REG_TS_1_AS 0x18003c +/* [RW 3] The arbitration scheme of time_slot 2 */ +#define TSEM_REG_TS_2_AS 0x180040 +/* [RW 3] The arbitration scheme of time_slot 3 */ +#define TSEM_REG_TS_3_AS 0x180044 +/* [RW 3] The arbitration scheme of time_slot 4 */ +#define TSEM_REG_TS_4_AS 0x180048 +/* [RW 3] The arbitration scheme of time_slot 5 */ +#define TSEM_REG_TS_5_AS 0x18004c +/* [RW 3] The arbitration scheme of time_slot 6 */ +#define TSEM_REG_TS_6_AS 0x180050 +/* [RW 3] The arbitration scheme of time_slot 7 */ +#define TSEM_REG_TS_7_AS 0x180054 +/* [RW 3] The arbitration scheme of time_slot 8 */ +#define TSEM_REG_TS_8_AS 0x180058 +/* [RW 3] The arbitration scheme of time_slot 9 */ +#define TSEM_REG_TS_9_AS 0x18005c +/* [RW 32] Interrupt mask register #0 read/write */ +#define TSEM_REG_TSEM_INT_MASK_0 0x180100 +#define TSEM_REG_TSEM_INT_MASK_1 0x180110 +/* [R 32] Interrupt register #0 read */ +#define TSEM_REG_TSEM_INT_STS_0 0x1800f4 +#define TSEM_REG_TSEM_INT_STS_1 0x180104 +/* [RW 32] Parity mask register #0 read/write */ +#define TSEM_REG_TSEM_PRTY_MASK_0 0x180120 +#define TSEM_REG_TSEM_PRTY_MASK_1 0x180130 +/* [R 32] Parity register #0 read */ +#define TSEM_REG_TSEM_PRTY_STS_0 0x180114 +#define TSEM_REG_TSEM_PRTY_STS_1 0x180124 +/* [W 7] VF or PF ID for reset error bit. Values 0-63 reset error bit for 64 + * VF; values 64-67 reset error for 4 PF; values 68-127 are not valid. */ +#define TSEM_REG_VFPF_ERR_NUM 0x180380 +/* [RW 32] Indirect access to AG context with 32-bits granularity. The bits + * [10:8] of the address should be the offset within the accessed LCID + * context; the bits [7:0] are the accessed LCID.Example: to write to REG10 + * LCID100. The RBC address should be 12'ha64. */ +#define UCM_REG_AG_CTX 0xe2000 +/* [R 5] Used to read the XX protection CAM occupancy counter. */ +#define UCM_REG_CAM_OCCUP 0xe0170 +/* [RW 1] CDU AG read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define UCM_REG_CDU_AG_RD_IFEN 0xe0038 +/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input + are disregarded; all other signals are treated as usual; if 1 - normal + activity. */ +#define UCM_REG_CDU_AG_WR_IFEN 0xe0034 +/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define UCM_REG_CDU_SM_RD_IFEN 0xe0040 +/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid + input is disregarded; all other signals are treated as usual; if 1 - + normal activity. */ +#define UCM_REG_CDU_SM_WR_IFEN 0xe003c +/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 1 at start-up. */ +#define UCM_REG_CFC_INIT_CRD 0xe0204 +/* [RW 3] The weight of the CP input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_CP_WEIGHT 0xe00c4 +/* [RW 1] Input csem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_CSEM_IFEN 0xe0028 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the csem interface is detected. */ +#define UCM_REG_CSEM_LENGTH_MIS 0xe0160 +/* [RW 3] The weight of the input csem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_CSEM_WEIGHT 0xe00b8 +/* [RW 1] Input dorq Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_DORQ_IFEN 0xe0030 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the dorq interface is detected. */ +#define UCM_REG_DORQ_LENGTH_MIS 0xe0168 +/* [RW 3] The weight of the input dorq in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_DORQ_WEIGHT 0xe00c0 +/* [RW 8] The Event ID in case ErrorFlg input message bit is set. */ +#define UCM_REG_ERR_EVNT_ID 0xe00a4 +/* [RW 28] The CM erroneous header for QM and Timers formatting. */ +#define UCM_REG_ERR_UCM_HDR 0xe00a0 +/* [RW 8] The Event ID for Timers expiration. */ +#define UCM_REG_EXPR_EVNT_ID 0xe00a8 +/* [RW 8] FIC0 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define UCM_REG_FIC0_INIT_CRD 0xe020c +/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define UCM_REG_FIC1_INIT_CRD 0xe0210 +/* [RW 1] Arbitration between Input Arbiter groups: 0 - fair Round-Robin; 1 + - strict priority defined by ~ucm_registers_gr_ag_pr.gr_ag_pr; + ~ucm_registers_gr_ld0_pr.gr_ld0_pr and + ~ucm_registers_gr_ld1_pr.gr_ld1_pr. */ +#define UCM_REG_GR_ARB_TYPE 0xe0144 +/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Store channel group is + compliment to the others. */ +#define UCM_REG_GR_LD0_PR 0xe014c +/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Store channel group is + compliment to the others. */ +#define UCM_REG_GR_LD1_PR 0xe0150 +/* [RW 2] The queue index for invalidate counter flag decision. */ +#define UCM_REG_INV_CFLG_Q 0xe00e4 +/* [RW 5] The number of double REG-pairs; loaded from the STORM context and + sent to STORM; for a specific connection type. the double REG-pairs are + used in order to align to STORM context row size of 128 bits. The offset + of these data in the STORM context is always 0. Index _i stands for the + connection type (one of 16). */ +#define UCM_REG_N_SM_CTX_LD_0 0xe0054 +#define UCM_REG_N_SM_CTX_LD_1 0xe0058 +#define UCM_REG_N_SM_CTX_LD_2 0xe005c +#define UCM_REG_N_SM_CTX_LD_3 0xe0060 +#define UCM_REG_N_SM_CTX_LD_4 0xe0064 +#define UCM_REG_N_SM_CTX_LD_5 0xe0068 +#define UCM_REG_PHYS_QNUM0_0 0xe0110 +#define UCM_REG_PHYS_QNUM0_1 0xe0114 +#define UCM_REG_PHYS_QNUM1_0 0xe0118 +#define UCM_REG_PHYS_QNUM1_1 0xe011c +#define UCM_REG_PHYS_QNUM2_0 0xe0120 +#define UCM_REG_PHYS_QNUM2_1 0xe0124 +#define UCM_REG_PHYS_QNUM3_0 0xe0128 +#define UCM_REG_PHYS_QNUM3_1 0xe012c +/* [RW 8] The Event ID for Timers formatting in case of stop done. */ +#define UCM_REG_STOP_EVNT_ID 0xe00ac +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the STORM interface is detected. */ +#define UCM_REG_STORM_LENGTH_MIS 0xe0154 +/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_STORM_UCM_IFEN 0xe0010 +/* [RW 3] The weight of the STORM input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_STORM_WEIGHT 0xe00b0 +/* [RW 4] Timers output initial credit. Max credit available - 15.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 4 at start-up. */ +#define UCM_REG_TM_INIT_CRD 0xe021c +/* [RW 28] The CM header for Timers expiration command. */ +#define UCM_REG_TM_UCM_HDR 0xe009c +/* [RW 1] Timers - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_TM_UCM_IFEN 0xe001c +/* [RW 3] The weight of the Timers input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_TM_WEIGHT 0xe00d4 +/* [RW 1] Input tsem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_TSEM_IFEN 0xe0024 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the tsem interface is detected. */ +#define UCM_REG_TSEM_LENGTH_MIS 0xe015c +/* [RW 3] The weight of the input tsem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_TSEM_WEIGHT 0xe00b4 +/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_UCM_CFC_IFEN 0xe0044 +/* [RW 11] Interrupt mask register #0 read/write */ +#define UCM_REG_UCM_INT_MASK 0xe01d4 +/* [R 11] Interrupt register #0 read */ +#define UCM_REG_UCM_INT_STS 0xe01c8 +/* [RW 27] Parity mask register #0 read/write */ +#define UCM_REG_UCM_PRTY_MASK 0xe01e4 +/* [R 27] Parity register #0 read */ +#define UCM_REG_UCM_PRTY_STS 0xe01d8 +/* [RC 27] Parity register #0 read clear */ +#define UCM_REG_UCM_PRTY_STS_CLR 0xe01dc +/* [RW 2] The size of AG context region 0 in REG-pairs. Designates the MS + REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). + Is used to determine the number of the AG context REG-pairs written back; + when the Reg1WbFlg isn't set. */ +#define UCM_REG_UCM_REG0_SZ 0xe00dc +/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_UCM_STORM0_IFEN 0xe0004 +/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_UCM_STORM1_IFEN 0xe0008 +/* [RW 1] CM - Timers Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_UCM_TM_IFEN 0xe0020 +/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_UCM_UQM_IFEN 0xe000c +/* [RW 1] If set the Q index; received from the QM is inserted to event ID. */ +#define UCM_REG_UCM_UQM_USE_Q 0xe00d8 +/* [RW 6] QM output initial credit. Max credit available - 32.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 32 at start-up. */ +#define UCM_REG_UQM_INIT_CRD 0xe0220 +/* [RW 3] The weight of the QM (primary) input in the WRR mechanism. 0 + stands for weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_UQM_P_WEIGHT 0xe00cc +/* [RW 3] The weight of the QM (secondary) input in the WRR mechanism. 0 + stands for weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_UQM_S_WEIGHT 0xe00d0 +/* [RW 28] The CM header value for QM request (primary). */ +#define UCM_REG_UQM_UCM_HDR_P 0xe0094 +/* [RW 28] The CM header value for QM request (secondary). */ +#define UCM_REG_UQM_UCM_HDR_S 0xe0098 +/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_UQM_UCM_IFEN 0xe0014 +/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define UCM_REG_USDM_IFEN 0xe0018 +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the SDM interface is detected. */ +#define UCM_REG_USDM_LENGTH_MIS 0xe0158 +/* [RW 3] The weight of the SDM input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_USDM_WEIGHT 0xe00c8 +/* [RW 1] Input xsem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define UCM_REG_XSEM_IFEN 0xe002c +/* [RC 1] Set when the message length mismatch (relative to last indication) + at the xsem interface isdetected. */ +#define UCM_REG_XSEM_LENGTH_MIS 0xe0164 +/* [RW 3] The weight of the input xsem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define UCM_REG_XSEM_WEIGHT 0xe00bc +/* [RW 20] Indirect access to the descriptor table of the XX protection + mechanism. The fields are:[5:0] - message length; 14:6] - message + pointer; 19:15] - next pointer. */ +#define UCM_REG_XX_DESCR_TABLE 0xe0280 +#define UCM_REG_XX_DESCR_TABLE_SIZE 27 +/* [R 6] Use to read the XX protection Free counter. */ +#define UCM_REG_XX_FREE 0xe016c +/* [RW 6] Initial value for the credit counter; responsible for fulfilling + of the Input Stage XX protection buffer by the XX protection pending + messages. Write writes the initial credit value; read returns the current + value of the credit counter. Must be initialized to 12 at start-up. */ +#define UCM_REG_XX_INIT_CRD 0xe0224 +/* [RW 6] The maximum number of pending messages; which may be stored in XX + protection. ~ucm_registers_xx_free.xx_free read on read. */ +#define UCM_REG_XX_MSG_NUM 0xe0228 +/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */ +#define UCM_REG_XX_OVFL_EVNT_ID 0xe004c +/* [RW 16] Indirect access to the XX table of the XX protection mechanism. + The fields are: [4:0] - tail pointer; 10:5] - Link List size; 15:11] - + header pointer. */ +#define UCM_REG_XX_TABLE 0xe0300 +#define UMAC_COMMAND_CONFIG_REG_IGNORE_TX_PAUSE (0x1<<28) +#define UMAC_COMMAND_CONFIG_REG_LOOP_ENA (0x1<<15) +#define UMAC_COMMAND_CONFIG_REG_NO_LGTH_CHECK (0x1<<24) +#define UMAC_COMMAND_CONFIG_REG_PAD_EN (0x1<<5) +#define UMAC_COMMAND_CONFIG_REG_PAUSE_IGNORE (0x1<<8) +#define UMAC_COMMAND_CONFIG_REG_PROMIS_EN (0x1<<4) +#define UMAC_COMMAND_CONFIG_REG_RX_ENA (0x1<<1) +#define UMAC_COMMAND_CONFIG_REG_SW_RESET (0x1<<13) +#define UMAC_COMMAND_CONFIG_REG_TX_ENA (0x1<<0) +#define UMAC_REG_COMMAND_CONFIG 0x8 +/* [RW 32] Register Bit 0 refers to Bit 16 of the MAC address; Bit 1 refers + * to bit 17 of the MAC address etc. */ +#define UMAC_REG_MAC_ADDR0 0xc +/* [RW 16] Register Bit 0 refers to Bit 0 of the MAC address; Register Bit 1 + * refers to Bit 1 of the MAC address etc. Bits 16 to 31 are reserved. */ +#define UMAC_REG_MAC_ADDR1 0x10 +/* [RW 14] Defines a 14-Bit maximum frame length used by the MAC receive + * logic to check frames. */ +#define UMAC_REG_MAXFR 0x14 +/* [RW 8] The event id for aggregated interrupt 0 */ +#define USDM_REG_AGG_INT_EVENT_0 0xc4038 +#define USDM_REG_AGG_INT_EVENT_1 0xc403c +#define USDM_REG_AGG_INT_EVENT_2 0xc4040 +#define USDM_REG_AGG_INT_EVENT_4 0xc4048 +#define USDM_REG_AGG_INT_EVENT_5 0xc404c +#define USDM_REG_AGG_INT_EVENT_6 0xc4050 +/* [RW 1] For each aggregated interrupt index whether the mode is normal (0) + or auto-mask-mode (1) */ +#define USDM_REG_AGG_INT_MODE_0 0xc41b8 +#define USDM_REG_AGG_INT_MODE_1 0xc41bc +#define USDM_REG_AGG_INT_MODE_4 0xc41c8 +#define USDM_REG_AGG_INT_MODE_5 0xc41cc +#define USDM_REG_AGG_INT_MODE_6 0xc41d0 +/* [RW 1] The T bit for aggregated interrupt 5 */ +#define USDM_REG_AGG_INT_T_5 0xc40cc +#define USDM_REG_AGG_INT_T_6 0xc40d0 +/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ +#define USDM_REG_CFC_RSP_START_ADDR 0xc4008 +/* [RW 16] The maximum value of the completion counter #0 */ +#define USDM_REG_CMP_COUNTER_MAX0 0xc401c +/* [RW 16] The maximum value of the completion counter #1 */ +#define USDM_REG_CMP_COUNTER_MAX1 0xc4020 +/* [RW 16] The maximum value of the completion counter #2 */ +#define USDM_REG_CMP_COUNTER_MAX2 0xc4024 +/* [RW 16] The maximum value of the completion counter #3 */ +#define USDM_REG_CMP_COUNTER_MAX3 0xc4028 +/* [RW 13] The start address in the internal RAM for the completion + counters. */ +#define USDM_REG_CMP_COUNTER_START_ADDR 0xc400c +#define USDM_REG_ENABLE_IN1 0xc4238 +#define USDM_REG_ENABLE_IN2 0xc423c +#define USDM_REG_ENABLE_OUT1 0xc4240 +#define USDM_REG_ENABLE_OUT2 0xc4244 +/* [RW 4] The initial number of messages that can be sent to the pxp control + interface without receiving any ACK. */ +#define USDM_REG_INIT_CREDIT_PXP_CTRL 0xc44c0 +/* [ST 32] The number of ACK after placement messages received */ +#define USDM_REG_NUM_OF_ACK_AFTER_PLACE 0xc4280 +/* [ST 32] The number of packet end messages received from the parser */ +#define USDM_REG_NUM_OF_PKT_END_MSG 0xc4278 +/* [ST 32] The number of requests received from the pxp async if */ +#define USDM_REG_NUM_OF_PXP_ASYNC_REQ 0xc427c +/* [ST 32] The number of commands received in queue 0 */ +#define USDM_REG_NUM_OF_Q0_CMD 0xc4248 +/* [ST 32] The number of commands received in queue 10 */ +#define USDM_REG_NUM_OF_Q10_CMD 0xc4270 +/* [ST 32] The number of commands received in queue 11 */ +#define USDM_REG_NUM_OF_Q11_CMD 0xc4274 +/* [ST 32] The number of commands received in queue 1 */ +#define USDM_REG_NUM_OF_Q1_CMD 0xc424c +/* [ST 32] The number of commands received in queue 2 */ +#define USDM_REG_NUM_OF_Q2_CMD 0xc4250 +/* [ST 32] The number of commands received in queue 3 */ +#define USDM_REG_NUM_OF_Q3_CMD 0xc4254 +/* [ST 32] The number of commands received in queue 4 */ +#define USDM_REG_NUM_OF_Q4_CMD 0xc4258 +/* [ST 32] The number of commands received in queue 5 */ +#define USDM_REG_NUM_OF_Q5_CMD 0xc425c +/* [ST 32] The number of commands received in queue 6 */ +#define USDM_REG_NUM_OF_Q6_CMD 0xc4260 +/* [ST 32] The number of commands received in queue 7 */ +#define USDM_REG_NUM_OF_Q7_CMD 0xc4264 +/* [ST 32] The number of commands received in queue 8 */ +#define USDM_REG_NUM_OF_Q8_CMD 0xc4268 +/* [ST 32] The number of commands received in queue 9 */ +#define USDM_REG_NUM_OF_Q9_CMD 0xc426c +/* [RW 13] The start address in the internal RAM for the packet end message */ +#define USDM_REG_PCK_END_MSG_START_ADDR 0xc4014 +/* [RW 13] The start address in the internal RAM for queue counters */ +#define USDM_REG_Q_COUNTER_START_ADDR 0xc4010 +/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */ +#define USDM_REG_RSP_PXP_CTRL_RDATA_EMPTY 0xc4550 +/* [R 1] parser fifo empty in sdm_sync block */ +#define USDM_REG_SYNC_PARSER_EMPTY 0xc4558 +/* [R 1] parser serial fifo empty in sdm_sync block */ +#define USDM_REG_SYNC_SYNC_EMPTY 0xc4560 +/* [RW 32] Tick for timer counter. Applicable only when + ~usdm_registers_timer_tick_enable.timer_tick_enable =1 */ +#define USDM_REG_TIMER_TICK 0xc4000 +/* [RW 32] Interrupt mask register #0 read/write */ +#define USDM_REG_USDM_INT_MASK_0 0xc42a0 +#define USDM_REG_USDM_INT_MASK_1 0xc42b0 +/* [R 32] Interrupt register #0 read */ +#define USDM_REG_USDM_INT_STS_0 0xc4294 +#define USDM_REG_USDM_INT_STS_1 0xc42a4 +/* [RW 11] Parity mask register #0 read/write */ +#define USDM_REG_USDM_PRTY_MASK 0xc42c0 +/* [R 11] Parity register #0 read */ +#define USDM_REG_USDM_PRTY_STS 0xc42b4 +/* [RC 11] Parity register #0 read clear */ +#define USDM_REG_USDM_PRTY_STS_CLR 0xc42b8 +/* [RW 5] The number of time_slots in the arbitration cycle */ +#define USEM_REG_ARB_CYCLE_SIZE 0x300034 +/* [RW 3] The source that is associated with arbitration element 0. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2 */ +#define USEM_REG_ARB_ELEMENT0 0x300020 +/* [RW 3] The source that is associated with arbitration element 1. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~usem_registers_arb_element0.arb_element0 */ +#define USEM_REG_ARB_ELEMENT1 0x300024 +/* [RW 3] The source that is associated with arbitration element 2. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~usem_registers_arb_element0.arb_element0 + and ~usem_registers_arb_element1.arb_element1 */ +#define USEM_REG_ARB_ELEMENT2 0x300028 +/* [RW 3] The source that is associated with arbitration element 3. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2.Could + not be equal to register ~usem_registers_arb_element0.arb_element0 and + ~usem_registers_arb_element1.arb_element1 and + ~usem_registers_arb_element2.arb_element2 */ +#define USEM_REG_ARB_ELEMENT3 0x30002c +/* [RW 3] The source that is associated with arbitration element 4. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~usem_registers_arb_element0.arb_element0 + and ~usem_registers_arb_element1.arb_element1 and + ~usem_registers_arb_element2.arb_element2 and + ~usem_registers_arb_element3.arb_element3 */ +#define USEM_REG_ARB_ELEMENT4 0x300030 +#define USEM_REG_ENABLE_IN 0x3000a4 +#define USEM_REG_ENABLE_OUT 0x3000a8 +/* [RW 32] This address space contains all registers and memories that are + placed in SEM_FAST block. The SEM_FAST registers are described in + appendix B. In order to access the sem_fast registers the base address + ~fast_memory.fast_memory should be added to eachsem_fast register offset. */ +#define USEM_REG_FAST_MEMORY 0x320000 +/* [RW 1] Disables input messages from FIC0 May be updated during run_time + by the microcode */ +#define USEM_REG_FIC0_DISABLE 0x300224 +/* [RW 1] Disables input messages from FIC1 May be updated during run_time + by the microcode */ +#define USEM_REG_FIC1_DISABLE 0x300234 +/* [RW 15] Interrupt table Read and write access to it is not possible in + the middle of the work */ +#define USEM_REG_INT_TABLE 0x300400 +/* [ST 24] Statistics register. The number of messages that entered through + FIC0 */ +#define USEM_REG_MSG_NUM_FIC0 0x300000 +/* [ST 24] Statistics register. The number of messages that entered through + FIC1 */ +#define USEM_REG_MSG_NUM_FIC1 0x300004 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC0 */ +#define USEM_REG_MSG_NUM_FOC0 0x300008 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC1 */ +#define USEM_REG_MSG_NUM_FOC1 0x30000c +/* [ST 24] Statistics register. The number of messages that were sent to + FOC2 */ +#define USEM_REG_MSG_NUM_FOC2 0x300010 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC3 */ +#define USEM_REG_MSG_NUM_FOC3 0x300014 +/* [RW 1] Disables input messages from the passive buffer May be updated + during run_time by the microcode */ +#define USEM_REG_PAS_DISABLE 0x30024c +/* [WB 128] Debug only. Passive buffer memory */ +#define USEM_REG_PASSIVE_BUFFER 0x302000 +/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */ +#define USEM_REG_PRAM 0x340000 +/* [R 16] Valid sleeping threads indication have bit per thread */ +#define USEM_REG_SLEEP_THREADS_VALID 0x30026c +/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */ +#define USEM_REG_SLOW_EXT_STORE_EMPTY 0x3002a0 +/* [RW 16] List of free threads . There is a bit per thread. */ +#define USEM_REG_THREADS_LIST 0x3002e4 +/* [RW 3] The arbitration scheme of time_slot 0 */ +#define USEM_REG_TS_0_AS 0x300038 +/* [RW 3] The arbitration scheme of time_slot 10 */ +#define USEM_REG_TS_10_AS 0x300060 +/* [RW 3] The arbitration scheme of time_slot 11 */ +#define USEM_REG_TS_11_AS 0x300064 +/* [RW 3] The arbitration scheme of time_slot 12 */ +#define USEM_REG_TS_12_AS 0x300068 +/* [RW 3] The arbitration scheme of time_slot 13 */ +#define USEM_REG_TS_13_AS 0x30006c +/* [RW 3] The arbitration scheme of time_slot 14 */ +#define USEM_REG_TS_14_AS 0x300070 +/* [RW 3] The arbitration scheme of time_slot 15 */ +#define USEM_REG_TS_15_AS 0x300074 +/* [RW 3] The arbitration scheme of time_slot 16 */ +#define USEM_REG_TS_16_AS 0x300078 +/* [RW 3] The arbitration scheme of time_slot 17 */ +#define USEM_REG_TS_17_AS 0x30007c +/* [RW 3] The arbitration scheme of time_slot 18 */ +#define USEM_REG_TS_18_AS 0x300080 +/* [RW 3] The arbitration scheme of time_slot 1 */ +#define USEM_REG_TS_1_AS 0x30003c +/* [RW 3] The arbitration scheme of time_slot 2 */ +#define USEM_REG_TS_2_AS 0x300040 +/* [RW 3] The arbitration scheme of time_slot 3 */ +#define USEM_REG_TS_3_AS 0x300044 +/* [RW 3] The arbitration scheme of time_slot 4 */ +#define USEM_REG_TS_4_AS 0x300048 +/* [RW 3] The arbitration scheme of time_slot 5 */ +#define USEM_REG_TS_5_AS 0x30004c +/* [RW 3] The arbitration scheme of time_slot 6 */ +#define USEM_REG_TS_6_AS 0x300050 +/* [RW 3] The arbitration scheme of time_slot 7 */ +#define USEM_REG_TS_7_AS 0x300054 +/* [RW 3] The arbitration scheme of time_slot 8 */ +#define USEM_REG_TS_8_AS 0x300058 +/* [RW 3] The arbitration scheme of time_slot 9 */ +#define USEM_REG_TS_9_AS 0x30005c +/* [RW 32] Interrupt mask register #0 read/write */ +#define USEM_REG_USEM_INT_MASK_0 0x300110 +#define USEM_REG_USEM_INT_MASK_1 0x300120 +/* [R 32] Interrupt register #0 read */ +#define USEM_REG_USEM_INT_STS_0 0x300104 +#define USEM_REG_USEM_INT_STS_1 0x300114 +/* [RW 32] Parity mask register #0 read/write */ +#define USEM_REG_USEM_PRTY_MASK_0 0x300130 +#define USEM_REG_USEM_PRTY_MASK_1 0x300140 +/* [R 32] Parity register #0 read */ +#define USEM_REG_USEM_PRTY_STS_0 0x300124 +#define USEM_REG_USEM_PRTY_STS_1 0x300134 +/* [RC 32] Parity register #0 read clear */ +#define USEM_REG_USEM_PRTY_STS_CLR_0 0x300128 +#define USEM_REG_USEM_PRTY_STS_CLR_1 0x300138 +/* [W 7] VF or PF ID for reset error bit. Values 0-63 reset error bit for 64 + * VF; values 64-67 reset error for 4 PF; values 68-127 are not valid. */ +#define USEM_REG_VFPF_ERR_NUM 0x300380 +#define VFC_MEMORIES_RST_REG_CAM_RST (0x1<<0) +#define VFC_MEMORIES_RST_REG_RAM_RST (0x1<<1) +#define VFC_REG_MEMORIES_RST 0x1943c +/* [RW 32] Indirect access to AG context with 32-bits granularity. The bits + * [12:8] of the address should be the offset within the accessed LCID + * context; the bits [7:0] are the accessed LCID.Example: to write to REG10 + * LCID100. The RBC address should be 13'ha64. */ +#define XCM_REG_AG_CTX 0x28000 +/* [RW 2] The queue index for registration on Aux1 counter flag. */ +#define XCM_REG_AUX1_Q 0x20134 +/* [RW 2] Per each decision rule the queue index to register to. */ +#define XCM_REG_AUX_CNT_FLG_Q_19 0x201b0 +/* [R 5] Used to read the XX protection CAM occupancy counter. */ +#define XCM_REG_CAM_OCCUP 0x20244 +/* [RW 1] CDU AG read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define XCM_REG_CDU_AG_RD_IFEN 0x20044 +/* [RW 1] CDU AG write Interface enable. If 0 - the request and valid input + are disregarded; all other signals are treated as usual; if 1 - normal + activity. */ +#define XCM_REG_CDU_AG_WR_IFEN 0x20040 +/* [RW 1] CDU STORM read Interface enable. If 0 - the request input is + disregarded; valid output is deasserted; all other signals are treated as + usual; if 1 - normal activity. */ +#define XCM_REG_CDU_SM_RD_IFEN 0x2004c +/* [RW 1] CDU STORM write Interface enable. If 0 - the request and valid + input is disregarded; all other signals are treated as usual; if 1 - + normal activity. */ +#define XCM_REG_CDU_SM_WR_IFEN 0x20048 +/* [RW 4] CFC output initial credit. Max credit available - 15.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 1 at start-up. */ +#define XCM_REG_CFC_INIT_CRD 0x20404 +/* [RW 3] The weight of the CP input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_CP_WEIGHT 0x200dc +/* [RW 1] Input csem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_CSEM_IFEN 0x20028 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the csem interface. */ +#define XCM_REG_CSEM_LENGTH_MIS 0x20228 +/* [RW 3] The weight of the input csem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_CSEM_WEIGHT 0x200c4 +/* [RW 1] Input dorq Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_DORQ_IFEN 0x20030 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the dorq interface. */ +#define XCM_REG_DORQ_LENGTH_MIS 0x20230 +/* [RW 3] The weight of the input dorq in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_DORQ_WEIGHT 0x200cc +/* [RW 8] The Event ID in case the ErrorFlg input message bit is set. */ +#define XCM_REG_ERR_EVNT_ID 0x200b0 +/* [RW 28] The CM erroneous header for QM and Timers formatting. */ +#define XCM_REG_ERR_XCM_HDR 0x200ac +/* [RW 8] The Event ID for Timers expiration. */ +#define XCM_REG_EXPR_EVNT_ID 0x200b4 +/* [RW 8] FIC0 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define XCM_REG_FIC0_INIT_CRD 0x2040c +/* [RW 8] FIC1 output initial credit. Max credit available - 255.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 64 at start-up. */ +#define XCM_REG_FIC1_INIT_CRD 0x20410 +#define XCM_REG_GLB_DEL_ACK_MAX_CNT_0 0x20118 +#define XCM_REG_GLB_DEL_ACK_MAX_CNT_1 0x2011c +#define XCM_REG_GLB_DEL_ACK_TMR_VAL_0 0x20108 +#define XCM_REG_GLB_DEL_ACK_TMR_VAL_1 0x2010c +/* [RW 1] Arbitratiojn between Input Arbiter groups: 0 - fair Round-Robin; 1 + - strict priority defined by ~xcm_registers_gr_ag_pr.gr_ag_pr; + ~xcm_registers_gr_ld0_pr.gr_ld0_pr and + ~xcm_registers_gr_ld1_pr.gr_ld1_pr. */ +#define XCM_REG_GR_ARB_TYPE 0x2020c +/* [RW 2] Load (FIC0) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Channel group is the + compliment of the other 3 groups. */ +#define XCM_REG_GR_LD0_PR 0x20214 +/* [RW 2] Load (FIC1) channel group priority. The lowest priority is 0; the + highest priority is 3. It is supposed that the Channel group is the + compliment of the other 3 groups. */ +#define XCM_REG_GR_LD1_PR 0x20218 +/* [RW 1] Input nig0 Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_NIG0_IFEN 0x20038 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the nig0 interface. */ +#define XCM_REG_NIG0_LENGTH_MIS 0x20238 +/* [RW 3] The weight of the input nig0 in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_NIG0_WEIGHT 0x200d4 +/* [RW 1] Input nig1 Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_NIG1_IFEN 0x2003c +/* [RC 1] Set at message length mismatch (relative to last indication) at + the nig1 interface. */ +#define XCM_REG_NIG1_LENGTH_MIS 0x2023c +/* [RW 5] The number of double REG-pairs; loaded from the STORM context and + sent to STORM; for a specific connection type. The double REG-pairs are + used in order to align to STORM context row size of 128 bits. The offset + of these data in the STORM context is always 0. Index _i stands for the + connection type (one of 16). */ +#define XCM_REG_N_SM_CTX_LD_0 0x20060 +#define XCM_REG_N_SM_CTX_LD_1 0x20064 +#define XCM_REG_N_SM_CTX_LD_2 0x20068 +#define XCM_REG_N_SM_CTX_LD_3 0x2006c +#define XCM_REG_N_SM_CTX_LD_4 0x20070 +#define XCM_REG_N_SM_CTX_LD_5 0x20074 +/* [RW 1] Input pbf Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_PBF_IFEN 0x20034 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the pbf interface. */ +#define XCM_REG_PBF_LENGTH_MIS 0x20234 +/* [RW 3] The weight of the input pbf in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_PBF_WEIGHT 0x200d0 +#define XCM_REG_PHYS_QNUM3_0 0x20100 +#define XCM_REG_PHYS_QNUM3_1 0x20104 +/* [RW 8] The Event ID for Timers formatting in case of stop done. */ +#define XCM_REG_STOP_EVNT_ID 0x200b8 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the STORM interface. */ +#define XCM_REG_STORM_LENGTH_MIS 0x2021c +/* [RW 3] The weight of the STORM input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_STORM_WEIGHT 0x200bc +/* [RW 1] STORM - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_STORM_XCM_IFEN 0x20010 +/* [RW 4] Timers output initial credit. Max credit available - 15.Write + writes the initial credit value; read returns the current value of the + credit counter. Must be initialized to 4 at start-up. */ +#define XCM_REG_TM_INIT_CRD 0x2041c +/* [RW 3] The weight of the Timers input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_TM_WEIGHT 0x200ec +/* [RW 28] The CM header for Timers expiration command. */ +#define XCM_REG_TM_XCM_HDR 0x200a8 +/* [RW 1] Timers - CM Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_TM_XCM_IFEN 0x2001c +/* [RW 1] Input tsem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_TSEM_IFEN 0x20024 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the tsem interface. */ +#define XCM_REG_TSEM_LENGTH_MIS 0x20224 +/* [RW 3] The weight of the input tsem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_TSEM_WEIGHT 0x200c0 +/* [RW 2] The queue index for registration on UNA greater NXT decision rule. */ +#define XCM_REG_UNA_GT_NXT_Q 0x20120 +/* [RW 1] Input usem Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_USEM_IFEN 0x2002c +/* [RC 1] Message length mismatch (relative to last indication) at the usem + interface. */ +#define XCM_REG_USEM_LENGTH_MIS 0x2022c +/* [RW 3] The weight of the input usem in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_USEM_WEIGHT 0x200c8 +#define XCM_REG_WU_DA_CNT_CMD00 0x201d4 +#define XCM_REG_WU_DA_CNT_CMD01 0x201d8 +#define XCM_REG_WU_DA_CNT_CMD10 0x201dc +#define XCM_REG_WU_DA_CNT_CMD11 0x201e0 +#define XCM_REG_WU_DA_CNT_UPD_VAL00 0x201e4 +#define XCM_REG_WU_DA_CNT_UPD_VAL01 0x201e8 +#define XCM_REG_WU_DA_CNT_UPD_VAL10 0x201ec +#define XCM_REG_WU_DA_CNT_UPD_VAL11 0x201f0 +#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD00 0x201c4 +#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD01 0x201c8 +#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD10 0x201cc +#define XCM_REG_WU_DA_SET_TMR_CNT_FLG_CMD11 0x201d0 +/* [RW 1] CM - CFC Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XCM_CFC_IFEN 0x20050 +/* [RW 14] Interrupt mask register #0 read/write */ +#define XCM_REG_XCM_INT_MASK 0x202b4 +/* [R 14] Interrupt register #0 read */ +#define XCM_REG_XCM_INT_STS 0x202a8 +/* [RW 30] Parity mask register #0 read/write */ +#define XCM_REG_XCM_PRTY_MASK 0x202c4 +/* [R 30] Parity register #0 read */ +#define XCM_REG_XCM_PRTY_STS 0x202b8 +/* [RC 30] Parity register #0 read clear */ +#define XCM_REG_XCM_PRTY_STS_CLR 0x202bc + +/* [RW 4] The size of AG context region 0 in REG-pairs. Designates the MS + REG-pair number (e.g. if region 0 is 6 REG-pairs; the value should be 5). + Is used to determine the number of the AG context REG-pairs written back; + when the Reg1WbFlg isn't set. */ +#define XCM_REG_XCM_REG0_SZ 0x200f4 +/* [RW 1] CM - STORM 0 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XCM_STORM0_IFEN 0x20004 +/* [RW 1] CM - STORM 1 Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XCM_STORM1_IFEN 0x20008 +/* [RW 1] CM - Timers Interface enable. If 0 - the valid input is + disregarded; acknowledge output is deasserted; all other signals are + treated as usual; if 1 - normal activity. */ +#define XCM_REG_XCM_TM_IFEN 0x20020 +/* [RW 1] CM - QM Interface enable. If 0 - the acknowledge input is + disregarded; valid is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XCM_XQM_IFEN 0x2000c +/* [RW 1] If set the Q index; received from the QM is inserted to event ID. */ +#define XCM_REG_XCM_XQM_USE_Q 0x200f0 +/* [RW 4] The value by which CFC updates the activity counter at QM bypass. */ +#define XCM_REG_XQM_BYP_ACT_UPD 0x200fc +/* [RW 6] QM output initial credit. Max credit available - 32.Write writes + the initial credit value; read returns the current value of the credit + counter. Must be initialized to 32 at start-up. */ +#define XCM_REG_XQM_INIT_CRD 0x20420 +/* [RW 3] The weight of the QM (primary) input in the WRR mechanism. 0 + stands for weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_XQM_P_WEIGHT 0x200e4 +/* [RW 3] The weight of the QM (secondary) input in the WRR mechanism. 0 + stands for weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_XQM_S_WEIGHT 0x200e8 +/* [RW 28] The CM header value for QM request (primary). */ +#define XCM_REG_XQM_XCM_HDR_P 0x200a0 +/* [RW 28] The CM header value for QM request (secondary). */ +#define XCM_REG_XQM_XCM_HDR_S 0x200a4 +/* [RW 1] QM - CM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XQM_XCM_IFEN 0x20014 +/* [RW 1] Input SDM Interface enable. If 0 - the valid input is disregarded; + acknowledge output is deasserted; all other signals are treated as usual; + if 1 - normal activity. */ +#define XCM_REG_XSDM_IFEN 0x20018 +/* [RC 1] Set at message length mismatch (relative to last indication) at + the SDM interface. */ +#define XCM_REG_XSDM_LENGTH_MIS 0x20220 +/* [RW 3] The weight of the SDM input in the WRR mechanism. 0 stands for + weight 8 (the most prioritised); 1 stands for weight 1(least + prioritised); 2 stands for weight 2; tc. */ +#define XCM_REG_XSDM_WEIGHT 0x200e0 +/* [RW 17] Indirect access to the descriptor table of the XX protection + mechanism. The fields are: [5:0] - message length; 11:6] - message + pointer; 16:12] - next pointer. */ +#define XCM_REG_XX_DESCR_TABLE 0x20480 +#define XCM_REG_XX_DESCR_TABLE_SIZE 32 +/* [R 6] Used to read the XX protection Free counter. */ +#define XCM_REG_XX_FREE 0x20240 +/* [RW 6] Initial value for the credit counter; responsible for fulfilling + of the Input Stage XX protection buffer by the XX protection pending + messages. Max credit available - 3.Write writes the initial credit value; + read returns the current value of the credit counter. Must be initialized + to 2 at start-up. */ +#define XCM_REG_XX_INIT_CRD 0x20424 +/* [RW 6] The maximum number of pending messages; which may be stored in XX + protection. ~xcm_registers_xx_free.xx_free read on read. */ +#define XCM_REG_XX_MSG_NUM 0x20428 +/* [RW 8] The Event ID; sent to the STORM in case of XX overflow. */ +#define XCM_REG_XX_OVFL_EVNT_ID 0x20058 +#define XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_LOCAL_FAULT_STATUS (0x1<<0) +#define XMAC_CLEAR_RX_LSS_STATUS_REG_CLEAR_REMOTE_FAULT_STATUS (0x1<<1) +#define XMAC_CTRL_REG_CORE_LOCAL_LPBK (0x1<<3) +#define XMAC_CTRL_REG_RX_EN (0x1<<1) +#define XMAC_CTRL_REG_SOFT_RESET (0x1<<6) +#define XMAC_CTRL_REG_TX_EN (0x1<<0) +#define XMAC_PAUSE_CTRL_REG_RX_PAUSE_EN (0x1<<18) +#define XMAC_PAUSE_CTRL_REG_TX_PAUSE_EN (0x1<<17) +#define XMAC_PFC_CTRL_HI_REG_PFC_REFRESH_EN (0x1<<0) +#define XMAC_PFC_CTRL_HI_REG_PFC_STATS_EN (0x1<<3) +#define XMAC_PFC_CTRL_HI_REG_RX_PFC_EN (0x1<<4) +#define XMAC_PFC_CTRL_HI_REG_TX_PFC_EN (0x1<<5) +#define XMAC_REG_CLEAR_RX_LSS_STATUS 0x60 +#define XMAC_REG_CTRL 0 +/* [RW 16] Upper 48 bits of ctrl_sa register. Used as the SA in PAUSE/PFC + * packets transmitted by the MAC */ +#define XMAC_REG_CTRL_SA_HI 0x2c +/* [RW 32] Lower 48 bits of ctrl_sa register. Used as the SA in PAUSE/PFC + * packets transmitted by the MAC */ +#define XMAC_REG_CTRL_SA_LO 0x28 +#define XMAC_REG_PAUSE_CTRL 0x68 +#define XMAC_REG_PFC_CTRL 0x70 +#define XMAC_REG_PFC_CTRL_HI 0x74 +#define XMAC_REG_RX_LSS_STATUS 0x58 +/* [RW 14] Maximum packet size in receive direction; exclusive of preamble & + * CRC in strip mode */ +#define XMAC_REG_RX_MAX_SIZE 0x40 +#define XMAC_REG_TX_CTRL 0x20 +/* [RW 16] Indirect access to the XX table of the XX protection mechanism. + The fields are:[4:0] - tail pointer; 9:5] - Link List size; 14:10] - + header pointer. */ +#define XCM_REG_XX_TABLE 0x20500 +/* [RW 8] The event id for aggregated interrupt 0 */ +#define XSDM_REG_AGG_INT_EVENT_0 0x166038 +#define XSDM_REG_AGG_INT_EVENT_1 0x16603c +#define XSDM_REG_AGG_INT_EVENT_10 0x166060 +#define XSDM_REG_AGG_INT_EVENT_11 0x166064 +#define XSDM_REG_AGG_INT_EVENT_12 0x166068 +#define XSDM_REG_AGG_INT_EVENT_13 0x16606c +#define XSDM_REG_AGG_INT_EVENT_14 0x166070 +#define XSDM_REG_AGG_INT_EVENT_2 0x166040 +#define XSDM_REG_AGG_INT_EVENT_3 0x166044 +#define XSDM_REG_AGG_INT_EVENT_4 0x166048 +#define XSDM_REG_AGG_INT_EVENT_5 0x16604c +#define XSDM_REG_AGG_INT_EVENT_6 0x166050 +#define XSDM_REG_AGG_INT_EVENT_7 0x166054 +#define XSDM_REG_AGG_INT_EVENT_8 0x166058 +#define XSDM_REG_AGG_INT_EVENT_9 0x16605c +/* [RW 1] For each aggregated interrupt index whether the mode is normal (0) + or auto-mask-mode (1) */ +#define XSDM_REG_AGG_INT_MODE_0 0x1661b8 +#define XSDM_REG_AGG_INT_MODE_1 0x1661bc +/* [RW 13] The start address in the internal RAM for the cfc_rsp lcid */ +#define XSDM_REG_CFC_RSP_START_ADDR 0x166008 +/* [RW 16] The maximum value of the completion counter #0 */ +#define XSDM_REG_CMP_COUNTER_MAX0 0x16601c +/* [RW 16] The maximum value of the completion counter #1 */ +#define XSDM_REG_CMP_COUNTER_MAX1 0x166020 +/* [RW 16] The maximum value of the completion counter #2 */ +#define XSDM_REG_CMP_COUNTER_MAX2 0x166024 +/* [RW 16] The maximum value of the completion counter #3 */ +#define XSDM_REG_CMP_COUNTER_MAX3 0x166028 +/* [RW 13] The start address in the internal RAM for the completion + counters. */ +#define XSDM_REG_CMP_COUNTER_START_ADDR 0x16600c +#define XSDM_REG_ENABLE_IN1 0x166238 +#define XSDM_REG_ENABLE_IN2 0x16623c +#define XSDM_REG_ENABLE_OUT1 0x166240 +#define XSDM_REG_ENABLE_OUT2 0x166244 +/* [RW 4] The initial number of messages that can be sent to the pxp control + interface without receiving any ACK. */ +#define XSDM_REG_INIT_CREDIT_PXP_CTRL 0x1664bc +/* [ST 32] The number of ACK after placement messages received */ +#define XSDM_REG_NUM_OF_ACK_AFTER_PLACE 0x16627c +/* [ST 32] The number of packet end messages received from the parser */ +#define XSDM_REG_NUM_OF_PKT_END_MSG 0x166274 +/* [ST 32] The number of requests received from the pxp async if */ +#define XSDM_REG_NUM_OF_PXP_ASYNC_REQ 0x166278 +/* [ST 32] The number of commands received in queue 0 */ +#define XSDM_REG_NUM_OF_Q0_CMD 0x166248 +/* [ST 32] The number of commands received in queue 10 */ +#define XSDM_REG_NUM_OF_Q10_CMD 0x16626c +/* [ST 32] The number of commands received in queue 11 */ +#define XSDM_REG_NUM_OF_Q11_CMD 0x166270 +/* [ST 32] The number of commands received in queue 1 */ +#define XSDM_REG_NUM_OF_Q1_CMD 0x16624c +/* [ST 32] The number of commands received in queue 3 */ +#define XSDM_REG_NUM_OF_Q3_CMD 0x166250 +/* [ST 32] The number of commands received in queue 4 */ +#define XSDM_REG_NUM_OF_Q4_CMD 0x166254 +/* [ST 32] The number of commands received in queue 5 */ +#define XSDM_REG_NUM_OF_Q5_CMD 0x166258 +/* [ST 32] The number of commands received in queue 6 */ +#define XSDM_REG_NUM_OF_Q6_CMD 0x16625c +/* [ST 32] The number of commands received in queue 7 */ +#define XSDM_REG_NUM_OF_Q7_CMD 0x166260 +/* [ST 32] The number of commands received in queue 8 */ +#define XSDM_REG_NUM_OF_Q8_CMD 0x166264 +/* [ST 32] The number of commands received in queue 9 */ +#define XSDM_REG_NUM_OF_Q9_CMD 0x166268 +/* [RW 13] The start address in the internal RAM for queue counters */ +#define XSDM_REG_Q_COUNTER_START_ADDR 0x166010 +/* [W 17] Generate an operation after completion; bit-16 is + * AggVectIdx_valid; bits 15:8 are AggVectIdx; bits 7:5 are the TRIG and + * bits 4:0 are the T124Param[4:0] */ +#define XSDM_REG_OPERATION_GEN 0x1664c4 +/* [R 1] pxp_ctrl rd_data fifo empty in sdm_dma_rsp block */ +#define XSDM_REG_RSP_PXP_CTRL_RDATA_EMPTY 0x166548 +/* [R 1] parser fifo empty in sdm_sync block */ +#define XSDM_REG_SYNC_PARSER_EMPTY 0x166550 +/* [R 1] parser serial fifo empty in sdm_sync block */ +#define XSDM_REG_SYNC_SYNC_EMPTY 0x166558 +/* [RW 32] Tick for timer counter. Applicable only when + ~xsdm_registers_timer_tick_enable.timer_tick_enable =1 */ +#define XSDM_REG_TIMER_TICK 0x166000 +/* [RW 32] Interrupt mask register #0 read/write */ +#define XSDM_REG_XSDM_INT_MASK_0 0x16629c +#define XSDM_REG_XSDM_INT_MASK_1 0x1662ac +/* [R 32] Interrupt register #0 read */ +#define XSDM_REG_XSDM_INT_STS_0 0x166290 +#define XSDM_REG_XSDM_INT_STS_1 0x1662a0 +/* [RW 11] Parity mask register #0 read/write */ +#define XSDM_REG_XSDM_PRTY_MASK 0x1662bc +/* [R 11] Parity register #0 read */ +#define XSDM_REG_XSDM_PRTY_STS 0x1662b0 +/* [RC 11] Parity register #0 read clear */ +#define XSDM_REG_XSDM_PRTY_STS_CLR 0x1662b4 +/* [RW 5] The number of time_slots in the arbitration cycle */ +#define XSEM_REG_ARB_CYCLE_SIZE 0x280034 +/* [RW 3] The source that is associated with arbitration element 0. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2 */ +#define XSEM_REG_ARB_ELEMENT0 0x280020 +/* [RW 3] The source that is associated with arbitration element 1. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~xsem_registers_arb_element0.arb_element0 */ +#define XSEM_REG_ARB_ELEMENT1 0x280024 +/* [RW 3] The source that is associated with arbitration element 2. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~xsem_registers_arb_element0.arb_element0 + and ~xsem_registers_arb_element1.arb_element1 */ +#define XSEM_REG_ARB_ELEMENT2 0x280028 +/* [RW 3] The source that is associated with arbitration element 3. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2.Could + not be equal to register ~xsem_registers_arb_element0.arb_element0 and + ~xsem_registers_arb_element1.arb_element1 and + ~xsem_registers_arb_element2.arb_element2 */ +#define XSEM_REG_ARB_ELEMENT3 0x28002c +/* [RW 3] The source that is associated with arbitration element 4. Source + decoding is: 0- foc0; 1-fic1; 2-sleeping thread with priority 0; 3- + sleeping thread with priority 1; 4- sleeping thread with priority 2. + Could not be equal to register ~xsem_registers_arb_element0.arb_element0 + and ~xsem_registers_arb_element1.arb_element1 and + ~xsem_registers_arb_element2.arb_element2 and + ~xsem_registers_arb_element3.arb_element3 */ +#define XSEM_REG_ARB_ELEMENT4 0x280030 +#define XSEM_REG_ENABLE_IN 0x2800a4 +#define XSEM_REG_ENABLE_OUT 0x2800a8 +/* [RW 32] This address space contains all registers and memories that are + placed in SEM_FAST block. The SEM_FAST registers are described in + appendix B. In order to access the sem_fast registers the base address + ~fast_memory.fast_memory should be added to eachsem_fast register offset. */ +#define XSEM_REG_FAST_MEMORY 0x2a0000 +/* [RW 1] Disables input messages from FIC0 May be updated during run_time + by the microcode */ +#define XSEM_REG_FIC0_DISABLE 0x280224 +/* [RW 1] Disables input messages from FIC1 May be updated during run_time + by the microcode */ +#define XSEM_REG_FIC1_DISABLE 0x280234 +/* [RW 15] Interrupt table Read and write access to it is not possible in + the middle of the work */ +#define XSEM_REG_INT_TABLE 0x280400 +/* [ST 24] Statistics register. The number of messages that entered through + FIC0 */ +#define XSEM_REG_MSG_NUM_FIC0 0x280000 +/* [ST 24] Statistics register. The number of messages that entered through + FIC1 */ +#define XSEM_REG_MSG_NUM_FIC1 0x280004 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC0 */ +#define XSEM_REG_MSG_NUM_FOC0 0x280008 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC1 */ +#define XSEM_REG_MSG_NUM_FOC1 0x28000c +/* [ST 24] Statistics register. The number of messages that were sent to + FOC2 */ +#define XSEM_REG_MSG_NUM_FOC2 0x280010 +/* [ST 24] Statistics register. The number of messages that were sent to + FOC3 */ +#define XSEM_REG_MSG_NUM_FOC3 0x280014 +/* [RW 1] Disables input messages from the passive buffer May be updated + during run_time by the microcode */ +#define XSEM_REG_PAS_DISABLE 0x28024c +/* [WB 128] Debug only. Passive buffer memory */ +#define XSEM_REG_PASSIVE_BUFFER 0x282000 +/* [WB 46] pram memory. B45 is parity; b[44:0] - data. */ +#define XSEM_REG_PRAM 0x2c0000 +/* [R 16] Valid sleeping threads indication have bit per thread */ +#define XSEM_REG_SLEEP_THREADS_VALID 0x28026c +/* [R 1] EXT_STORE FIFO is empty in sem_slow_ls_ext */ +#define XSEM_REG_SLOW_EXT_STORE_EMPTY 0x2802a0 +/* [RW 16] List of free threads . There is a bit per thread. */ +#define XSEM_REG_THREADS_LIST 0x2802e4 +/* [RW 3] The arbitration scheme of time_slot 0 */ +#define XSEM_REG_TS_0_AS 0x280038 +/* [RW 3] The arbitration scheme of time_slot 10 */ +#define XSEM_REG_TS_10_AS 0x280060 +/* [RW 3] The arbitration scheme of time_slot 11 */ +#define XSEM_REG_TS_11_AS 0x280064 +/* [RW 3] The arbitration scheme of time_slot 12 */ +#define XSEM_REG_TS_12_AS 0x280068 +/* [RW 3] The arbitration scheme of time_slot 13 */ +#define XSEM_REG_TS_13_AS 0x28006c +/* [RW 3] The arbitration scheme of time_slot 14 */ +#define XSEM_REG_TS_14_AS 0x280070 +/* [RW 3] The arbitration scheme of time_slot 15 */ +#define XSEM_REG_TS_15_AS 0x280074 +/* [RW 3] The arbitration scheme of time_slot 16 */ +#define XSEM_REG_TS_16_AS 0x280078 +/* [RW 3] The arbitration scheme of time_slot 17 */ +#define XSEM_REG_TS_17_AS 0x28007c +/* [RW 3] The arbitration scheme of time_slot 18 */ +#define XSEM_REG_TS_18_AS 0x280080 +/* [RW 3] The arbitration scheme of time_slot 1 */ +#define XSEM_REG_TS_1_AS 0x28003c +/* [RW 3] The arbitration scheme of time_slot 2 */ +#define XSEM_REG_TS_2_AS 0x280040 +/* [RW 3] The arbitration scheme of time_slot 3 */ +#define XSEM_REG_TS_3_AS 0x280044 +/* [RW 3] The arbitration scheme of time_slot 4 */ +#define XSEM_REG_TS_4_AS 0x280048 +/* [RW 3] The arbitration scheme of time_slot 5 */ +#define XSEM_REG_TS_5_AS 0x28004c +/* [RW 3] The arbitration scheme of time_slot 6 */ +#define XSEM_REG_TS_6_AS 0x280050 +/* [RW 3] The arbitration scheme of time_slot 7 */ +#define XSEM_REG_TS_7_AS 0x280054 +/* [RW 3] The arbitration scheme of time_slot 8 */ +#define XSEM_REG_TS_8_AS 0x280058 +/* [RW 3] The arbitration scheme of time_slot 9 */ +#define XSEM_REG_TS_9_AS 0x28005c +/* [W 7] VF or PF ID for reset error bit. Values 0-63 reset error bit for 64 + * VF; values 64-67 reset error for 4 PF; values 68-127 are not valid. */ +#define XSEM_REG_VFPF_ERR_NUM 0x280380 +/* [RW 32] Interrupt mask register #0 read/write */ +#define XSEM_REG_XSEM_INT_MASK_0 0x280110 +#define XSEM_REG_XSEM_INT_MASK_1 0x280120 +/* [R 32] Interrupt register #0 read */ +#define XSEM_REG_XSEM_INT_STS_0 0x280104 +#define XSEM_REG_XSEM_INT_STS_1 0x280114 +/* [RW 32] Parity mask register #0 read/write */ +#define XSEM_REG_XSEM_PRTY_MASK_0 0x280130 +#define XSEM_REG_XSEM_PRTY_MASK_1 0x280140 +/* [R 32] Parity register #0 read */ +#define XSEM_REG_XSEM_PRTY_STS_0 0x280124 +#define XSEM_REG_XSEM_PRTY_STS_1 0x280134 +/* [RC 32] Parity register #0 read clear */ +#define XSEM_REG_XSEM_PRTY_STS_CLR_0 0x280128 +#define XSEM_REG_XSEM_PRTY_STS_CLR_1 0x280138 +#define MCPR_NVM_ACCESS_ENABLE_EN (1L<<0) +#define MCPR_NVM_ACCESS_ENABLE_WR_EN (1L<<1) +#define MCPR_NVM_ADDR_NVM_ADDR_VALUE (0xffffffL<<0) +#define MCPR_NVM_CFG4_FLASH_SIZE (0x7L<<0) +#define MCPR_NVM_COMMAND_DOIT (1L<<4) +#define MCPR_NVM_COMMAND_DONE (1L<<3) +#define MCPR_NVM_COMMAND_FIRST (1L<<7) +#define MCPR_NVM_COMMAND_LAST (1L<<8) +#define MCPR_NVM_COMMAND_WR (1L<<5) +#define MCPR_NVM_SW_ARB_ARB_ARB1 (1L<<9) +#define MCPR_NVM_SW_ARB_ARB_REQ_CLR1 (1L<<5) +#define MCPR_NVM_SW_ARB_ARB_REQ_SET1 (1L<<1) +#define BIGMAC_REGISTER_BMAC_CONTROL (0x00<<3) +#define BIGMAC_REGISTER_BMAC_XGXS_CONTROL (0x01<<3) +#define BIGMAC_REGISTER_CNT_MAX_SIZE (0x05<<3) +#define BIGMAC_REGISTER_RX_CONTROL (0x21<<3) +#define BIGMAC_REGISTER_RX_LLFC_MSG_FLDS (0x46<<3) +#define BIGMAC_REGISTER_RX_LSS_STATUS (0x43<<3) +#define BIGMAC_REGISTER_RX_MAX_SIZE (0x23<<3) +#define BIGMAC_REGISTER_RX_STAT_GR64 (0x26<<3) +#define BIGMAC_REGISTER_RX_STAT_GRIPJ (0x42<<3) +#define BIGMAC_REGISTER_TX_CONTROL (0x07<<3) +#define BIGMAC_REGISTER_TX_MAX_SIZE (0x09<<3) +#define BIGMAC_REGISTER_TX_PAUSE_THRESHOLD (0x0A<<3) +#define BIGMAC_REGISTER_TX_SOURCE_ADDR (0x08<<3) +#define BIGMAC_REGISTER_TX_STAT_GTBYT (0x20<<3) +#define BIGMAC_REGISTER_TX_STAT_GTPKT (0x0C<<3) +#define BIGMAC2_REGISTER_BMAC_CONTROL (0x00<<3) +#define BIGMAC2_REGISTER_BMAC_XGXS_CONTROL (0x01<<3) +#define BIGMAC2_REGISTER_CNT_MAX_SIZE (0x05<<3) +#define BIGMAC2_REGISTER_PFC_CONTROL (0x06<<3) +#define BIGMAC2_REGISTER_RX_CONTROL (0x3A<<3) +#define BIGMAC2_REGISTER_RX_LLFC_MSG_FLDS (0x62<<3) +#define BIGMAC2_REGISTER_RX_LSS_STAT (0x3E<<3) +#define BIGMAC2_REGISTER_RX_MAX_SIZE (0x3C<<3) +#define BIGMAC2_REGISTER_RX_STAT_GR64 (0x40<<3) +#define BIGMAC2_REGISTER_RX_STAT_GRIPJ (0x5f<<3) +#define BIGMAC2_REGISTER_RX_STAT_GRPP (0x51<<3) +#define BIGMAC2_REGISTER_TX_CONTROL (0x1C<<3) +#define BIGMAC2_REGISTER_TX_MAX_SIZE (0x1E<<3) +#define BIGMAC2_REGISTER_TX_PAUSE_CONTROL (0x20<<3) +#define BIGMAC2_REGISTER_TX_SOURCE_ADDR (0x1D<<3) +#define BIGMAC2_REGISTER_TX_STAT_GTBYT (0x39<<3) +#define BIGMAC2_REGISTER_TX_STAT_GTPOK (0x22<<3) +#define BIGMAC2_REGISTER_TX_STAT_GTPP (0x24<<3) +#define EMAC_LED_1000MB_OVERRIDE (1L<<1) +#define EMAC_LED_100MB_OVERRIDE (1L<<2) +#define EMAC_LED_10MB_OVERRIDE (1L<<3) +#define EMAC_LED_2500MB_OVERRIDE (1L<<12) +#define EMAC_LED_OVERRIDE (1L<<0) +#define EMAC_LED_TRAFFIC (1L<<6) +#define EMAC_MDIO_COMM_COMMAND_ADDRESS (0L<<26) +#define EMAC_MDIO_COMM_COMMAND_READ_22 (2L<<26) +#define EMAC_MDIO_COMM_COMMAND_READ_45 (3L<<26) +#define EMAC_MDIO_COMM_COMMAND_WRITE_22 (1L<<26) +#define EMAC_MDIO_COMM_COMMAND_WRITE_45 (1L<<26) +#define EMAC_MDIO_COMM_DATA (0xffffL<<0) +#define EMAC_MDIO_COMM_START_BUSY (1L<<29) +#define EMAC_MDIO_MODE_AUTO_POLL (1L<<4) +#define EMAC_MDIO_MODE_CLAUSE_45 (1L<<31) +#define EMAC_MDIO_MODE_CLOCK_CNT (0x3ffL<<16) +#define EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT 16 +#define EMAC_MDIO_STATUS_10MB (1L<<1) +#define EMAC_MODE_25G_MODE (1L<<5) +#define EMAC_MODE_HALF_DUPLEX (1L<<1) +#define EMAC_MODE_PORT_GMII (2L<<2) +#define EMAC_MODE_PORT_MII (1L<<2) +#define EMAC_MODE_PORT_MII_10M (3L<<2) +#define EMAC_MODE_RESET (1L<<0) +#define EMAC_REG_EMAC_LED 0xc +#define EMAC_REG_EMAC_MAC_MATCH 0x10 +#define EMAC_REG_EMAC_MDIO_COMM 0xac +#define EMAC_REG_EMAC_MDIO_MODE 0xb4 +#define EMAC_REG_EMAC_MDIO_STATUS 0xb0 +#define EMAC_REG_EMAC_MODE 0x0 +#define EMAC_REG_EMAC_RX_MODE 0xc8 +#define EMAC_REG_EMAC_RX_MTU_SIZE 0x9c +#define EMAC_REG_EMAC_RX_STAT_AC 0x180 +#define EMAC_REG_EMAC_RX_STAT_AC_28 0x1f4 +#define EMAC_REG_EMAC_RX_STAT_AC_COUNT 23 +#define EMAC_REG_EMAC_TX_MODE 0xbc +#define EMAC_REG_EMAC_TX_STAT_AC 0x280 +#define EMAC_REG_EMAC_TX_STAT_AC_COUNT 22 +#define EMAC_REG_RX_PFC_MODE 0x320 +#define EMAC_REG_RX_PFC_MODE_PRIORITIES (1L<<2) +#define EMAC_REG_RX_PFC_MODE_RX_EN (1L<<1) +#define EMAC_REG_RX_PFC_MODE_TX_EN (1L<<0) +#define EMAC_REG_RX_PFC_PARAM 0x324 +#define EMAC_REG_RX_PFC_PARAM_OPCODE_BITSHIFT 0 +#define EMAC_REG_RX_PFC_PARAM_PRIORITY_EN_BITSHIFT 16 +#define EMAC_REG_RX_PFC_STATS_XOFF_RCVD 0x328 +#define EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT (0xffff<<0) +#define EMAC_REG_RX_PFC_STATS_XOFF_SENT 0x330 +#define EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT (0xffff<<0) +#define EMAC_REG_RX_PFC_STATS_XON_RCVD 0x32c +#define EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT (0xffff<<0) +#define EMAC_REG_RX_PFC_STATS_XON_SENT 0x334 +#define EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT (0xffff<<0) +#define EMAC_RX_MODE_FLOW_EN (1L<<2) +#define EMAC_RX_MODE_KEEP_MAC_CONTROL (1L<<3) +#define EMAC_RX_MODE_KEEP_VLAN_TAG (1L<<10) +#define EMAC_RX_MODE_PROMISCUOUS (1L<<8) +#define EMAC_RX_MODE_RESET (1L<<0) +#define EMAC_RX_MTU_SIZE_JUMBO_ENA (1L<<31) +#define EMAC_TX_MODE_EXT_PAUSE_EN (1L<<3) +#define EMAC_TX_MODE_FLOW_EN (1L<<4) +#define EMAC_TX_MODE_RESET (1L<<0) +#define MISC_REGISTERS_GPIO_0 0 +#define MISC_REGISTERS_GPIO_1 1 +#define MISC_REGISTERS_GPIO_2 2 +#define MISC_REGISTERS_GPIO_3 3 +#define MISC_REGISTERS_GPIO_CLR_POS 16 +#define MISC_REGISTERS_GPIO_FLOAT (0xffL<<24) +#define MISC_REGISTERS_GPIO_FLOAT_POS 24 +#define MISC_REGISTERS_GPIO_HIGH 1 +#define MISC_REGISTERS_GPIO_INPUT_HI_Z 2 +#define MISC_REGISTERS_GPIO_INT_CLR_POS 24 +#define MISC_REGISTERS_GPIO_INT_OUTPUT_CLR 0 +#define MISC_REGISTERS_GPIO_INT_OUTPUT_SET 1 +#define MISC_REGISTERS_GPIO_INT_SET_POS 16 +#define MISC_REGISTERS_GPIO_LOW 0 +#define MISC_REGISTERS_GPIO_OUTPUT_HIGH 1 +#define MISC_REGISTERS_GPIO_OUTPUT_LOW 0 +#define MISC_REGISTERS_GPIO_PORT_SHIFT 4 +#define MISC_REGISTERS_GPIO_SET_POS 8 +#define MISC_REGISTERS_RESET_REG_1_CLEAR 0x588 +#define MISC_REGISTERS_RESET_REG_1_RST_HC (0x1<<29) +#define MISC_REGISTERS_RESET_REG_1_RST_NIG (0x1<<7) +#define MISC_REGISTERS_RESET_REG_1_RST_PXP (0x1<<26) +#define MISC_REGISTERS_RESET_REG_1_RST_PXPV (0x1<<27) +#define MISC_REGISTERS_RESET_REG_1_SET 0x584 +#define MISC_REGISTERS_RESET_REG_2_CLEAR 0x598 +#define MISC_REGISTERS_RESET_REG_2_MSTAT0 (0x1<<24) +#define MISC_REGISTERS_RESET_REG_2_MSTAT1 (0x1<<25) +#define MISC_REGISTERS_RESET_REG_2_PGLC (0x1<<19) +#define MISC_REGISTERS_RESET_REG_2_RST_ATC (0x1<<17) +#define MISC_REGISTERS_RESET_REG_2_RST_BMAC0 (0x1<<0) +#define MISC_REGISTERS_RESET_REG_2_RST_BMAC1 (0x1<<1) +#define MISC_REGISTERS_RESET_REG_2_RST_EMAC0 (0x1<<2) +#define MISC_REGISTERS_RESET_REG_2_RST_EMAC0_HARD_CORE (0x1<<14) +#define MISC_REGISTERS_RESET_REG_2_RST_EMAC1 (0x1<<3) +#define MISC_REGISTERS_RESET_REG_2_RST_EMAC1_HARD_CORE (0x1<<15) +#define MISC_REGISTERS_RESET_REG_2_RST_GRC (0x1<<4) +#define MISC_REGISTERS_RESET_REG_2_RST_MCP_N_HARD_CORE_RST_B (0x1<<6) +#define MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CORE (0x1<<8) +#define MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_CMN_CPU (0x1<<7) +#define MISC_REGISTERS_RESET_REG_2_RST_MCP_N_RESET_REG_HARD_CORE (0x1<<5) +#define MISC_REGISTERS_RESET_REG_2_RST_MDIO (0x1<<13) +#define MISC_REGISTERS_RESET_REG_2_RST_MISC_CORE (0x1<<11) +#define MISC_REGISTERS_RESET_REG_2_RST_PCI_MDIO (0x1<<13) +#define MISC_REGISTERS_RESET_REG_2_RST_RBCN (0x1<<9) +#define MISC_REGISTERS_RESET_REG_2_SET 0x594 +#define MISC_REGISTERS_RESET_REG_2_UMAC0 (0x1<<20) +#define MISC_REGISTERS_RESET_REG_2_UMAC1 (0x1<<21) +#define MISC_REGISTERS_RESET_REG_2_XMAC (0x1<<22) +#define MISC_REGISTERS_RESET_REG_2_XMAC_SOFT (0x1<<23) +#define MISC_REGISTERS_RESET_REG_3_CLEAR 0x5a8 +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_IDDQ (0x1<<1) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN (0x1<<2) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_PWRDWN_SD (0x1<<3) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_SERDES0_RSTB_HW (0x1<<0) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_IDDQ (0x1<<5) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN (0x1<<6) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_PWRDWN_SD (0x1<<7) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_RSTB_HW (0x1<<4) +#define MISC_REGISTERS_RESET_REG_3_MISC_NIG_MUX_XGXS0_TXD_FIFO_RSTB (0x1<<8) +#define MISC_REGISTERS_RESET_REG_3_SET 0x5a4 +#define MISC_REGISTERS_SPIO_4 4 +#define MISC_REGISTERS_SPIO_5 5 +#define MISC_REGISTERS_SPIO_7 7 +#define MISC_REGISTERS_SPIO_CLR_POS 16 +#define MISC_REGISTERS_SPIO_FLOAT (0xffL<<24) +#define MISC_REGISTERS_SPIO_FLOAT_POS 24 +#define MISC_REGISTERS_SPIO_INPUT_HI_Z 2 +#define MISC_REGISTERS_SPIO_INT_OLD_SET_POS 16 +#define MISC_REGISTERS_SPIO_OUTPUT_HIGH 1 +#define MISC_REGISTERS_SPIO_OUTPUT_LOW 0 +#define MISC_REGISTERS_SPIO_SET_POS 8 +#define HW_LOCK_DRV_FLAGS 10 +#define HW_LOCK_MAX_RESOURCE_VALUE 31 +#define HW_LOCK_RESOURCE_GPIO 1 +#define HW_LOCK_RESOURCE_MDIO 0 +#define HW_LOCK_RESOURCE_PORT0_ATT_MASK 3 +#define HW_LOCK_RESOURCE_RECOVERY_LEADER_0 8 +#define HW_LOCK_RESOURCE_RECOVERY_LEADER_1 9 +#define HW_LOCK_RESOURCE_SPIO 2 +#define HW_LOCK_RESOURCE_UNDI 5 +#define AEU_INPUTS_ATTN_BITS_ATC_HW_INTERRUPT (0x1<<4) +#define AEU_INPUTS_ATTN_BITS_ATC_PARITY_ERROR (0x1<<5) +#define AEU_INPUTS_ATTN_BITS_BRB_PARITY_ERROR (0x1<<18) +#define AEU_INPUTS_ATTN_BITS_CCM_HW_INTERRUPT (0x1<<31) +#define AEU_INPUTS_ATTN_BITS_CCM_PARITY_ERROR (0x1<<30) +#define AEU_INPUTS_ATTN_BITS_CDU_HW_INTERRUPT (0x1<<9) +#define AEU_INPUTS_ATTN_BITS_CDU_PARITY_ERROR (0x1<<8) +#define AEU_INPUTS_ATTN_BITS_CFC_HW_INTERRUPT (0x1<<7) +#define AEU_INPUTS_ATTN_BITS_CFC_PARITY_ERROR (0x1<<6) +#define AEU_INPUTS_ATTN_BITS_CSDM_HW_INTERRUPT (0x1<<29) +#define AEU_INPUTS_ATTN_BITS_CSDM_PARITY_ERROR (0x1<<28) +#define AEU_INPUTS_ATTN_BITS_CSEMI_HW_INTERRUPT (0x1<<1) +#define AEU_INPUTS_ATTN_BITS_CSEMI_PARITY_ERROR (0x1<<0) +#define AEU_INPUTS_ATTN_BITS_DEBUG_PARITY_ERROR (0x1<<18) +#define AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT (0x1<<11) +#define AEU_INPUTS_ATTN_BITS_DMAE_PARITY_ERROR (0x1<<10) +#define AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT (0x1<<13) +#define AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR (0x1<<12) +#define AEU_INPUTS_ATTN_BITS_GPIO0_FUNCTION_0 (0x1<<2) +#define AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR (0x1<<12) +#define AEU_INPUTS_ATTN_BITS_MCP_LATCHED_ROM_PARITY (0x1<<28) +#define AEU_INPUTS_ATTN_BITS_MCP_LATCHED_SCPAD_PARITY (0x1<<31) +#define AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_RX_PARITY (0x1<<29) +#define AEU_INPUTS_ATTN_BITS_MCP_LATCHED_UMP_TX_PARITY (0x1<<30) +#define AEU_INPUTS_ATTN_BITS_MISC_HW_INTERRUPT (0x1<<15) +#define AEU_INPUTS_ATTN_BITS_MISC_PARITY_ERROR (0x1<<14) +#define AEU_INPUTS_ATTN_BITS_NIG_PARITY_ERROR (0x1<<14) +#define AEU_INPUTS_ATTN_BITS_PARSER_PARITY_ERROR (0x1<<20) +#define AEU_INPUTS_ATTN_BITS_PBCLIENT_HW_INTERRUPT (0x1<<31) +#define AEU_INPUTS_ATTN_BITS_PBCLIENT_PARITY_ERROR (0x1<<30) +#define AEU_INPUTS_ATTN_BITS_PBF_PARITY_ERROR (0x1<<0) +#define AEU_INPUTS_ATTN_BITS_PGLUE_HW_INTERRUPT (0x1<<2) +#define AEU_INPUTS_ATTN_BITS_PGLUE_PARITY_ERROR (0x1<<3) +#define AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_HW_INTERRUPT (0x1<<5) +#define AEU_INPUTS_ATTN_BITS_PXPPCICLOCKCLIENT_PARITY_ERROR (0x1<<4) +#define AEU_INPUTS_ATTN_BITS_PXP_HW_INTERRUPT (0x1<<3) +#define AEU_INPUTS_ATTN_BITS_PXP_PARITY_ERROR (0x1<<2) +#define AEU_INPUTS_ATTN_BITS_QM_HW_INTERRUPT (0x1<<3) +#define AEU_INPUTS_ATTN_BITS_QM_PARITY_ERROR (0x1<<2) +#define AEU_INPUTS_ATTN_BITS_SEARCHER_PARITY_ERROR (0x1<<22) +#define AEU_INPUTS_ATTN_BITS_SPIO5 (0x1<<15) +#define AEU_INPUTS_ATTN_BITS_TCM_HW_INTERRUPT (0x1<<27) +#define AEU_INPUTS_ATTN_BITS_TCM_PARITY_ERROR (0x1<<26) +#define AEU_INPUTS_ATTN_BITS_TIMERS_HW_INTERRUPT (0x1<<5) +#define AEU_INPUTS_ATTN_BITS_TIMERS_PARITY_ERROR (0x1<<4) +#define AEU_INPUTS_ATTN_BITS_TSDM_HW_INTERRUPT (0x1<<25) +#define AEU_INPUTS_ATTN_BITS_TSDM_PARITY_ERROR (0x1<<24) +#define AEU_INPUTS_ATTN_BITS_TSEMI_HW_INTERRUPT (0x1<<29) +#define AEU_INPUTS_ATTN_BITS_TSEMI_PARITY_ERROR (0x1<<28) +#define AEU_INPUTS_ATTN_BITS_UCM_HW_INTERRUPT (0x1<<23) +#define AEU_INPUTS_ATTN_BITS_UCM_PARITY_ERROR (0x1<<22) +#define AEU_INPUTS_ATTN_BITS_UPB_HW_INTERRUPT (0x1<<27) +#define AEU_INPUTS_ATTN_BITS_UPB_PARITY_ERROR (0x1<<26) +#define AEU_INPUTS_ATTN_BITS_USDM_HW_INTERRUPT (0x1<<21) +#define AEU_INPUTS_ATTN_BITS_USDM_PARITY_ERROR (0x1<<20) +#define AEU_INPUTS_ATTN_BITS_USEMI_HW_INTERRUPT (0x1<<25) +#define AEU_INPUTS_ATTN_BITS_USEMI_PARITY_ERROR (0x1<<24) +#define AEU_INPUTS_ATTN_BITS_VAUX_PCI_CORE_PARITY_ERROR (0x1<<16) +#define AEU_INPUTS_ATTN_BITS_XCM_HW_INTERRUPT (0x1<<9) +#define AEU_INPUTS_ATTN_BITS_XCM_PARITY_ERROR (0x1<<8) +#define AEU_INPUTS_ATTN_BITS_XSDM_HW_INTERRUPT (0x1<<7) +#define AEU_INPUTS_ATTN_BITS_XSDM_PARITY_ERROR (0x1<<6) +#define AEU_INPUTS_ATTN_BITS_XSEMI_HW_INTERRUPT (0x1<<11) +#define AEU_INPUTS_ATTN_BITS_XSEMI_PARITY_ERROR (0x1<<10) + +#define AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 (0x1<<5) +#define AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 (0x1<<9) + +#define RESERVED_GENERAL_ATTENTION_BIT_0 0 + +#define EVEREST_GEN_ATTN_IN_USE_MASK 0x7ffe0 +#define EVEREST_LATCHED_ATTN_IN_USE_MASK 0xffe00000 + +#define RESERVED_GENERAL_ATTENTION_BIT_6 6 +#define RESERVED_GENERAL_ATTENTION_BIT_7 7 +#define RESERVED_GENERAL_ATTENTION_BIT_8 8 +#define RESERVED_GENERAL_ATTENTION_BIT_9 9 +#define RESERVED_GENERAL_ATTENTION_BIT_10 10 +#define RESERVED_GENERAL_ATTENTION_BIT_11 11 +#define RESERVED_GENERAL_ATTENTION_BIT_12 12 +#define RESERVED_GENERAL_ATTENTION_BIT_13 13 +#define RESERVED_GENERAL_ATTENTION_BIT_14 14 +#define RESERVED_GENERAL_ATTENTION_BIT_15 15 +#define RESERVED_GENERAL_ATTENTION_BIT_16 16 +#define RESERVED_GENERAL_ATTENTION_BIT_17 17 +#define RESERVED_GENERAL_ATTENTION_BIT_18 18 +#define RESERVED_GENERAL_ATTENTION_BIT_19 19 +#define RESERVED_GENERAL_ATTENTION_BIT_20 20 +#define RESERVED_GENERAL_ATTENTION_BIT_21 21 + +/* storm asserts attention bits */ +#define TSTORM_FATAL_ASSERT_ATTENTION_BIT RESERVED_GENERAL_ATTENTION_BIT_7 +#define USTORM_FATAL_ASSERT_ATTENTION_BIT RESERVED_GENERAL_ATTENTION_BIT_8 +#define CSTORM_FATAL_ASSERT_ATTENTION_BIT RESERVED_GENERAL_ATTENTION_BIT_9 +#define XSTORM_FATAL_ASSERT_ATTENTION_BIT RESERVED_GENERAL_ATTENTION_BIT_10 + +/* mcp error attention bit */ +#define MCP_FATAL_ASSERT_ATTENTION_BIT RESERVED_GENERAL_ATTENTION_BIT_11 + +/*E1H NIG status sync attention mapped to group 4-7*/ +#define LINK_SYNC_ATTENTION_BIT_FUNC_0 RESERVED_GENERAL_ATTENTION_BIT_12 +#define LINK_SYNC_ATTENTION_BIT_FUNC_1 RESERVED_GENERAL_ATTENTION_BIT_13 +#define LINK_SYNC_ATTENTION_BIT_FUNC_2 RESERVED_GENERAL_ATTENTION_BIT_14 +#define LINK_SYNC_ATTENTION_BIT_FUNC_3 RESERVED_GENERAL_ATTENTION_BIT_15 +#define LINK_SYNC_ATTENTION_BIT_FUNC_4 RESERVED_GENERAL_ATTENTION_BIT_16 +#define LINK_SYNC_ATTENTION_BIT_FUNC_5 RESERVED_GENERAL_ATTENTION_BIT_17 +#define LINK_SYNC_ATTENTION_BIT_FUNC_6 RESERVED_GENERAL_ATTENTION_BIT_18 +#define LINK_SYNC_ATTENTION_BIT_FUNC_7 RESERVED_GENERAL_ATTENTION_BIT_19 + + +#define LATCHED_ATTN_RBCR 23 +#define LATCHED_ATTN_RBCT 24 +#define LATCHED_ATTN_RBCN 25 +#define LATCHED_ATTN_RBCU 26 +#define LATCHED_ATTN_RBCP 27 +#define LATCHED_ATTN_TIMEOUT_GRC 28 +#define LATCHED_ATTN_RSVD_GRC 29 +#define LATCHED_ATTN_ROM_PARITY_MCP 30 +#define LATCHED_ATTN_UM_RX_PARITY_MCP 31 +#define LATCHED_ATTN_UM_TX_PARITY_MCP 32 +#define LATCHED_ATTN_SCPAD_PARITY_MCP 33 + +#define GENERAL_ATTEN_WORD(atten_name) ((94 + atten_name) / 32) +#define GENERAL_ATTEN_OFFSET(atten_name)\ + (1UL << ((94 + atten_name) % 32)) +/* + * This file defines GRC base address for every block. + * This file is included by chipsim, asm microcode and cpp microcode. + * These values are used in Design.xml on regBase attribute + * Use the base with the generated offsets of specific registers. + */ + +#define GRCBASE_PXPCS 0x000000 +#define GRCBASE_PCICONFIG 0x002000 +#define GRCBASE_PCIREG 0x002400 +#define GRCBASE_EMAC0 0x008000 +#define GRCBASE_EMAC1 0x008400 +#define GRCBASE_DBU 0x008800 +#define GRCBASE_MISC 0x00A000 +#define GRCBASE_DBG 0x00C000 +#define GRCBASE_NIG 0x010000 +#define GRCBASE_XCM 0x020000 +#define GRCBASE_PRS 0x040000 +#define GRCBASE_SRCH 0x040400 +#define GRCBASE_TSDM 0x042000 +#define GRCBASE_TCM 0x050000 +#define GRCBASE_BRB1 0x060000 +#define GRCBASE_MCP 0x080000 +#define GRCBASE_UPB 0x0C1000 +#define GRCBASE_CSDM 0x0C2000 +#define GRCBASE_USDM 0x0C4000 +#define GRCBASE_CCM 0x0D0000 +#define GRCBASE_UCM 0x0E0000 +#define GRCBASE_CDU 0x101000 +#define GRCBASE_DMAE 0x102000 +#define GRCBASE_PXP 0x103000 +#define GRCBASE_CFC 0x104000 +#define GRCBASE_HC 0x108000 +#define GRCBASE_PXP2 0x120000 +#define GRCBASE_PBF 0x140000 +#define GRCBASE_UMAC0 0x160000 +#define GRCBASE_UMAC1 0x160400 +#define GRCBASE_XPB 0x161000 +#define GRCBASE_MSTAT0 0x162000 +#define GRCBASE_MSTAT1 0x162800 +#define GRCBASE_XMAC0 0x163000 +#define GRCBASE_XMAC1 0x163800 +#define GRCBASE_TIMERS 0x164000 +#define GRCBASE_XSDM 0x166000 +#define GRCBASE_QM 0x168000 +#define GRCBASE_DQ 0x170000 +#define GRCBASE_TSEM 0x180000 +#define GRCBASE_CSEM 0x200000 +#define GRCBASE_XSEM 0x280000 +#define GRCBASE_USEM 0x300000 +#define GRCBASE_MISC_AEU GRCBASE_MISC + + +/* offset of configuration space in the pci core register */ +#define PCICFG_OFFSET 0x2000 +#define PCICFG_VENDOR_ID_OFFSET 0x00 +#define PCICFG_DEVICE_ID_OFFSET 0x02 +#define PCICFG_COMMAND_OFFSET 0x04 +#define PCICFG_COMMAND_IO_SPACE (1<<0) +#define PCICFG_COMMAND_MEM_SPACE (1<<1) +#define PCICFG_COMMAND_BUS_MASTER (1<<2) +#define PCICFG_COMMAND_SPECIAL_CYCLES (1<<3) +#define PCICFG_COMMAND_MWI_CYCLES (1<<4) +#define PCICFG_COMMAND_VGA_SNOOP (1<<5) +#define PCICFG_COMMAND_PERR_ENA (1<<6) +#define PCICFG_COMMAND_STEPPING (1<<7) +#define PCICFG_COMMAND_SERR_ENA (1<<8) +#define PCICFG_COMMAND_FAST_B2B (1<<9) +#define PCICFG_COMMAND_INT_DISABLE (1<<10) +#define PCICFG_COMMAND_RESERVED (0x1f<<11) +#define PCICFG_STATUS_OFFSET 0x06 +#define PCICFG_REVESION_ID_OFFSET 0x08 +#define PCICFG_CACHE_LINE_SIZE 0x0c +#define PCICFG_LATENCY_TIMER 0x0d +#define PCICFG_BAR_1_LOW 0x10 +#define PCICFG_BAR_1_HIGH 0x14 +#define PCICFG_BAR_2_LOW 0x18 +#define PCICFG_BAR_2_HIGH 0x1c +#define PCICFG_SUBSYSTEM_VENDOR_ID_OFFSET 0x2c +#define PCICFG_SUBSYSTEM_ID_OFFSET 0x2e +#define PCICFG_INT_LINE 0x3c +#define PCICFG_INT_PIN 0x3d +#define PCICFG_PM_CAPABILITY 0x48 +#define PCICFG_PM_CAPABILITY_VERSION (0x3<<16) +#define PCICFG_PM_CAPABILITY_CLOCK (1<<19) +#define PCICFG_PM_CAPABILITY_RESERVED (1<<20) +#define PCICFG_PM_CAPABILITY_DSI (1<<21) +#define PCICFG_PM_CAPABILITY_AUX_CURRENT (0x7<<22) +#define PCICFG_PM_CAPABILITY_D1_SUPPORT (1<<25) +#define PCICFG_PM_CAPABILITY_D2_SUPPORT (1<<26) +#define PCICFG_PM_CAPABILITY_PME_IN_D0 (1<<27) +#define PCICFG_PM_CAPABILITY_PME_IN_D1 (1<<28) +#define PCICFG_PM_CAPABILITY_PME_IN_D2 (1<<29) +#define PCICFG_PM_CAPABILITY_PME_IN_D3_HOT (1<<30) +#define PCICFG_PM_CAPABILITY_PME_IN_D3_COLD (1<<31) +#define PCICFG_PM_CSR_OFFSET 0x4c +#define PCICFG_PM_CSR_STATE (0x3<<0) +#define PCICFG_PM_CSR_PME_ENABLE (1<<8) +#define PCICFG_PM_CSR_PME_STATUS (1<<15) +#define PCICFG_MSI_CAP_ID_OFFSET 0x58 +#define PCICFG_MSI_CONTROL_ENABLE (0x1<<16) +#define PCICFG_MSI_CONTROL_MCAP (0x7<<17) +#define PCICFG_MSI_CONTROL_MENA (0x7<<20) +#define PCICFG_MSI_CONTROL_64_BIT_ADDR_CAP (0x1<<23) +#define PCICFG_MSI_CONTROL_MSI_PVMASK_CAPABLE (0x1<<24) +#define PCICFG_GRC_ADDRESS 0x78 +#define PCICFG_GRC_DATA 0x80 +#define PCICFG_MSIX_CAP_ID_OFFSET 0xa0 +#define PCICFG_MSIX_CONTROL_TABLE_SIZE (0x7ff<<16) +#define PCICFG_MSIX_CONTROL_RESERVED (0x7<<27) +#define PCICFG_MSIX_CONTROL_FUNC_MASK (0x1<<30) +#define PCICFG_MSIX_CONTROL_MSIX_ENABLE (0x1<<31) + +#define PCICFG_DEVICE_CONTROL 0xb4 +#define PCICFG_DEVICE_STATUS 0xb6 +#define PCICFG_DEVICE_STATUS_CORR_ERR_DET (1<<0) +#define PCICFG_DEVICE_STATUS_NON_FATAL_ERR_DET (1<<1) +#define PCICFG_DEVICE_STATUS_FATAL_ERR_DET (1<<2) +#define PCICFG_DEVICE_STATUS_UNSUP_REQ_DET (1<<3) +#define PCICFG_DEVICE_STATUS_AUX_PWR_DET (1<<4) +#define PCICFG_DEVICE_STATUS_NO_PEND (1<<5) +#define PCICFG_LINK_CONTROL 0xbc + + +#define BAR_USTRORM_INTMEM 0x400000 +#define BAR_CSTRORM_INTMEM 0x410000 +#define BAR_XSTRORM_INTMEM 0x420000 +#define BAR_TSTRORM_INTMEM 0x430000 + +/* for accessing the IGU in case of status block ACK */ +#define BAR_IGU_INTMEM 0x440000 + +#define BAR_DOORBELL_OFFSET 0x800000 + +#define BAR_ME_REGISTER 0x450000 + +/* config_2 offset */ +#define GRC_CONFIG_2_SIZE_REG 0x408 +#define PCI_CONFIG_2_BAR1_SIZE (0xfL<<0) +#define PCI_CONFIG_2_BAR1_SIZE_DISABLED (0L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_64K (1L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_128K (2L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_256K (3L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_512K (4L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_1M (5L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_2M (6L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_4M (7L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_8M (8L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_16M (9L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_32M (10L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_64M (11L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_128M (12L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_256M (13L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_512M (14L<<0) +#define PCI_CONFIG_2_BAR1_SIZE_1G (15L<<0) +#define PCI_CONFIG_2_BAR1_64ENA (1L<<4) +#define PCI_CONFIG_2_EXP_ROM_RETRY (1L<<5) +#define PCI_CONFIG_2_CFG_CYCLE_RETRY (1L<<6) +#define PCI_CONFIG_2_FIRST_CFG_DONE (1L<<7) +#define PCI_CONFIG_2_EXP_ROM_SIZE (0xffL<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_DISABLED (0L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_2K (1L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_4K (2L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_8K (3L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_16K (4L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_32K (5L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_64K (6L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_128K (7L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_256K (8L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_512K (9L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_1M (10L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_2M (11L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_4M (12L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_8M (13L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_16M (14L<<8) +#define PCI_CONFIG_2_EXP_ROM_SIZE_32M (15L<<8) +#define PCI_CONFIG_2_BAR_PREFETCH (1L<<16) +#define PCI_CONFIG_2_RESERVED0 (0x7fffL<<17) + +/* config_3 offset */ +#define GRC_CONFIG_3_SIZE_REG 0x40c +#define PCI_CONFIG_3_STICKY_BYTE (0xffL<<0) +#define PCI_CONFIG_3_FORCE_PME (1L<<24) +#define PCI_CONFIG_3_PME_STATUS (1L<<25) +#define PCI_CONFIG_3_PME_ENABLE (1L<<26) +#define PCI_CONFIG_3_PM_STATE (0x3L<<27) +#define PCI_CONFIG_3_VAUX_PRESET (1L<<30) +#define PCI_CONFIG_3_PCI_POWER (1L<<31) + +#define GRC_BAR2_CONFIG 0x4e0 +#define PCI_CONFIG_2_BAR2_SIZE (0xfL<<0) +#define PCI_CONFIG_2_BAR2_SIZE_DISABLED (0L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_64K (1L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_128K (2L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_256K (3L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_512K (4L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_1M (5L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_2M (6L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_4M (7L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_8M (8L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_16M (9L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_32M (10L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_64M (11L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_128M (12L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_256M (13L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_512M (14L<<0) +#define PCI_CONFIG_2_BAR2_SIZE_1G (15L<<0) +#define PCI_CONFIG_2_BAR2_64ENA (1L<<4) + +#define PCI_PM_DATA_A 0x410 +#define PCI_PM_DATA_B 0x414 +#define PCI_ID_VAL1 0x434 +#define PCI_ID_VAL2 0x438 + +#define PXPCS_TL_CONTROL_5 0x814 +#define PXPCS_TL_CONTROL_5_UNKNOWNTYPE_ERR_ATTN (1 << 29) /*WC*/ +#define PXPCS_TL_CONTROL_5_BOUNDARY4K_ERR_ATTN (1 << 28) /*WC*/ +#define PXPCS_TL_CONTROL_5_MRRS_ERR_ATTN (1 << 27) /*WC*/ +#define PXPCS_TL_CONTROL_5_MPS_ERR_ATTN (1 << 26) /*WC*/ +#define PXPCS_TL_CONTROL_5_TTX_BRIDGE_FORWARD_ERR (1 << 25) /*WC*/ +#define PXPCS_TL_CONTROL_5_TTX_TXINTF_OVERFLOW (1 << 24) /*WC*/ +#define PXPCS_TL_CONTROL_5_PHY_ERR_ATTN (1 << 23) /*RO*/ +#define PXPCS_TL_CONTROL_5_DL_ERR_ATTN (1 << 22) /*RO*/ +#define PXPCS_TL_CONTROL_5_TTX_ERR_NP_TAG_IN_USE (1 << 21) /*WC*/ +#define PXPCS_TL_CONTROL_5_TRX_ERR_UNEXP_RTAG (1 << 20) /*WC*/ +#define PXPCS_TL_CONTROL_5_PRI_SIG_TARGET_ABORT1 (1 << 19) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_UNSPPORT1 (1 << 18) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_ECRC1 (1 << 17) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_MALF_TLP1 (1 << 16) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_RX_OFLOW1 (1 << 15) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_UNEXP_CPL1 (1 << 14) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_MASTER_ABRT1 (1 << 13) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_CPL_TIMEOUT1 (1 << 12) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_FC_PRTL1 (1 << 11) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_PSND_TLP1 (1 << 10) /*WC*/ +#define PXPCS_TL_CONTROL_5_PRI_SIG_TARGET_ABORT (1 << 9) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_UNSPPORT (1 << 8) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_ECRC (1 << 7) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_MALF_TLP (1 << 6) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_RX_OFLOW (1 << 5) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_UNEXP_CPL (1 << 4) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_MASTER_ABRT (1 << 3) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_CPL_TIMEOUT (1 << 2) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_FC_PRTL (1 << 1) /*WC*/ +#define PXPCS_TL_CONTROL_5_ERR_PSND_TLP (1 << 0) /*WC*/ + + +#define PXPCS_TL_FUNC345_STAT 0x854 +#define PXPCS_TL_FUNC345_STAT_PRI_SIG_TARGET_ABORT4 (1 << 29) /* WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT4\ + (1 << 28) /* Unsupported Request Error Status in function4, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_ECRC4\ + (1 << 27) /* ECRC Error TLP Status Status in function 4, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_MALF_TLP4\ + (1 << 26) /* Malformed TLP Status Status in function 4, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_RX_OFLOW4\ + (1 << 25) /* Receiver Overflow Status Status in function 4, if \ + set, generate pcie_err_attn output when this error is seen.. WC \ + */ +#define PXPCS_TL_FUNC345_STAT_ERR_UNEXP_CPL4\ + (1 << 24) /* Unexpected Completion Status Status in function 4, \ + if set, generate pcie_err_attn output when this error is seen. WC \ + */ +#define PXPCS_TL_FUNC345_STAT_ERR_MASTER_ABRT4\ + (1 << 23) /* Receive UR Statusin function 4. If set, generate \ + pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_CPL_TIMEOUT4\ + (1 << 22) /* Completer Timeout Status Status in function 4, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_FC_PRTL4\ + (1 << 21) /* Flow Control Protocol Error Status Status in \ + function 4, if set, generate pcie_err_attn output when this error \ + is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_PSND_TLP4\ + (1 << 20) /* Poisoned Error Status Status in function 4, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC345_STAT_PRI_SIG_TARGET_ABORT3 (1 << 19) /* WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT3\ + (1 << 18) /* Unsupported Request Error Status in function3, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_ECRC3\ + (1 << 17) /* ECRC Error TLP Status Status in function 3, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_MALF_TLP3\ + (1 << 16) /* Malformed TLP Status Status in function 3, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_RX_OFLOW3\ + (1 << 15) /* Receiver Overflow Status Status in function 3, if \ + set, generate pcie_err_attn output when this error is seen.. WC \ + */ +#define PXPCS_TL_FUNC345_STAT_ERR_UNEXP_CPL3\ + (1 << 14) /* Unexpected Completion Status Status in function 3, \ + if set, generate pcie_err_attn output when this error is seen. WC \ + */ +#define PXPCS_TL_FUNC345_STAT_ERR_MASTER_ABRT3\ + (1 << 13) /* Receive UR Statusin function 3. If set, generate \ + pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_CPL_TIMEOUT3\ + (1 << 12) /* Completer Timeout Status Status in function 3, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_FC_PRTL3\ + (1 << 11) /* Flow Control Protocol Error Status Status in \ + function 3, if set, generate pcie_err_attn output when this error \ + is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_PSND_TLP3\ + (1 << 10) /* Poisoned Error Status Status in function 3, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC345_STAT_PRI_SIG_TARGET_ABORT2 (1 << 9) /* WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_UNSPPORT2\ + (1 << 8) /* Unsupported Request Error Status for Function 2, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_ECRC2\ + (1 << 7) /* ECRC Error TLP Status Status for Function 2, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_MALF_TLP2\ + (1 << 6) /* Malformed TLP Status Status for Function 2, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_RX_OFLOW2\ + (1 << 5) /* Receiver Overflow Status Status for Function 2, if \ + set, generate pcie_err_attn output when this error is seen.. WC \ + */ +#define PXPCS_TL_FUNC345_STAT_ERR_UNEXP_CPL2\ + (1 << 4) /* Unexpected Completion Status Status for Function 2, \ + if set, generate pcie_err_attn output when this error is seen. WC \ + */ +#define PXPCS_TL_FUNC345_STAT_ERR_MASTER_ABRT2\ + (1 << 3) /* Receive UR Statusfor Function 2. If set, generate \ + pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_CPL_TIMEOUT2\ + (1 << 2) /* Completer Timeout Status Status for Function 2, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_FC_PRTL2\ + (1 << 1) /* Flow Control Protocol Error Status Status for \ + Function 2, if set, generate pcie_err_attn output when this error \ + is seen. WC */ +#define PXPCS_TL_FUNC345_STAT_ERR_PSND_TLP2\ + (1 << 0) /* Poisoned Error Status Status for Function 2, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ + + +#define PXPCS_TL_FUNC678_STAT 0x85C +#define PXPCS_TL_FUNC678_STAT_PRI_SIG_TARGET_ABORT7 (1 << 29) /* WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT7\ + (1 << 28) /* Unsupported Request Error Status in function7, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_ECRC7\ + (1 << 27) /* ECRC Error TLP Status Status in function 7, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_MALF_TLP7\ + (1 << 26) /* Malformed TLP Status Status in function 7, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_RX_OFLOW7\ + (1 << 25) /* Receiver Overflow Status Status in function 7, if \ + set, generate pcie_err_attn output when this error is seen.. WC \ + */ +#define PXPCS_TL_FUNC678_STAT_ERR_UNEXP_CPL7\ + (1 << 24) /* Unexpected Completion Status Status in function 7, \ + if set, generate pcie_err_attn output when this error is seen. WC \ + */ +#define PXPCS_TL_FUNC678_STAT_ERR_MASTER_ABRT7\ + (1 << 23) /* Receive UR Statusin function 7. If set, generate \ + pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_CPL_TIMEOUT7\ + (1 << 22) /* Completer Timeout Status Status in function 7, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_FC_PRTL7\ + (1 << 21) /* Flow Control Protocol Error Status Status in \ + function 7, if set, generate pcie_err_attn output when this error \ + is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_PSND_TLP7\ + (1 << 20) /* Poisoned Error Status Status in function 7, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC678_STAT_PRI_SIG_TARGET_ABORT6 (1 << 19) /* WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT6\ + (1 << 18) /* Unsupported Request Error Status in function6, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_ECRC6\ + (1 << 17) /* ECRC Error TLP Status Status in function 6, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_MALF_TLP6\ + (1 << 16) /* Malformed TLP Status Status in function 6, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_RX_OFLOW6\ + (1 << 15) /* Receiver Overflow Status Status in function 6, if \ + set, generate pcie_err_attn output when this error is seen.. WC \ + */ +#define PXPCS_TL_FUNC678_STAT_ERR_UNEXP_CPL6\ + (1 << 14) /* Unexpected Completion Status Status in function 6, \ + if set, generate pcie_err_attn output when this error is seen. WC \ + */ +#define PXPCS_TL_FUNC678_STAT_ERR_MASTER_ABRT6\ + (1 << 13) /* Receive UR Statusin function 6. If set, generate \ + pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_CPL_TIMEOUT6\ + (1 << 12) /* Completer Timeout Status Status in function 6, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_FC_PRTL6\ + (1 << 11) /* Flow Control Protocol Error Status Status in \ + function 6, if set, generate pcie_err_attn output when this error \ + is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_PSND_TLP6\ + (1 << 10) /* Poisoned Error Status Status in function 6, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC678_STAT_PRI_SIG_TARGET_ABORT5 (1 << 9) /* WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_UNSPPORT5\ + (1 << 8) /* Unsupported Request Error Status for Function 5, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_ECRC5\ + (1 << 7) /* ECRC Error TLP Status Status for Function 5, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_MALF_TLP5\ + (1 << 6) /* Malformed TLP Status Status for Function 5, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_RX_OFLOW5\ + (1 << 5) /* Receiver Overflow Status Status for Function 5, if \ + set, generate pcie_err_attn output when this error is seen.. WC \ + */ +#define PXPCS_TL_FUNC678_STAT_ERR_UNEXP_CPL5\ + (1 << 4) /* Unexpected Completion Status Status for Function 5, \ + if set, generate pcie_err_attn output when this error is seen. WC \ + */ +#define PXPCS_TL_FUNC678_STAT_ERR_MASTER_ABRT5\ + (1 << 3) /* Receive UR Statusfor Function 5. If set, generate \ + pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_CPL_TIMEOUT5\ + (1 << 2) /* Completer Timeout Status Status for Function 5, if \ + set, generate pcie_err_attn output when this error is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_FC_PRTL5\ + (1 << 1) /* Flow Control Protocol Error Status Status for \ + Function 5, if set, generate pcie_err_attn output when this error \ + is seen. WC */ +#define PXPCS_TL_FUNC678_STAT_ERR_PSND_TLP5\ + (1 << 0) /* Poisoned Error Status Status for Function 5, if set, \ + generate pcie_err_attn output when this error is seen.. WC */ + + +#define BAR_USTRORM_INTMEM 0x400000 +#define BAR_CSTRORM_INTMEM 0x410000 +#define BAR_XSTRORM_INTMEM 0x420000 +#define BAR_TSTRORM_INTMEM 0x430000 + +/* for accessing the IGU in case of status block ACK */ +#define BAR_IGU_INTMEM 0x440000 + +#define BAR_DOORBELL_OFFSET 0x800000 + +#define BAR_ME_REGISTER 0x450000 +#define ME_REG_PF_NUM_SHIFT 0 +#define ME_REG_PF_NUM\ + (7L<> 1; + } + + /* split the crc into 8 bits */ + for (i = 0; i < 8; i++) { + C[i] = crc & 1; + crc = crc >> 1; + } + + NewCRC[0] = D[31] ^ D[30] ^ D[28] ^ D[23] ^ D[21] ^ D[19] ^ D[18] ^ + D[16] ^ D[14] ^ D[12] ^ D[8] ^ D[7] ^ D[6] ^ D[0] ^ C[4] ^ + C[6] ^ C[7]; + NewCRC[1] = D[30] ^ D[29] ^ D[28] ^ D[24] ^ D[23] ^ D[22] ^ D[21] ^ + D[20] ^ D[18] ^ D[17] ^ D[16] ^ D[15] ^ D[14] ^ D[13] ^ + D[12] ^ D[9] ^ D[6] ^ D[1] ^ D[0] ^ C[0] ^ C[4] ^ C[5] ^ + C[6]; + NewCRC[2] = D[29] ^ D[28] ^ D[25] ^ D[24] ^ D[22] ^ D[17] ^ D[15] ^ + D[13] ^ D[12] ^ D[10] ^ D[8] ^ D[6] ^ D[2] ^ D[1] ^ D[0] ^ + C[0] ^ C[1] ^ C[4] ^ C[5]; + NewCRC[3] = D[30] ^ D[29] ^ D[26] ^ D[25] ^ D[23] ^ D[18] ^ D[16] ^ + D[14] ^ D[13] ^ D[11] ^ D[9] ^ D[7] ^ D[3] ^ D[2] ^ D[1] ^ + C[1] ^ C[2] ^ C[5] ^ C[6]; + NewCRC[4] = D[31] ^ D[30] ^ D[27] ^ D[26] ^ D[24] ^ D[19] ^ D[17] ^ + D[15] ^ D[14] ^ D[12] ^ D[10] ^ D[8] ^ D[4] ^ D[3] ^ D[2] ^ + C[0] ^ C[2] ^ C[3] ^ C[6] ^ C[7]; + NewCRC[5] = D[31] ^ D[28] ^ D[27] ^ D[25] ^ D[20] ^ D[18] ^ D[16] ^ + D[15] ^ D[13] ^ D[11] ^ D[9] ^ D[5] ^ D[4] ^ D[3] ^ C[1] ^ + C[3] ^ C[4] ^ C[7]; + NewCRC[6] = D[29] ^ D[28] ^ D[26] ^ D[21] ^ D[19] ^ D[17] ^ D[16] ^ + D[14] ^ D[12] ^ D[10] ^ D[6] ^ D[5] ^ D[4] ^ C[2] ^ C[4] ^ + C[5]; + NewCRC[7] = D[30] ^ D[29] ^ D[27] ^ D[22] ^ D[20] ^ D[18] ^ D[17] ^ + D[15] ^ D[13] ^ D[11] ^ D[7] ^ D[6] ^ D[5] ^ C[3] ^ C[5] ^ + C[6]; + + crc_res = 0; + for (i = 0; i < 8; i++) + crc_res |= (NewCRC[i] << i); + + return crc_res; +} + + +#endif /* BNX2X_REG_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c new file mode 100644 index 000000000000..df52f110c6c5 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -0,0 +1,5692 @@ +/* bnx2x_sp.c: Broadcom Everest network driver. + * + * Copyright 2011 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + * + * Maintained by: Eilon Greenstein + * Written by: Vladislav Zolotarov + * + */ +#include +#include +#include +#include +#include +#include "bnx2x.h" +#include "bnx2x_cmn.h" +#include "bnx2x_sp.h" + +#define BNX2X_MAX_EMUL_MULTI 16 + +/**** Exe Queue interfaces ****/ + +/** + * bnx2x_exe_queue_init - init the Exe Queue object + * + * @o: poiter to the object + * @exe_len: length + * @owner: poiter to the owner + * @validate: validate function pointer + * @optimize: optimize function pointer + * @exec: execute function pointer + * @get: get function pointer + */ +static inline void bnx2x_exe_queue_init(struct bnx2x *bp, + struct bnx2x_exe_queue_obj *o, + int exe_len, + union bnx2x_qable_obj *owner, + exe_q_validate validate, + exe_q_optimize optimize, + exe_q_execute exec, + exe_q_get get) +{ + memset(o, 0, sizeof(*o)); + + INIT_LIST_HEAD(&o->exe_queue); + INIT_LIST_HEAD(&o->pending_comp); + + spin_lock_init(&o->lock); + + o->exe_chunk_len = exe_len; + o->owner = owner; + + /* Owner specific callbacks */ + o->validate = validate; + o->optimize = optimize; + o->execute = exec; + o->get = get; + + DP(BNX2X_MSG_SP, "Setup the execution queue with the chunk " + "length of %d\n", exe_len); +} + +static inline void bnx2x_exe_queue_free_elem(struct bnx2x *bp, + struct bnx2x_exeq_elem *elem) +{ + DP(BNX2X_MSG_SP, "Deleting an exe_queue element\n"); + kfree(elem); +} + +static inline int bnx2x_exe_queue_length(struct bnx2x_exe_queue_obj *o) +{ + struct bnx2x_exeq_elem *elem; + int cnt = 0; + + spin_lock_bh(&o->lock); + + list_for_each_entry(elem, &o->exe_queue, link) + cnt++; + + spin_unlock_bh(&o->lock); + + return cnt; +} + +/** + * bnx2x_exe_queue_add - add a new element to the execution queue + * + * @bp: driver handle + * @o: queue + * @cmd: new command to add + * @restore: true - do not optimize the command + * + * If the element is optimized or is illegal, frees it. + */ +static inline int bnx2x_exe_queue_add(struct bnx2x *bp, + struct bnx2x_exe_queue_obj *o, + struct bnx2x_exeq_elem *elem, + bool restore) +{ + int rc; + + spin_lock_bh(&o->lock); + + if (!restore) { + /* Try to cancel this element queue */ + rc = o->optimize(bp, o->owner, elem); + if (rc) + goto free_and_exit; + + /* Check if this request is ok */ + rc = o->validate(bp, o->owner, elem); + if (rc) { + BNX2X_ERR("Preamble failed: %d\n", rc); + goto free_and_exit; + } + } + + /* If so, add it to the execution queue */ + list_add_tail(&elem->link, &o->exe_queue); + + spin_unlock_bh(&o->lock); + + return 0; + +free_and_exit: + bnx2x_exe_queue_free_elem(bp, elem); + + spin_unlock_bh(&o->lock); + + return rc; + +} + +static inline void __bnx2x_exe_queue_reset_pending( + struct bnx2x *bp, + struct bnx2x_exe_queue_obj *o) +{ + struct bnx2x_exeq_elem *elem; + + while (!list_empty(&o->pending_comp)) { + elem = list_first_entry(&o->pending_comp, + struct bnx2x_exeq_elem, link); + + list_del(&elem->link); + bnx2x_exe_queue_free_elem(bp, elem); + } +} + +static inline void bnx2x_exe_queue_reset_pending(struct bnx2x *bp, + struct bnx2x_exe_queue_obj *o) +{ + + spin_lock_bh(&o->lock); + + __bnx2x_exe_queue_reset_pending(bp, o); + + spin_unlock_bh(&o->lock); + +} + +/** + * bnx2x_exe_queue_step - execute one execution chunk atomically + * + * @bp: driver handle + * @o: queue + * @ramrod_flags: flags + * + * (Atomicy is ensured using the exe_queue->lock). + */ +static inline int bnx2x_exe_queue_step(struct bnx2x *bp, + struct bnx2x_exe_queue_obj *o, + unsigned long *ramrod_flags) +{ + struct bnx2x_exeq_elem *elem, spacer; + int cur_len = 0, rc; + + memset(&spacer, 0, sizeof(spacer)); + + spin_lock_bh(&o->lock); + + /* + * Next step should not be performed until the current is finished, + * unless a DRV_CLEAR_ONLY bit is set. In this case we just want to + * properly clear object internals without sending any command to the FW + * which also implies there won't be any completion to clear the + * 'pending' list. + */ + if (!list_empty(&o->pending_comp)) { + if (test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags)) { + DP(BNX2X_MSG_SP, "RAMROD_DRV_CLR_ONLY requested: " + "resetting pending_comp\n"); + __bnx2x_exe_queue_reset_pending(bp, o); + } else { + spin_unlock_bh(&o->lock); + return 1; + } + } + + /* + * Run through the pending commands list and create a next + * execution chunk. + */ + while (!list_empty(&o->exe_queue)) { + elem = list_first_entry(&o->exe_queue, struct bnx2x_exeq_elem, + link); + WARN_ON(!elem->cmd_len); + + if (cur_len + elem->cmd_len <= o->exe_chunk_len) { + cur_len += elem->cmd_len; + /* + * Prevent from both lists being empty when moving an + * element. This will allow the call of + * bnx2x_exe_queue_empty() without locking. + */ + list_add_tail(&spacer.link, &o->pending_comp); + mb(); + list_del(&elem->link); + list_add_tail(&elem->link, &o->pending_comp); + list_del(&spacer.link); + } else + break; + } + + /* Sanity check */ + if (!cur_len) { + spin_unlock_bh(&o->lock); + return 0; + } + + rc = o->execute(bp, o->owner, &o->pending_comp, ramrod_flags); + if (rc < 0) + /* + * In case of an error return the commands back to the queue + * and reset the pending_comp. + */ + list_splice_init(&o->pending_comp, &o->exe_queue); + else if (!rc) + /* + * If zero is returned, means there are no outstanding pending + * completions and we may dismiss the pending list. + */ + __bnx2x_exe_queue_reset_pending(bp, o); + + spin_unlock_bh(&o->lock); + return rc; +} + +static inline bool bnx2x_exe_queue_empty(struct bnx2x_exe_queue_obj *o) +{ + bool empty = list_empty(&o->exe_queue); + + /* Don't reorder!!! */ + mb(); + + return empty && list_empty(&o->pending_comp); +} + +static inline struct bnx2x_exeq_elem *bnx2x_exe_queue_alloc_elem( + struct bnx2x *bp) +{ + DP(BNX2X_MSG_SP, "Allocating a new exe_queue element\n"); + return kzalloc(sizeof(struct bnx2x_exeq_elem), GFP_ATOMIC); +} + +/************************ raw_obj functions ***********************************/ +static bool bnx2x_raw_check_pending(struct bnx2x_raw_obj *o) +{ + return !!test_bit(o->state, o->pstate); +} + +static void bnx2x_raw_clear_pending(struct bnx2x_raw_obj *o) +{ + smp_mb__before_clear_bit(); + clear_bit(o->state, o->pstate); + smp_mb__after_clear_bit(); +} + +static void bnx2x_raw_set_pending(struct bnx2x_raw_obj *o) +{ + smp_mb__before_clear_bit(); + set_bit(o->state, o->pstate); + smp_mb__after_clear_bit(); +} + +/** + * bnx2x_state_wait - wait until the given bit(state) is cleared + * + * @bp: device handle + * @state: state which is to be cleared + * @state_p: state buffer + * + */ +static inline int bnx2x_state_wait(struct bnx2x *bp, int state, + unsigned long *pstate) +{ + /* can take a while if any port is running */ + int cnt = 5000; + + + if (CHIP_REV_IS_EMUL(bp)) + cnt *= 20; + + DP(BNX2X_MSG_SP, "waiting for state to become %d\n", state); + + might_sleep(); + while (cnt--) { + if (!test_bit(state, pstate)) { +#ifdef BNX2X_STOP_ON_ERROR + DP(BNX2X_MSG_SP, "exit (cnt %d)\n", 5000 - cnt); +#endif + return 0; + } + + usleep_range(1000, 1000); + + if (bp->panic) + return -EIO; + } + + /* timeout! */ + BNX2X_ERR("timeout waiting for state %d\n", state); +#ifdef BNX2X_STOP_ON_ERROR + bnx2x_panic(); +#endif + + return -EBUSY; +} + +static int bnx2x_raw_wait(struct bnx2x *bp, struct bnx2x_raw_obj *raw) +{ + return bnx2x_state_wait(bp, raw->state, raw->pstate); +} + +/***************** Classification verbs: Set/Del MAC/VLAN/VLAN-MAC ************/ +/* credit handling callbacks */ +static bool bnx2x_get_cam_offset_mac(struct bnx2x_vlan_mac_obj *o, int *offset) +{ + struct bnx2x_credit_pool_obj *mp = o->macs_pool; + + WARN_ON(!mp); + + return mp->get_entry(mp, offset); +} + +static bool bnx2x_get_credit_mac(struct bnx2x_vlan_mac_obj *o) +{ + struct bnx2x_credit_pool_obj *mp = o->macs_pool; + + WARN_ON(!mp); + + return mp->get(mp, 1); +} + +static bool bnx2x_get_cam_offset_vlan(struct bnx2x_vlan_mac_obj *o, int *offset) +{ + struct bnx2x_credit_pool_obj *vp = o->vlans_pool; + + WARN_ON(!vp); + + return vp->get_entry(vp, offset); +} + +static bool bnx2x_get_credit_vlan(struct bnx2x_vlan_mac_obj *o) +{ + struct bnx2x_credit_pool_obj *vp = o->vlans_pool; + + WARN_ON(!vp); + + return vp->get(vp, 1); +} + +static bool bnx2x_get_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o) +{ + struct bnx2x_credit_pool_obj *mp = o->macs_pool; + struct bnx2x_credit_pool_obj *vp = o->vlans_pool; + + if (!mp->get(mp, 1)) + return false; + + if (!vp->get(vp, 1)) { + mp->put(mp, 1); + return false; + } + + return true; +} + +static bool bnx2x_put_cam_offset_mac(struct bnx2x_vlan_mac_obj *o, int offset) +{ + struct bnx2x_credit_pool_obj *mp = o->macs_pool; + + return mp->put_entry(mp, offset); +} + +static bool bnx2x_put_credit_mac(struct bnx2x_vlan_mac_obj *o) +{ + struct bnx2x_credit_pool_obj *mp = o->macs_pool; + + return mp->put(mp, 1); +} + +static bool bnx2x_put_cam_offset_vlan(struct bnx2x_vlan_mac_obj *o, int offset) +{ + struct bnx2x_credit_pool_obj *vp = o->vlans_pool; + + return vp->put_entry(vp, offset); +} + +static bool bnx2x_put_credit_vlan(struct bnx2x_vlan_mac_obj *o) +{ + struct bnx2x_credit_pool_obj *vp = o->vlans_pool; + + return vp->put(vp, 1); +} + +static bool bnx2x_put_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o) +{ + struct bnx2x_credit_pool_obj *mp = o->macs_pool; + struct bnx2x_credit_pool_obj *vp = o->vlans_pool; + + if (!mp->put(mp, 1)) + return false; + + if (!vp->put(vp, 1)) { + mp->get(mp, 1); + return false; + } + + return true; +} + +/* check_add() callbacks */ +static int bnx2x_check_mac_add(struct bnx2x_vlan_mac_obj *o, + union bnx2x_classification_ramrod_data *data) +{ + struct bnx2x_vlan_mac_registry_elem *pos; + + if (!is_valid_ether_addr(data->mac.mac)) + return -EINVAL; + + /* Check if a requested MAC already exists */ + list_for_each_entry(pos, &o->head, link) + if (!memcmp(data->mac.mac, pos->u.mac.mac, ETH_ALEN)) + return -EEXIST; + + return 0; +} + +static int bnx2x_check_vlan_add(struct bnx2x_vlan_mac_obj *o, + union bnx2x_classification_ramrod_data *data) +{ + struct bnx2x_vlan_mac_registry_elem *pos; + + list_for_each_entry(pos, &o->head, link) + if (data->vlan.vlan == pos->u.vlan.vlan) + return -EEXIST; + + return 0; +} + +static int bnx2x_check_vlan_mac_add(struct bnx2x_vlan_mac_obj *o, + union bnx2x_classification_ramrod_data *data) +{ + struct bnx2x_vlan_mac_registry_elem *pos; + + list_for_each_entry(pos, &o->head, link) + if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) && + (!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac, + ETH_ALEN))) + return -EEXIST; + + return 0; +} + + +/* check_del() callbacks */ +static struct bnx2x_vlan_mac_registry_elem * + bnx2x_check_mac_del(struct bnx2x_vlan_mac_obj *o, + union bnx2x_classification_ramrod_data *data) +{ + struct bnx2x_vlan_mac_registry_elem *pos; + + list_for_each_entry(pos, &o->head, link) + if (!memcmp(data->mac.mac, pos->u.mac.mac, ETH_ALEN)) + return pos; + + return NULL; +} + +static struct bnx2x_vlan_mac_registry_elem * + bnx2x_check_vlan_del(struct bnx2x_vlan_mac_obj *o, + union bnx2x_classification_ramrod_data *data) +{ + struct bnx2x_vlan_mac_registry_elem *pos; + + list_for_each_entry(pos, &o->head, link) + if (data->vlan.vlan == pos->u.vlan.vlan) + return pos; + + return NULL; +} + +static struct bnx2x_vlan_mac_registry_elem * + bnx2x_check_vlan_mac_del(struct bnx2x_vlan_mac_obj *o, + union bnx2x_classification_ramrod_data *data) +{ + struct bnx2x_vlan_mac_registry_elem *pos; + + list_for_each_entry(pos, &o->head, link) + if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) && + (!memcmp(data->vlan_mac.mac, pos->u.vlan_mac.mac, + ETH_ALEN))) + return pos; + + return NULL; +} + +/* check_move() callback */ +static bool bnx2x_check_move(struct bnx2x_vlan_mac_obj *src_o, + struct bnx2x_vlan_mac_obj *dst_o, + union bnx2x_classification_ramrod_data *data) +{ + struct bnx2x_vlan_mac_registry_elem *pos; + int rc; + + /* Check if we can delete the requested configuration from the first + * object. + */ + pos = src_o->check_del(src_o, data); + + /* check if configuration can be added */ + rc = dst_o->check_add(dst_o, data); + + /* If this classification can not be added (is already set) + * or can't be deleted - return an error. + */ + if (rc || !pos) + return false; + + return true; +} + +static bool bnx2x_check_move_always_err( + struct bnx2x_vlan_mac_obj *src_o, + struct bnx2x_vlan_mac_obj *dst_o, + union bnx2x_classification_ramrod_data *data) +{ + return false; +} + + +static inline u8 bnx2x_vlan_mac_get_rx_tx_flag(struct bnx2x_vlan_mac_obj *o) +{ + struct bnx2x_raw_obj *raw = &o->raw; + u8 rx_tx_flag = 0; + + if ((raw->obj_type == BNX2X_OBJ_TYPE_TX) || + (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX)) + rx_tx_flag |= ETH_CLASSIFY_CMD_HEADER_TX_CMD; + + if ((raw->obj_type == BNX2X_OBJ_TYPE_RX) || + (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX)) + rx_tx_flag |= ETH_CLASSIFY_CMD_HEADER_RX_CMD; + + return rx_tx_flag; +} + +/* LLH CAM line allocations */ +enum { + LLH_CAM_ISCSI_ETH_LINE = 0, + LLH_CAM_ETH_LINE, + LLH_CAM_MAX_PF_LINE = NIG_REG_LLH1_FUNC_MEM_SIZE / 2 +}; + +static inline void bnx2x_set_mac_in_nig(struct bnx2x *bp, + bool add, unsigned char *dev_addr, int index) +{ + u32 wb_data[2]; + u32 reg_offset = BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM : + NIG_REG_LLH0_FUNC_MEM; + + if (!IS_MF_SI(bp) || index > LLH_CAM_MAX_PF_LINE) + return; + + DP(BNX2X_MSG_SP, "Going to %s LLH configuration at entry %d\n", + (add ? "ADD" : "DELETE"), index); + + if (add) { + /* LLH_FUNC_MEM is a u64 WB register */ + reg_offset += 8*index; + + wb_data[0] = ((dev_addr[2] << 24) | (dev_addr[3] << 16) | + (dev_addr[4] << 8) | dev_addr[5]); + wb_data[1] = ((dev_addr[0] << 8) | dev_addr[1]); + + REG_WR_DMAE(bp, reg_offset, wb_data, 2); + } + + REG_WR(bp, (BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM_ENABLE : + NIG_REG_LLH0_FUNC_MEM_ENABLE) + 4*index, add); +} + +/** + * bnx2x_vlan_mac_set_cmd_hdr_e2 - set a header in a single classify ramrod + * + * @bp: device handle + * @o: queue for which we want to configure this rule + * @add: if true the command is an ADD command, DEL otherwise + * @opcode: CLASSIFY_RULE_OPCODE_XXX + * @hdr: pointer to a header to setup + * + */ +static inline void bnx2x_vlan_mac_set_cmd_hdr_e2(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, bool add, int opcode, + struct eth_classify_cmd_header *hdr) +{ + struct bnx2x_raw_obj *raw = &o->raw; + + hdr->client_id = raw->cl_id; + hdr->func_id = raw->func_id; + + /* Rx or/and Tx (internal switching) configuration ? */ + hdr->cmd_general_data |= + bnx2x_vlan_mac_get_rx_tx_flag(o); + + if (add) + hdr->cmd_general_data |= ETH_CLASSIFY_CMD_HEADER_IS_ADD; + + hdr->cmd_general_data |= + (opcode << ETH_CLASSIFY_CMD_HEADER_OPCODE_SHIFT); +} + +/** + * bnx2x_vlan_mac_set_rdata_hdr_e2 - set the classify ramrod data header + * + * @cid: connection id + * @type: BNX2X_FILTER_XXX_PENDING + * @hdr: poiter to header to setup + * @rule_cnt: + * + * currently we always configure one rule and echo field to contain a CID and an + * opcode type. + */ +static inline void bnx2x_vlan_mac_set_rdata_hdr_e2(u32 cid, int type, + struct eth_classify_header *hdr, int rule_cnt) +{ + hdr->echo = (cid & BNX2X_SWCID_MASK) | (type << BNX2X_SWCID_SHIFT); + hdr->rule_cnt = (u8)rule_cnt; +} + + +/* hw_config() callbacks */ +static void bnx2x_set_one_mac_e2(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + struct bnx2x_exeq_elem *elem, int rule_idx, + int cam_offset) +{ + struct bnx2x_raw_obj *raw = &o->raw; + struct eth_classify_rules_ramrod_data *data = + (struct eth_classify_rules_ramrod_data *)(raw->rdata); + int rule_cnt = rule_idx + 1, cmd = elem->cmd_data.vlan_mac.cmd; + union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx]; + bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false; + unsigned long *vlan_mac_flags = &elem->cmd_data.vlan_mac.vlan_mac_flags; + u8 *mac = elem->cmd_data.vlan_mac.u.mac.mac; + + /* + * Set LLH CAM entry: currently only iSCSI and ETH macs are + * relevant. In addition, current implementation is tuned for a + * single ETH MAC. + * + * When multiple unicast ETH MACs PF configuration in switch + * independent mode is required (NetQ, multiple netdev MACs, + * etc.), consider better utilisation of 8 per function MAC + * entries in the LLH register. There is also + * NIG_REG_P[01]_LLH_FUNC_MEM2 registers that complete the + * total number of CAM entries to 16. + * + * Currently we won't configure NIG for MACs other than a primary ETH + * MAC and iSCSI L2 MAC. + * + * If this MAC is moving from one Queue to another, no need to change + * NIG configuration. + */ + if (cmd != BNX2X_VLAN_MAC_MOVE) { + if (test_bit(BNX2X_ISCSI_ETH_MAC, vlan_mac_flags)) + bnx2x_set_mac_in_nig(bp, add, mac, + LLH_CAM_ISCSI_ETH_LINE); + else if (test_bit(BNX2X_ETH_MAC, vlan_mac_flags)) + bnx2x_set_mac_in_nig(bp, add, mac, LLH_CAM_ETH_LINE); + } + + /* Reset the ramrod data buffer for the first rule */ + if (rule_idx == 0) + memset(data, 0, sizeof(*data)); + + /* Setup a command header */ + bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_MAC, + &rule_entry->mac.header); + + DP(BNX2X_MSG_SP, "About to %s MAC "BNX2X_MAC_FMT" for " + "Queue %d\n", (add ? "add" : "delete"), + BNX2X_MAC_PRN_LIST(mac), raw->cl_id); + + /* Set a MAC itself */ + bnx2x_set_fw_mac_addr(&rule_entry->mac.mac_msb, + &rule_entry->mac.mac_mid, + &rule_entry->mac.mac_lsb, mac); + + /* MOVE: Add a rule that will add this MAC to the target Queue */ + if (cmd == BNX2X_VLAN_MAC_MOVE) { + rule_entry++; + rule_cnt++; + + /* Setup ramrod data */ + bnx2x_vlan_mac_set_cmd_hdr_e2(bp, + elem->cmd_data.vlan_mac.target_obj, + true, CLASSIFY_RULE_OPCODE_MAC, + &rule_entry->mac.header); + + /* Set a MAC itself */ + bnx2x_set_fw_mac_addr(&rule_entry->mac.mac_msb, + &rule_entry->mac.mac_mid, + &rule_entry->mac.mac_lsb, mac); + } + + /* Set the ramrod data header */ + /* TODO: take this to the higher level in order to prevent multiple + writing */ + bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header, + rule_cnt); +} + +/** + * bnx2x_vlan_mac_set_rdata_hdr_e1x - set a header in a single classify ramrod + * + * @bp: device handle + * @o: queue + * @type: + * @cam_offset: offset in cam memory + * @hdr: pointer to a header to setup + * + * E1/E1H + */ +static inline void bnx2x_vlan_mac_set_rdata_hdr_e1x(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, int type, int cam_offset, + struct mac_configuration_hdr *hdr) +{ + struct bnx2x_raw_obj *r = &o->raw; + + hdr->length = 1; + hdr->offset = (u8)cam_offset; + hdr->client_id = 0xff; + hdr->echo = ((r->cid & BNX2X_SWCID_MASK) | (type << BNX2X_SWCID_SHIFT)); +} + +static inline void bnx2x_vlan_mac_set_cfg_entry_e1x(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, bool add, int opcode, u8 *mac, + u16 vlan_id, struct mac_configuration_entry *cfg_entry) +{ + struct bnx2x_raw_obj *r = &o->raw; + u32 cl_bit_vec = (1 << r->cl_id); + + cfg_entry->clients_bit_vector = cpu_to_le32(cl_bit_vec); + cfg_entry->pf_id = r->func_id; + cfg_entry->vlan_id = cpu_to_le16(vlan_id); + + if (add) { + SET_FLAG(cfg_entry->flags, MAC_CONFIGURATION_ENTRY_ACTION_TYPE, + T_ETH_MAC_COMMAND_SET); + SET_FLAG(cfg_entry->flags, + MAC_CONFIGURATION_ENTRY_VLAN_FILTERING_MODE, opcode); + + /* Set a MAC in a ramrod data */ + bnx2x_set_fw_mac_addr(&cfg_entry->msb_mac_addr, + &cfg_entry->middle_mac_addr, + &cfg_entry->lsb_mac_addr, mac); + } else + SET_FLAG(cfg_entry->flags, MAC_CONFIGURATION_ENTRY_ACTION_TYPE, + T_ETH_MAC_COMMAND_INVALIDATE); +} + +static inline void bnx2x_vlan_mac_set_rdata_e1x(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, int type, int cam_offset, bool add, + u8 *mac, u16 vlan_id, int opcode, struct mac_configuration_cmd *config) +{ + struct mac_configuration_entry *cfg_entry = &config->config_table[0]; + struct bnx2x_raw_obj *raw = &o->raw; + + bnx2x_vlan_mac_set_rdata_hdr_e1x(bp, o, type, cam_offset, + &config->hdr); + bnx2x_vlan_mac_set_cfg_entry_e1x(bp, o, add, opcode, mac, vlan_id, + cfg_entry); + + DP(BNX2X_MSG_SP, "%s MAC "BNX2X_MAC_FMT" CLID %d CAM offset %d\n", + (add ? "setting" : "clearing"), + BNX2X_MAC_PRN_LIST(mac), raw->cl_id, cam_offset); +} + +/** + * bnx2x_set_one_mac_e1x - fill a single MAC rule ramrod data + * + * @bp: device handle + * @o: bnx2x_vlan_mac_obj + * @elem: bnx2x_exeq_elem + * @rule_idx: rule_idx + * @cam_offset: cam_offset + */ +static void bnx2x_set_one_mac_e1x(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + struct bnx2x_exeq_elem *elem, int rule_idx, + int cam_offset) +{ + struct bnx2x_raw_obj *raw = &o->raw; + struct mac_configuration_cmd *config = + (struct mac_configuration_cmd *)(raw->rdata); + /* + * 57710 and 57711 do not support MOVE command, + * so it's either ADD or DEL + */ + bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ? + true : false; + + /* Reset the ramrod data buffer */ + memset(config, 0, sizeof(*config)); + + bnx2x_vlan_mac_set_rdata_e1x(bp, o, BNX2X_FILTER_MAC_PENDING, + cam_offset, add, + elem->cmd_data.vlan_mac.u.mac.mac, 0, + ETH_VLAN_FILTER_ANY_VLAN, config); +} + +static void bnx2x_set_one_vlan_e2(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + struct bnx2x_exeq_elem *elem, int rule_idx, + int cam_offset) +{ + struct bnx2x_raw_obj *raw = &o->raw; + struct eth_classify_rules_ramrod_data *data = + (struct eth_classify_rules_ramrod_data *)(raw->rdata); + int rule_cnt = rule_idx + 1; + union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx]; + int cmd = elem->cmd_data.vlan_mac.cmd; + bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false; + u16 vlan = elem->cmd_data.vlan_mac.u.vlan.vlan; + + /* Reset the ramrod data buffer for the first rule */ + if (rule_idx == 0) + memset(data, 0, sizeof(*data)); + + /* Set a rule header */ + bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_VLAN, + &rule_entry->vlan.header); + + DP(BNX2X_MSG_SP, "About to %s VLAN %d\n", (add ? "add" : "delete"), + vlan); + + /* Set a VLAN itself */ + rule_entry->vlan.vlan = cpu_to_le16(vlan); + + /* MOVE: Add a rule that will add this MAC to the target Queue */ + if (cmd == BNX2X_VLAN_MAC_MOVE) { + rule_entry++; + rule_cnt++; + + /* Setup ramrod data */ + bnx2x_vlan_mac_set_cmd_hdr_e2(bp, + elem->cmd_data.vlan_mac.target_obj, + true, CLASSIFY_RULE_OPCODE_VLAN, + &rule_entry->vlan.header); + + /* Set a VLAN itself */ + rule_entry->vlan.vlan = cpu_to_le16(vlan); + } + + /* Set the ramrod data header */ + /* TODO: take this to the higher level in order to prevent multiple + writing */ + bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header, + rule_cnt); +} + +static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + struct bnx2x_exeq_elem *elem, + int rule_idx, int cam_offset) +{ + struct bnx2x_raw_obj *raw = &o->raw; + struct eth_classify_rules_ramrod_data *data = + (struct eth_classify_rules_ramrod_data *)(raw->rdata); + int rule_cnt = rule_idx + 1; + union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx]; + int cmd = elem->cmd_data.vlan_mac.cmd; + bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false; + u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan; + u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac; + + + /* Reset the ramrod data buffer for the first rule */ + if (rule_idx == 0) + memset(data, 0, sizeof(*data)); + + /* Set a rule header */ + bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_PAIR, + &rule_entry->pair.header); + + /* Set VLAN and MAC themselvs */ + rule_entry->pair.vlan = cpu_to_le16(vlan); + bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb, + &rule_entry->pair.mac_mid, + &rule_entry->pair.mac_lsb, mac); + + /* MOVE: Add a rule that will add this MAC to the target Queue */ + if (cmd == BNX2X_VLAN_MAC_MOVE) { + rule_entry++; + rule_cnt++; + + /* Setup ramrod data */ + bnx2x_vlan_mac_set_cmd_hdr_e2(bp, + elem->cmd_data.vlan_mac.target_obj, + true, CLASSIFY_RULE_OPCODE_PAIR, + &rule_entry->pair.header); + + /* Set a VLAN itself */ + rule_entry->pair.vlan = cpu_to_le16(vlan); + bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb, + &rule_entry->pair.mac_mid, + &rule_entry->pair.mac_lsb, mac); + } + + /* Set the ramrod data header */ + /* TODO: take this to the higher level in order to prevent multiple + writing */ + bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header, + rule_cnt); +} + +/** + * bnx2x_set_one_vlan_mac_e1h - + * + * @bp: device handle + * @o: bnx2x_vlan_mac_obj + * @elem: bnx2x_exeq_elem + * @rule_idx: rule_idx + * @cam_offset: cam_offset + */ +static void bnx2x_set_one_vlan_mac_e1h(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + struct bnx2x_exeq_elem *elem, + int rule_idx, int cam_offset) +{ + struct bnx2x_raw_obj *raw = &o->raw; + struct mac_configuration_cmd *config = + (struct mac_configuration_cmd *)(raw->rdata); + /* + * 57710 and 57711 do not support MOVE command, + * so it's either ADD or DEL + */ + bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ? + true : false; + + /* Reset the ramrod data buffer */ + memset(config, 0, sizeof(*config)); + + bnx2x_vlan_mac_set_rdata_e1x(bp, o, BNX2X_FILTER_VLAN_MAC_PENDING, + cam_offset, add, + elem->cmd_data.vlan_mac.u.vlan_mac.mac, + elem->cmd_data.vlan_mac.u.vlan_mac.vlan, + ETH_VLAN_FILTER_CLASSIFY, config); +} + +#define list_next_entry(pos, member) \ + list_entry((pos)->member.next, typeof(*(pos)), member) + +/** + * bnx2x_vlan_mac_restore - reconfigure next MAC/VLAN/VLAN-MAC element + * + * @bp: device handle + * @p: command parameters + * @ppos: pointer to the cooky + * + * reconfigure next MAC/VLAN/VLAN-MAC element from the + * previously configured elements list. + * + * from command parameters only RAMROD_COMP_WAIT bit in ramrod_flags is taken + * into an account + * + * pointer to the cooky - that should be given back in the next call to make + * function handle the next element. If *ppos is set to NULL it will restart the + * iterator. If returned *ppos == NULL this means that the last element has been + * handled. + * + */ +static int bnx2x_vlan_mac_restore(struct bnx2x *bp, + struct bnx2x_vlan_mac_ramrod_params *p, + struct bnx2x_vlan_mac_registry_elem **ppos) +{ + struct bnx2x_vlan_mac_registry_elem *pos; + struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj; + + /* If list is empty - there is nothing to do here */ + if (list_empty(&o->head)) { + *ppos = NULL; + return 0; + } + + /* make a step... */ + if (*ppos == NULL) + *ppos = list_first_entry(&o->head, + struct bnx2x_vlan_mac_registry_elem, + link); + else + *ppos = list_next_entry(*ppos, link); + + pos = *ppos; + + /* If it's the last step - return NULL */ + if (list_is_last(&pos->link, &o->head)) + *ppos = NULL; + + /* Prepare a 'user_req' */ + memcpy(&p->user_req.u, &pos->u, sizeof(pos->u)); + + /* Set the command */ + p->user_req.cmd = BNX2X_VLAN_MAC_ADD; + + /* Set vlan_mac_flags */ + p->user_req.vlan_mac_flags = pos->vlan_mac_flags; + + /* Set a restore bit */ + __set_bit(RAMROD_RESTORE, &p->ramrod_flags); + + return bnx2x_config_vlan_mac(bp, p); +} + +/* + * bnx2x_exeq_get_mac/bnx2x_exeq_get_vlan/bnx2x_exeq_get_vlan_mac return a + * pointer to an element with a specific criteria and NULL if such an element + * hasn't been found. + */ +static struct bnx2x_exeq_elem *bnx2x_exeq_get_mac( + struct bnx2x_exe_queue_obj *o, + struct bnx2x_exeq_elem *elem) +{ + struct bnx2x_exeq_elem *pos; + struct bnx2x_mac_ramrod_data *data = &elem->cmd_data.vlan_mac.u.mac; + + /* Check pending for execution commands */ + list_for_each_entry(pos, &o->exe_queue, link) + if (!memcmp(&pos->cmd_data.vlan_mac.u.mac, data, + sizeof(*data)) && + (pos->cmd_data.vlan_mac.cmd == elem->cmd_data.vlan_mac.cmd)) + return pos; + + return NULL; +} + +static struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan( + struct bnx2x_exe_queue_obj *o, + struct bnx2x_exeq_elem *elem) +{ + struct bnx2x_exeq_elem *pos; + struct bnx2x_vlan_ramrod_data *data = &elem->cmd_data.vlan_mac.u.vlan; + + /* Check pending for execution commands */ + list_for_each_entry(pos, &o->exe_queue, link) + if (!memcmp(&pos->cmd_data.vlan_mac.u.vlan, data, + sizeof(*data)) && + (pos->cmd_data.vlan_mac.cmd == elem->cmd_data.vlan_mac.cmd)) + return pos; + + return NULL; +} + +static struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan_mac( + struct bnx2x_exe_queue_obj *o, + struct bnx2x_exeq_elem *elem) +{ + struct bnx2x_exeq_elem *pos; + struct bnx2x_vlan_mac_ramrod_data *data = + &elem->cmd_data.vlan_mac.u.vlan_mac; + + /* Check pending for execution commands */ + list_for_each_entry(pos, &o->exe_queue, link) + if (!memcmp(&pos->cmd_data.vlan_mac.u.vlan_mac, data, + sizeof(*data)) && + (pos->cmd_data.vlan_mac.cmd == elem->cmd_data.vlan_mac.cmd)) + return pos; + + return NULL; +} + +/** + * bnx2x_validate_vlan_mac_add - check if an ADD command can be executed + * + * @bp: device handle + * @qo: bnx2x_qable_obj + * @elem: bnx2x_exeq_elem + * + * Checks that the requested configuration can be added. If yes and if + * requested, consume CAM credit. + * + * The 'validate' is run after the 'optimize'. + * + */ +static inline int bnx2x_validate_vlan_mac_add(struct bnx2x *bp, + union bnx2x_qable_obj *qo, + struct bnx2x_exeq_elem *elem) +{ + struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac; + struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; + int rc; + + /* Check the registry */ + rc = o->check_add(o, &elem->cmd_data.vlan_mac.u); + if (rc) { + DP(BNX2X_MSG_SP, "ADD command is not allowed considering " + "current registry state\n"); + return rc; + } + + /* + * Check if there is a pending ADD command for this + * MAC/VLAN/VLAN-MAC. Return an error if there is. + */ + if (exeq->get(exeq, elem)) { + DP(BNX2X_MSG_SP, "There is a pending ADD command already\n"); + return -EEXIST; + } + + /* + * TODO: Check the pending MOVE from other objects where this + * object is a destination object. + */ + + /* Consume the credit if not requested not to */ + if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, + &elem->cmd_data.vlan_mac.vlan_mac_flags) || + o->get_credit(o))) + return -EINVAL; + + return 0; +} + +/** + * bnx2x_validate_vlan_mac_del - check if the DEL command can be executed + * + * @bp: device handle + * @qo: quable object to check + * @elem: element that needs to be deleted + * + * Checks that the requested configuration can be deleted. If yes and if + * requested, returns a CAM credit. + * + * The 'validate' is run after the 'optimize'. + */ +static inline int bnx2x_validate_vlan_mac_del(struct bnx2x *bp, + union bnx2x_qable_obj *qo, + struct bnx2x_exeq_elem *elem) +{ + struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac; + struct bnx2x_vlan_mac_registry_elem *pos; + struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; + struct bnx2x_exeq_elem query_elem; + + /* If this classification can not be deleted (doesn't exist) + * - return a BNX2X_EXIST. + */ + pos = o->check_del(o, &elem->cmd_data.vlan_mac.u); + if (!pos) { + DP(BNX2X_MSG_SP, "DEL command is not allowed considering " + "current registry state\n"); + return -EEXIST; + } + + /* + * Check if there are pending DEL or MOVE commands for this + * MAC/VLAN/VLAN-MAC. Return an error if so. + */ + memcpy(&query_elem, elem, sizeof(query_elem)); + + /* Check for MOVE commands */ + query_elem.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_MOVE; + if (exeq->get(exeq, &query_elem)) { + BNX2X_ERR("There is a pending MOVE command already\n"); + return -EINVAL; + } + + /* Check for DEL commands */ + if (exeq->get(exeq, elem)) { + DP(BNX2X_MSG_SP, "There is a pending DEL command already\n"); + return -EEXIST; + } + + /* Return the credit to the credit pool if not requested not to */ + if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, + &elem->cmd_data.vlan_mac.vlan_mac_flags) || + o->put_credit(o))) { + BNX2X_ERR("Failed to return a credit\n"); + return -EINVAL; + } + + return 0; +} + +/** + * bnx2x_validate_vlan_mac_move - check if the MOVE command can be executed + * + * @bp: device handle + * @qo: quable object to check (source) + * @elem: element that needs to be moved + * + * Checks that the requested configuration can be moved. If yes and if + * requested, returns a CAM credit. + * + * The 'validate' is run after the 'optimize'. + */ +static inline int bnx2x_validate_vlan_mac_move(struct bnx2x *bp, + union bnx2x_qable_obj *qo, + struct bnx2x_exeq_elem *elem) +{ + struct bnx2x_vlan_mac_obj *src_o = &qo->vlan_mac; + struct bnx2x_vlan_mac_obj *dest_o = elem->cmd_data.vlan_mac.target_obj; + struct bnx2x_exeq_elem query_elem; + struct bnx2x_exe_queue_obj *src_exeq = &src_o->exe_queue; + struct bnx2x_exe_queue_obj *dest_exeq = &dest_o->exe_queue; + + /* + * Check if we can perform this operation based on the current registry + * state. + */ + if (!src_o->check_move(src_o, dest_o, &elem->cmd_data.vlan_mac.u)) { + DP(BNX2X_MSG_SP, "MOVE command is not allowed considering " + "current registry state\n"); + return -EINVAL; + } + + /* + * Check if there is an already pending DEL or MOVE command for the + * source object or ADD command for a destination object. Return an + * error if so. + */ + memcpy(&query_elem, elem, sizeof(query_elem)); + + /* Check DEL on source */ + query_elem.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_DEL; + if (src_exeq->get(src_exeq, &query_elem)) { + BNX2X_ERR("There is a pending DEL command on the source " + "queue already\n"); + return -EINVAL; + } + + /* Check MOVE on source */ + if (src_exeq->get(src_exeq, elem)) { + DP(BNX2X_MSG_SP, "There is a pending MOVE command already\n"); + return -EEXIST; + } + + /* Check ADD on destination */ + query_elem.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_ADD; + if (dest_exeq->get(dest_exeq, &query_elem)) { + BNX2X_ERR("There is a pending ADD command on the " + "destination queue already\n"); + return -EINVAL; + } + + /* Consume the credit if not requested not to */ + if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT_DEST, + &elem->cmd_data.vlan_mac.vlan_mac_flags) || + dest_o->get_credit(dest_o))) + return -EINVAL; + + if (!(test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, + &elem->cmd_data.vlan_mac.vlan_mac_flags) || + src_o->put_credit(src_o))) { + /* return the credit taken from dest... */ + dest_o->put_credit(dest_o); + return -EINVAL; + } + + return 0; +} + +static int bnx2x_validate_vlan_mac(struct bnx2x *bp, + union bnx2x_qable_obj *qo, + struct bnx2x_exeq_elem *elem) +{ + switch (elem->cmd_data.vlan_mac.cmd) { + case BNX2X_VLAN_MAC_ADD: + return bnx2x_validate_vlan_mac_add(bp, qo, elem); + case BNX2X_VLAN_MAC_DEL: + return bnx2x_validate_vlan_mac_del(bp, qo, elem); + case BNX2X_VLAN_MAC_MOVE: + return bnx2x_validate_vlan_mac_move(bp, qo, elem); + default: + return -EINVAL; + } +} + +/** + * bnx2x_wait_vlan_mac - passivly wait for 5 seconds until all work completes. + * + * @bp: device handle + * @o: bnx2x_vlan_mac_obj + * + */ +static int bnx2x_wait_vlan_mac(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o) +{ + int cnt = 5000, rc; + struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; + struct bnx2x_raw_obj *raw = &o->raw; + + while (cnt--) { + /* Wait for the current command to complete */ + rc = raw->wait_comp(bp, raw); + if (rc) + return rc; + + /* Wait until there are no pending commands */ + if (!bnx2x_exe_queue_empty(exeq)) + usleep_range(1000, 1000); + else + return 0; + } + + return -EBUSY; +} + +/** + * bnx2x_complete_vlan_mac - complete one VLAN-MAC ramrod + * + * @bp: device handle + * @o: bnx2x_vlan_mac_obj + * @cqe: + * @cont: if true schedule next execution chunk + * + */ +static int bnx2x_complete_vlan_mac(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + union event_ring_elem *cqe, + unsigned long *ramrod_flags) +{ + struct bnx2x_raw_obj *r = &o->raw; + int rc; + + /* Reset pending list */ + bnx2x_exe_queue_reset_pending(bp, &o->exe_queue); + + /* Clear pending */ + r->clear_pending(r); + + /* If ramrod failed this is most likely a SW bug */ + if (cqe->message.error) + return -EINVAL; + + /* Run the next bulk of pending commands if requeted */ + if (test_bit(RAMROD_CONT, ramrod_flags)) { + rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags); + if (rc < 0) + return rc; + } + + /* If there is more work to do return PENDING */ + if (!bnx2x_exe_queue_empty(&o->exe_queue)) + return 1; + + return 0; +} + +/** + * bnx2x_optimize_vlan_mac - optimize ADD and DEL commands. + * + * @bp: device handle + * @o: bnx2x_qable_obj + * @elem: bnx2x_exeq_elem + */ +static int bnx2x_optimize_vlan_mac(struct bnx2x *bp, + union bnx2x_qable_obj *qo, + struct bnx2x_exeq_elem *elem) +{ + struct bnx2x_exeq_elem query, *pos; + struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac; + struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; + + memcpy(&query, elem, sizeof(query)); + + switch (elem->cmd_data.vlan_mac.cmd) { + case BNX2X_VLAN_MAC_ADD: + query.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_DEL; + break; + case BNX2X_VLAN_MAC_DEL: + query.cmd_data.vlan_mac.cmd = BNX2X_VLAN_MAC_ADD; + break; + default: + /* Don't handle anything other than ADD or DEL */ + return 0; + } + + /* If we found the appropriate element - delete it */ + pos = exeq->get(exeq, &query); + if (pos) { + + /* Return the credit of the optimized command */ + if (!test_bit(BNX2X_DONT_CONSUME_CAM_CREDIT, + &pos->cmd_data.vlan_mac.vlan_mac_flags)) { + if ((query.cmd_data.vlan_mac.cmd == + BNX2X_VLAN_MAC_ADD) && !o->put_credit(o)) { + BNX2X_ERR("Failed to return the credit for the " + "optimized ADD command\n"); + return -EINVAL; + } else if (!o->get_credit(o)) { /* VLAN_MAC_DEL */ + BNX2X_ERR("Failed to recover the credit from " + "the optimized DEL command\n"); + return -EINVAL; + } + } + + DP(BNX2X_MSG_SP, "Optimizing %s command\n", + (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ? + "ADD" : "DEL"); + + list_del(&pos->link); + bnx2x_exe_queue_free_elem(bp, pos); + return 1; + } + + return 0; +} + +/** + * bnx2x_vlan_mac_get_registry_elem - prepare a registry element + * + * @bp: device handle + * @o: + * @elem: + * @restore: + * @re: + * + * prepare a registry element according to the current command request. + */ +static inline int bnx2x_vlan_mac_get_registry_elem( + struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + struct bnx2x_exeq_elem *elem, + bool restore, + struct bnx2x_vlan_mac_registry_elem **re) +{ + int cmd = elem->cmd_data.vlan_mac.cmd; + struct bnx2x_vlan_mac_registry_elem *reg_elem; + + /* Allocate a new registry element if needed. */ + if (!restore && + ((cmd == BNX2X_VLAN_MAC_ADD) || (cmd == BNX2X_VLAN_MAC_MOVE))) { + reg_elem = kzalloc(sizeof(*reg_elem), GFP_ATOMIC); + if (!reg_elem) + return -ENOMEM; + + /* Get a new CAM offset */ + if (!o->get_cam_offset(o, ®_elem->cam_offset)) { + /* + * This shell never happen, because we have checked the + * CAM availiability in the 'validate'. + */ + WARN_ON(1); + kfree(reg_elem); + return -EINVAL; + } + + DP(BNX2X_MSG_SP, "Got cam offset %d\n", reg_elem->cam_offset); + + /* Set a VLAN-MAC data */ + memcpy(®_elem->u, &elem->cmd_data.vlan_mac.u, + sizeof(reg_elem->u)); + + /* Copy the flags (needed for DEL and RESTORE flows) */ + reg_elem->vlan_mac_flags = + elem->cmd_data.vlan_mac.vlan_mac_flags; + } else /* DEL, RESTORE */ + reg_elem = o->check_del(o, &elem->cmd_data.vlan_mac.u); + + *re = reg_elem; + return 0; +} + +/** + * bnx2x_execute_vlan_mac - execute vlan mac command + * + * @bp: device handle + * @qo: + * @exe_chunk: + * @ramrod_flags: + * + * go and send a ramrod! + */ +static int bnx2x_execute_vlan_mac(struct bnx2x *bp, + union bnx2x_qable_obj *qo, + struct list_head *exe_chunk, + unsigned long *ramrod_flags) +{ + struct bnx2x_exeq_elem *elem; + struct bnx2x_vlan_mac_obj *o = &qo->vlan_mac, *cam_obj; + struct bnx2x_raw_obj *r = &o->raw; + int rc, idx = 0; + bool restore = test_bit(RAMROD_RESTORE, ramrod_flags); + bool drv_only = test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags); + struct bnx2x_vlan_mac_registry_elem *reg_elem; + int cmd; + + /* + * If DRIVER_ONLY execution is requested, cleanup a registry + * and exit. Otherwise send a ramrod to FW. + */ + if (!drv_only) { + WARN_ON(r->check_pending(r)); + + /* Set pending */ + r->set_pending(r); + + /* Fill tha ramrod data */ + list_for_each_entry(elem, exe_chunk, link) { + cmd = elem->cmd_data.vlan_mac.cmd; + /* + * We will add to the target object in MOVE command, so + * change the object for a CAM search. + */ + if (cmd == BNX2X_VLAN_MAC_MOVE) + cam_obj = elem->cmd_data.vlan_mac.target_obj; + else + cam_obj = o; + + rc = bnx2x_vlan_mac_get_registry_elem(bp, cam_obj, + elem, restore, + ®_elem); + if (rc) + goto error_exit; + + WARN_ON(!reg_elem); + + /* Push a new entry into the registry */ + if (!restore && + ((cmd == BNX2X_VLAN_MAC_ADD) || + (cmd == BNX2X_VLAN_MAC_MOVE))) + list_add(®_elem->link, &cam_obj->head); + + /* Configure a single command in a ramrod data buffer */ + o->set_one_rule(bp, o, elem, idx, + reg_elem->cam_offset); + + /* MOVE command consumes 2 entries in the ramrod data */ + if (cmd == BNX2X_VLAN_MAC_MOVE) + idx += 2; + else + idx++; + } + + /* + * No need for an explicit memory barrier here as long we would + * need to ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read and we will have to put a full memory barrier there + * (inside bnx2x_sp_post()). + */ + + rc = bnx2x_sp_post(bp, o->ramrod_cmd, r->cid, + U64_HI(r->rdata_mapping), + U64_LO(r->rdata_mapping), + ETH_CONNECTION_TYPE); + if (rc) + goto error_exit; + } + + /* Now, when we are done with the ramrod - clean up the registry */ + list_for_each_entry(elem, exe_chunk, link) { + cmd = elem->cmd_data.vlan_mac.cmd; + if ((cmd == BNX2X_VLAN_MAC_DEL) || + (cmd == BNX2X_VLAN_MAC_MOVE)) { + reg_elem = o->check_del(o, &elem->cmd_data.vlan_mac.u); + + WARN_ON(!reg_elem); + + o->put_cam_offset(o, reg_elem->cam_offset); + list_del(®_elem->link); + kfree(reg_elem); + } + } + + if (!drv_only) + return 1; + else + return 0; + +error_exit: + r->clear_pending(r); + + /* Cleanup a registry in case of a failure */ + list_for_each_entry(elem, exe_chunk, link) { + cmd = elem->cmd_data.vlan_mac.cmd; + + if (cmd == BNX2X_VLAN_MAC_MOVE) + cam_obj = elem->cmd_data.vlan_mac.target_obj; + else + cam_obj = o; + + /* Delete all newly added above entries */ + if (!restore && + ((cmd == BNX2X_VLAN_MAC_ADD) || + (cmd == BNX2X_VLAN_MAC_MOVE))) { + reg_elem = o->check_del(cam_obj, + &elem->cmd_data.vlan_mac.u); + if (reg_elem) { + list_del(®_elem->link); + kfree(reg_elem); + } + } + } + + return rc; +} + +static inline int bnx2x_vlan_mac_push_new_cmd( + struct bnx2x *bp, + struct bnx2x_vlan_mac_ramrod_params *p) +{ + struct bnx2x_exeq_elem *elem; + struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj; + bool restore = test_bit(RAMROD_RESTORE, &p->ramrod_flags); + + /* Allocate the execution queue element */ + elem = bnx2x_exe_queue_alloc_elem(bp); + if (!elem) + return -ENOMEM; + + /* Set the command 'length' */ + switch (p->user_req.cmd) { + case BNX2X_VLAN_MAC_MOVE: + elem->cmd_len = 2; + break; + default: + elem->cmd_len = 1; + } + + /* Fill the object specific info */ + memcpy(&elem->cmd_data.vlan_mac, &p->user_req, sizeof(p->user_req)); + + /* Try to add a new command to the pending list */ + return bnx2x_exe_queue_add(bp, &o->exe_queue, elem, restore); +} + +/** + * bnx2x_config_vlan_mac - configure VLAN/MAC/VLAN_MAC filtering rules. + * + * @bp: device handle + * @p: + * + */ +int bnx2x_config_vlan_mac( + struct bnx2x *bp, + struct bnx2x_vlan_mac_ramrod_params *p) +{ + int rc = 0; + struct bnx2x_vlan_mac_obj *o = p->vlan_mac_obj; + unsigned long *ramrod_flags = &p->ramrod_flags; + bool cont = test_bit(RAMROD_CONT, ramrod_flags); + struct bnx2x_raw_obj *raw = &o->raw; + + /* + * Add new elements to the execution list for commands that require it. + */ + if (!cont) { + rc = bnx2x_vlan_mac_push_new_cmd(bp, p); + if (rc) + return rc; + } + + /* + * If nothing will be executed further in this iteration we want to + * return PENDING if there are pending commands + */ + if (!bnx2x_exe_queue_empty(&o->exe_queue)) + rc = 1; + + if (test_bit(RAMROD_DRV_CLR_ONLY, ramrod_flags)) { + DP(BNX2X_MSG_SP, "RAMROD_DRV_CLR_ONLY requested: " + "clearing a pending bit.\n"); + raw->clear_pending(raw); + } + + /* Execute commands if required */ + if (cont || test_bit(RAMROD_EXEC, ramrod_flags) || + test_bit(RAMROD_COMP_WAIT, ramrod_flags)) { + rc = bnx2x_exe_queue_step(bp, &o->exe_queue, ramrod_flags); + if (rc < 0) + return rc; + } + + /* + * RAMROD_COMP_WAIT is a superset of RAMROD_EXEC. If it was set + * then user want to wait until the last command is done. + */ + if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags)) { + /* + * Wait maximum for the current exe_queue length iterations plus + * one (for the current pending command). + */ + int max_iterations = bnx2x_exe_queue_length(&o->exe_queue) + 1; + + while (!bnx2x_exe_queue_empty(&o->exe_queue) && + max_iterations--) { + + /* Wait for the current command to complete */ + rc = raw->wait_comp(bp, raw); + if (rc) + return rc; + + /* Make a next step */ + rc = bnx2x_exe_queue_step(bp, &o->exe_queue, + ramrod_flags); + if (rc < 0) + return rc; + } + + return 0; + } + + return rc; +} + + + +/** + * bnx2x_vlan_mac_del_all - delete elements with given vlan_mac_flags spec + * + * @bp: device handle + * @o: + * @vlan_mac_flags: + * @ramrod_flags: execution flags to be used for this deletion + * + * if the last operation has completed successfully and there are no + * moreelements left, positive value if the last operation has completed + * successfully and there are more previously configured elements, negative + * value is current operation has failed. + */ +static int bnx2x_vlan_mac_del_all(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + unsigned long *vlan_mac_flags, + unsigned long *ramrod_flags) +{ + struct bnx2x_vlan_mac_registry_elem *pos = NULL; + int rc = 0; + struct bnx2x_vlan_mac_ramrod_params p; + struct bnx2x_exe_queue_obj *exeq = &o->exe_queue; + struct bnx2x_exeq_elem *exeq_pos, *exeq_pos_n; + + /* Clear pending commands first */ + + spin_lock_bh(&exeq->lock); + + list_for_each_entry_safe(exeq_pos, exeq_pos_n, &exeq->exe_queue, link) { + if (exeq_pos->cmd_data.vlan_mac.vlan_mac_flags == + *vlan_mac_flags) + list_del(&exeq_pos->link); + } + + spin_unlock_bh(&exeq->lock); + + /* Prepare a command request */ + memset(&p, 0, sizeof(p)); + p.vlan_mac_obj = o; + p.ramrod_flags = *ramrod_flags; + p.user_req.cmd = BNX2X_VLAN_MAC_DEL; + + /* + * Add all but the last VLAN-MAC to the execution queue without actually + * execution anything. + */ + __clear_bit(RAMROD_COMP_WAIT, &p.ramrod_flags); + __clear_bit(RAMROD_EXEC, &p.ramrod_flags); + __clear_bit(RAMROD_CONT, &p.ramrod_flags); + + list_for_each_entry(pos, &o->head, link) { + if (pos->vlan_mac_flags == *vlan_mac_flags) { + p.user_req.vlan_mac_flags = pos->vlan_mac_flags; + memcpy(&p.user_req.u, &pos->u, sizeof(pos->u)); + rc = bnx2x_config_vlan_mac(bp, &p); + if (rc < 0) { + BNX2X_ERR("Failed to add a new DEL command\n"); + return rc; + } + } + } + + p.ramrod_flags = *ramrod_flags; + __set_bit(RAMROD_CONT, &p.ramrod_flags); + + return bnx2x_config_vlan_mac(bp, &p); +} + +static inline void bnx2x_init_raw_obj(struct bnx2x_raw_obj *raw, u8 cl_id, + u32 cid, u8 func_id, void *rdata, dma_addr_t rdata_mapping, int state, + unsigned long *pstate, bnx2x_obj_type type) +{ + raw->func_id = func_id; + raw->cid = cid; + raw->cl_id = cl_id; + raw->rdata = rdata; + raw->rdata_mapping = rdata_mapping; + raw->state = state; + raw->pstate = pstate; + raw->obj_type = type; + raw->check_pending = bnx2x_raw_check_pending; + raw->clear_pending = bnx2x_raw_clear_pending; + raw->set_pending = bnx2x_raw_set_pending; + raw->wait_comp = bnx2x_raw_wait; +} + +static inline void bnx2x_init_vlan_mac_common(struct bnx2x_vlan_mac_obj *o, + u8 cl_id, u32 cid, u8 func_id, void *rdata, dma_addr_t rdata_mapping, + int state, unsigned long *pstate, bnx2x_obj_type type, + struct bnx2x_credit_pool_obj *macs_pool, + struct bnx2x_credit_pool_obj *vlans_pool) +{ + INIT_LIST_HEAD(&o->head); + + o->macs_pool = macs_pool; + o->vlans_pool = vlans_pool; + + o->delete_all = bnx2x_vlan_mac_del_all; + o->restore = bnx2x_vlan_mac_restore; + o->complete = bnx2x_complete_vlan_mac; + o->wait = bnx2x_wait_vlan_mac; + + bnx2x_init_raw_obj(&o->raw, cl_id, cid, func_id, rdata, rdata_mapping, + state, pstate, type); +} + + +void bnx2x_init_mac_obj(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *mac_obj, + u8 cl_id, u32 cid, u8 func_id, void *rdata, + dma_addr_t rdata_mapping, int state, + unsigned long *pstate, bnx2x_obj_type type, + struct bnx2x_credit_pool_obj *macs_pool) +{ + union bnx2x_qable_obj *qable_obj = (union bnx2x_qable_obj *)mac_obj; + + bnx2x_init_vlan_mac_common(mac_obj, cl_id, cid, func_id, rdata, + rdata_mapping, state, pstate, type, + macs_pool, NULL); + + /* CAM credit pool handling */ + mac_obj->get_credit = bnx2x_get_credit_mac; + mac_obj->put_credit = bnx2x_put_credit_mac; + mac_obj->get_cam_offset = bnx2x_get_cam_offset_mac; + mac_obj->put_cam_offset = bnx2x_put_cam_offset_mac; + + if (CHIP_IS_E1x(bp)) { + mac_obj->set_one_rule = bnx2x_set_one_mac_e1x; + mac_obj->check_del = bnx2x_check_mac_del; + mac_obj->check_add = bnx2x_check_mac_add; + mac_obj->check_move = bnx2x_check_move_always_err; + mac_obj->ramrod_cmd = RAMROD_CMD_ID_ETH_SET_MAC; + + /* Exe Queue */ + bnx2x_exe_queue_init(bp, + &mac_obj->exe_queue, 1, qable_obj, + bnx2x_validate_vlan_mac, + bnx2x_optimize_vlan_mac, + bnx2x_execute_vlan_mac, + bnx2x_exeq_get_mac); + } else { + mac_obj->set_one_rule = bnx2x_set_one_mac_e2; + mac_obj->check_del = bnx2x_check_mac_del; + mac_obj->check_add = bnx2x_check_mac_add; + mac_obj->check_move = bnx2x_check_move; + mac_obj->ramrod_cmd = + RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES; + + /* Exe Queue */ + bnx2x_exe_queue_init(bp, + &mac_obj->exe_queue, CLASSIFY_RULES_COUNT, + qable_obj, bnx2x_validate_vlan_mac, + bnx2x_optimize_vlan_mac, + bnx2x_execute_vlan_mac, + bnx2x_exeq_get_mac); + } +} + +void bnx2x_init_vlan_obj(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *vlan_obj, + u8 cl_id, u32 cid, u8 func_id, void *rdata, + dma_addr_t rdata_mapping, int state, + unsigned long *pstate, bnx2x_obj_type type, + struct bnx2x_credit_pool_obj *vlans_pool) +{ + union bnx2x_qable_obj *qable_obj = (union bnx2x_qable_obj *)vlan_obj; + + bnx2x_init_vlan_mac_common(vlan_obj, cl_id, cid, func_id, rdata, + rdata_mapping, state, pstate, type, NULL, + vlans_pool); + + vlan_obj->get_credit = bnx2x_get_credit_vlan; + vlan_obj->put_credit = bnx2x_put_credit_vlan; + vlan_obj->get_cam_offset = bnx2x_get_cam_offset_vlan; + vlan_obj->put_cam_offset = bnx2x_put_cam_offset_vlan; + + if (CHIP_IS_E1x(bp)) { + BNX2X_ERR("Do not support chips others than E2 and newer\n"); + BUG(); + } else { + vlan_obj->set_one_rule = bnx2x_set_one_vlan_e2; + vlan_obj->check_del = bnx2x_check_vlan_del; + vlan_obj->check_add = bnx2x_check_vlan_add; + vlan_obj->check_move = bnx2x_check_move; + vlan_obj->ramrod_cmd = + RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES; + + /* Exe Queue */ + bnx2x_exe_queue_init(bp, + &vlan_obj->exe_queue, CLASSIFY_RULES_COUNT, + qable_obj, bnx2x_validate_vlan_mac, + bnx2x_optimize_vlan_mac, + bnx2x_execute_vlan_mac, + bnx2x_exeq_get_vlan); + } +} + +void bnx2x_init_vlan_mac_obj(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *vlan_mac_obj, + u8 cl_id, u32 cid, u8 func_id, void *rdata, + dma_addr_t rdata_mapping, int state, + unsigned long *pstate, bnx2x_obj_type type, + struct bnx2x_credit_pool_obj *macs_pool, + struct bnx2x_credit_pool_obj *vlans_pool) +{ + union bnx2x_qable_obj *qable_obj = + (union bnx2x_qable_obj *)vlan_mac_obj; + + bnx2x_init_vlan_mac_common(vlan_mac_obj, cl_id, cid, func_id, rdata, + rdata_mapping, state, pstate, type, + macs_pool, vlans_pool); + + /* CAM pool handling */ + vlan_mac_obj->get_credit = bnx2x_get_credit_vlan_mac; + vlan_mac_obj->put_credit = bnx2x_put_credit_vlan_mac; + /* + * CAM offset is relevant for 57710 and 57711 chips only which have a + * single CAM for both MACs and VLAN-MAC pairs. So the offset + * will be taken from MACs' pool object only. + */ + vlan_mac_obj->get_cam_offset = bnx2x_get_cam_offset_mac; + vlan_mac_obj->put_cam_offset = bnx2x_put_cam_offset_mac; + + if (CHIP_IS_E1(bp)) { + BNX2X_ERR("Do not support chips others than E2\n"); + BUG(); + } else if (CHIP_IS_E1H(bp)) { + vlan_mac_obj->set_one_rule = bnx2x_set_one_vlan_mac_e1h; + vlan_mac_obj->check_del = bnx2x_check_vlan_mac_del; + vlan_mac_obj->check_add = bnx2x_check_vlan_mac_add; + vlan_mac_obj->check_move = bnx2x_check_move_always_err; + vlan_mac_obj->ramrod_cmd = RAMROD_CMD_ID_ETH_SET_MAC; + + /* Exe Queue */ + bnx2x_exe_queue_init(bp, + &vlan_mac_obj->exe_queue, 1, qable_obj, + bnx2x_validate_vlan_mac, + bnx2x_optimize_vlan_mac, + bnx2x_execute_vlan_mac, + bnx2x_exeq_get_vlan_mac); + } else { + vlan_mac_obj->set_one_rule = bnx2x_set_one_vlan_mac_e2; + vlan_mac_obj->check_del = bnx2x_check_vlan_mac_del; + vlan_mac_obj->check_add = bnx2x_check_vlan_mac_add; + vlan_mac_obj->check_move = bnx2x_check_move; + vlan_mac_obj->ramrod_cmd = + RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES; + + /* Exe Queue */ + bnx2x_exe_queue_init(bp, + &vlan_mac_obj->exe_queue, + CLASSIFY_RULES_COUNT, + qable_obj, bnx2x_validate_vlan_mac, + bnx2x_optimize_vlan_mac, + bnx2x_execute_vlan_mac, + bnx2x_exeq_get_vlan_mac); + } + +} + +/* RX_MODE verbs: DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */ +static inline void __storm_memset_mac_filters(struct bnx2x *bp, + struct tstorm_eth_mac_filter_config *mac_filters, + u16 pf_id) +{ + size_t size = sizeof(struct tstorm_eth_mac_filter_config); + + u32 addr = BAR_TSTRORM_INTMEM + + TSTORM_MAC_FILTER_CONFIG_OFFSET(pf_id); + + __storm_memset_struct(bp, addr, size, (u32 *)mac_filters); +} + +static int bnx2x_set_rx_mode_e1x(struct bnx2x *bp, + struct bnx2x_rx_mode_ramrod_params *p) +{ + /* update the bp MAC filter structure */ + u32 mask = (1 << p->cl_id); + + struct tstorm_eth_mac_filter_config *mac_filters = + (struct tstorm_eth_mac_filter_config *)p->rdata; + + /* initial seeting is drop-all */ + u8 drop_all_ucast = 1, drop_all_mcast = 1; + u8 accp_all_ucast = 0, accp_all_bcast = 0, accp_all_mcast = 0; + u8 unmatched_unicast = 0; + + /* In e1x there we only take into account rx acceot flag since tx switching + * isn't enabled. */ + if (test_bit(BNX2X_ACCEPT_UNICAST, &p->rx_accept_flags)) + /* accept matched ucast */ + drop_all_ucast = 0; + + if (test_bit(BNX2X_ACCEPT_MULTICAST, &p->rx_accept_flags)) + /* accept matched mcast */ + drop_all_mcast = 0; + + if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, &p->rx_accept_flags)) { + /* accept all mcast */ + drop_all_ucast = 0; + accp_all_ucast = 1; + } + if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, &p->rx_accept_flags)) { + /* accept all mcast */ + drop_all_mcast = 0; + accp_all_mcast = 1; + } + if (test_bit(BNX2X_ACCEPT_BROADCAST, &p->rx_accept_flags)) + /* accept (all) bcast */ + accp_all_bcast = 1; + if (test_bit(BNX2X_ACCEPT_UNMATCHED, &p->rx_accept_flags)) + /* accept unmatched unicasts */ + unmatched_unicast = 1; + + mac_filters->ucast_drop_all = drop_all_ucast ? + mac_filters->ucast_drop_all | mask : + mac_filters->ucast_drop_all & ~mask; + + mac_filters->mcast_drop_all = drop_all_mcast ? + mac_filters->mcast_drop_all | mask : + mac_filters->mcast_drop_all & ~mask; + + mac_filters->ucast_accept_all = accp_all_ucast ? + mac_filters->ucast_accept_all | mask : + mac_filters->ucast_accept_all & ~mask; + + mac_filters->mcast_accept_all = accp_all_mcast ? + mac_filters->mcast_accept_all | mask : + mac_filters->mcast_accept_all & ~mask; + + mac_filters->bcast_accept_all = accp_all_bcast ? + mac_filters->bcast_accept_all | mask : + mac_filters->bcast_accept_all & ~mask; + + mac_filters->unmatched_unicast = unmatched_unicast ? + mac_filters->unmatched_unicast | mask : + mac_filters->unmatched_unicast & ~mask; + + DP(BNX2X_MSG_SP, "drop_ucast 0x%x\ndrop_mcast 0x%x\n accp_ucast 0x%x\n" + "accp_mcast 0x%x\naccp_bcast 0x%x\n", + mac_filters->ucast_drop_all, + mac_filters->mcast_drop_all, + mac_filters->ucast_accept_all, + mac_filters->mcast_accept_all, + mac_filters->bcast_accept_all); + + /* write the MAC filter structure*/ + __storm_memset_mac_filters(bp, mac_filters, p->func_id); + + /* The operation is completed */ + clear_bit(p->state, p->pstate); + smp_mb__after_clear_bit(); + + return 0; +} + +/* Setup ramrod data */ +static inline void bnx2x_rx_mode_set_rdata_hdr_e2(u32 cid, + struct eth_classify_header *hdr, + u8 rule_cnt) +{ + hdr->echo = cid; + hdr->rule_cnt = rule_cnt; +} + +static inline void bnx2x_rx_mode_set_cmd_state_e2(struct bnx2x *bp, + unsigned long accept_flags, + struct eth_filter_rules_cmd *cmd, + bool clear_accept_all) +{ + u16 state; + + /* start with 'drop-all' */ + state = ETH_FILTER_RULES_CMD_UCAST_DROP_ALL | + ETH_FILTER_RULES_CMD_MCAST_DROP_ALL; + + if (accept_flags) { + if (test_bit(BNX2X_ACCEPT_UNICAST, &accept_flags)) + state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL; + + if (test_bit(BNX2X_ACCEPT_MULTICAST, &accept_flags)) + state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL; + + if (test_bit(BNX2X_ACCEPT_ALL_UNICAST, &accept_flags)) { + state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL; + state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL; + } + + if (test_bit(BNX2X_ACCEPT_ALL_MULTICAST, &accept_flags)) { + state |= ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL; + state &= ~ETH_FILTER_RULES_CMD_MCAST_DROP_ALL; + } + if (test_bit(BNX2X_ACCEPT_BROADCAST, &accept_flags)) + state |= ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL; + + if (test_bit(BNX2X_ACCEPT_UNMATCHED, &accept_flags)) { + state &= ~ETH_FILTER_RULES_CMD_UCAST_DROP_ALL; + state |= ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED; + } + if (test_bit(BNX2X_ACCEPT_ANY_VLAN, &accept_flags)) + state |= ETH_FILTER_RULES_CMD_ACCEPT_ANY_VLAN; + } + + /* Clear ACCEPT_ALL_XXX flags for FCoE L2 Queue */ + if (clear_accept_all) { + state &= ~ETH_FILTER_RULES_CMD_MCAST_ACCEPT_ALL; + state &= ~ETH_FILTER_RULES_CMD_BCAST_ACCEPT_ALL; + state &= ~ETH_FILTER_RULES_CMD_UCAST_ACCEPT_ALL; + state &= ~ETH_FILTER_RULES_CMD_UCAST_ACCEPT_UNMATCHED; + } + + cmd->state = cpu_to_le16(state); + +} + +static int bnx2x_set_rx_mode_e2(struct bnx2x *bp, + struct bnx2x_rx_mode_ramrod_params *p) +{ + struct eth_filter_rules_ramrod_data *data = p->rdata; + int rc; + u8 rule_idx = 0; + + /* Reset the ramrod data buffer */ + memset(data, 0, sizeof(*data)); + + /* Setup ramrod data */ + + /* Tx (internal switching) */ + if (test_bit(RAMROD_TX, &p->ramrod_flags)) { + data->rules[rule_idx].client_id = p->cl_id; + data->rules[rule_idx].func_id = p->func_id; + + data->rules[rule_idx].cmd_general_data = + ETH_FILTER_RULES_CMD_TX_CMD; + + bnx2x_rx_mode_set_cmd_state_e2(bp, p->tx_accept_flags, + &(data->rules[rule_idx++]), false); + } + + /* Rx */ + if (test_bit(RAMROD_RX, &p->ramrod_flags)) { + data->rules[rule_idx].client_id = p->cl_id; + data->rules[rule_idx].func_id = p->func_id; + + data->rules[rule_idx].cmd_general_data = + ETH_FILTER_RULES_CMD_RX_CMD; + + bnx2x_rx_mode_set_cmd_state_e2(bp, p->rx_accept_flags, + &(data->rules[rule_idx++]), false); + } + + + /* + * If FCoE Queue configuration has been requested configure the Rx and + * internal switching modes for this queue in separate rules. + * + * FCoE queue shell never be set to ACCEPT_ALL packets of any sort: + * MCAST_ALL, UCAST_ALL, BCAST_ALL and UNMATCHED. + */ + if (test_bit(BNX2X_RX_MODE_FCOE_ETH, &p->rx_mode_flags)) { + /* Tx (internal switching) */ + if (test_bit(RAMROD_TX, &p->ramrod_flags)) { + data->rules[rule_idx].client_id = bnx2x_fcoe(bp, cl_id); + data->rules[rule_idx].func_id = p->func_id; + + data->rules[rule_idx].cmd_general_data = + ETH_FILTER_RULES_CMD_TX_CMD; + + bnx2x_rx_mode_set_cmd_state_e2(bp, p->tx_accept_flags, + &(data->rules[rule_idx++]), + true); + } + + /* Rx */ + if (test_bit(RAMROD_RX, &p->ramrod_flags)) { + data->rules[rule_idx].client_id = bnx2x_fcoe(bp, cl_id); + data->rules[rule_idx].func_id = p->func_id; + + data->rules[rule_idx].cmd_general_data = + ETH_FILTER_RULES_CMD_RX_CMD; + + bnx2x_rx_mode_set_cmd_state_e2(bp, p->rx_accept_flags, + &(data->rules[rule_idx++]), + true); + } + } + + /* + * Set the ramrod header (most importantly - number of rules to + * configure). + */ + bnx2x_rx_mode_set_rdata_hdr_e2(p->cid, &data->header, rule_idx); + + DP(BNX2X_MSG_SP, "About to configure %d rules, rx_accept_flags 0x%lx, " + "tx_accept_flags 0x%lx\n", + data->header.rule_cnt, p->rx_accept_flags, + p->tx_accept_flags); + + /* + * No need for an explicit memory barrier here as long we would + * need to ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read and we will have to put a full memory barrier there + * (inside bnx2x_sp_post()). + */ + + /* Send a ramrod */ + rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_FILTER_RULES, p->cid, + U64_HI(p->rdata_mapping), + U64_LO(p->rdata_mapping), + ETH_CONNECTION_TYPE); + if (rc) + return rc; + + /* Ramrod completion is pending */ + return 1; +} + +static int bnx2x_wait_rx_mode_comp_e2(struct bnx2x *bp, + struct bnx2x_rx_mode_ramrod_params *p) +{ + return bnx2x_state_wait(bp, p->state, p->pstate); +} + +static int bnx2x_empty_rx_mode_wait(struct bnx2x *bp, + struct bnx2x_rx_mode_ramrod_params *p) +{ + /* Do nothing */ + return 0; +} + +int bnx2x_config_rx_mode(struct bnx2x *bp, + struct bnx2x_rx_mode_ramrod_params *p) +{ + int rc; + + /* Configure the new classification in the chip */ + rc = p->rx_mode_obj->config_rx_mode(bp, p); + if (rc < 0) + return rc; + + /* Wait for a ramrod completion if was requested */ + if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags)) { + rc = p->rx_mode_obj->wait_comp(bp, p); + if (rc) + return rc; + } + + return rc; +} + +void bnx2x_init_rx_mode_obj(struct bnx2x *bp, + struct bnx2x_rx_mode_obj *o) +{ + if (CHIP_IS_E1x(bp)) { + o->wait_comp = bnx2x_empty_rx_mode_wait; + o->config_rx_mode = bnx2x_set_rx_mode_e1x; + } else { + o->wait_comp = bnx2x_wait_rx_mode_comp_e2; + o->config_rx_mode = bnx2x_set_rx_mode_e2; + } +} + +/********************* Multicast verbs: SET, CLEAR ****************************/ +static inline u8 bnx2x_mcast_bin_from_mac(u8 *mac) +{ + return (crc32c_le(0, mac, ETH_ALEN) >> 24) & 0xff; +} + +struct bnx2x_mcast_mac_elem { + struct list_head link; + u8 mac[ETH_ALEN]; + u8 pad[2]; /* For a natural alignment of the following buffer */ +}; + +struct bnx2x_pending_mcast_cmd { + struct list_head link; + int type; /* BNX2X_MCAST_CMD_X */ + union { + struct list_head macs_head; + u32 macs_num; /* Needed for DEL command */ + int next_bin; /* Needed for RESTORE flow with aprox match */ + } data; + + bool done; /* set to true, when the command has been handled, + * practically used in 57712 handling only, where one pending + * command may be handled in a few operations. As long as for + * other chips every operation handling is completed in a + * single ramrod, there is no need to utilize this field. + */ +}; + +static int bnx2x_mcast_wait(struct bnx2x *bp, + struct bnx2x_mcast_obj *o) +{ + if (bnx2x_state_wait(bp, o->sched_state, o->raw.pstate) || + o->raw.wait_comp(bp, &o->raw)) + return -EBUSY; + + return 0; +} + +static int bnx2x_mcast_enqueue_cmd(struct bnx2x *bp, + struct bnx2x_mcast_obj *o, + struct bnx2x_mcast_ramrod_params *p, + int cmd) +{ + int total_sz; + struct bnx2x_pending_mcast_cmd *new_cmd; + struct bnx2x_mcast_mac_elem *cur_mac = NULL; + struct bnx2x_mcast_list_elem *pos; + int macs_list_len = ((cmd == BNX2X_MCAST_CMD_ADD) ? + p->mcast_list_len : 0); + + /* If the command is empty ("handle pending commands only"), break */ + if (!p->mcast_list_len) + return 0; + + total_sz = sizeof(*new_cmd) + + macs_list_len * sizeof(struct bnx2x_mcast_mac_elem); + + /* Add mcast is called under spin_lock, thus calling with GFP_ATOMIC */ + new_cmd = kzalloc(total_sz, GFP_ATOMIC); + + if (!new_cmd) + return -ENOMEM; + + DP(BNX2X_MSG_SP, "About to enqueue a new %d command. " + "macs_list_len=%d\n", cmd, macs_list_len); + + INIT_LIST_HEAD(&new_cmd->data.macs_head); + + new_cmd->type = cmd; + new_cmd->done = false; + + switch (cmd) { + case BNX2X_MCAST_CMD_ADD: + cur_mac = (struct bnx2x_mcast_mac_elem *) + ((u8 *)new_cmd + sizeof(*new_cmd)); + + /* Push the MACs of the current command into the pendig command + * MACs list: FIFO + */ + list_for_each_entry(pos, &p->mcast_list, link) { + memcpy(cur_mac->mac, pos->mac, ETH_ALEN); + list_add_tail(&cur_mac->link, &new_cmd->data.macs_head); + cur_mac++; + } + + break; + + case BNX2X_MCAST_CMD_DEL: + new_cmd->data.macs_num = p->mcast_list_len; + break; + + case BNX2X_MCAST_CMD_RESTORE: + new_cmd->data.next_bin = 0; + break; + + default: + BNX2X_ERR("Unknown command: %d\n", cmd); + return -EINVAL; + } + + /* Push the new pending command to the tail of the pending list: FIFO */ + list_add_tail(&new_cmd->link, &o->pending_cmds_head); + + o->set_sched(o); + + return 1; +} + +/** + * bnx2x_mcast_get_next_bin - get the next set bin (index) + * + * @o: + * @last: index to start looking from (including) + * + * returns the next found (set) bin or a negative value if none is found. + */ +static inline int bnx2x_mcast_get_next_bin(struct bnx2x_mcast_obj *o, int last) +{ + int i, j, inner_start = last % BIT_VEC64_ELEM_SZ; + + for (i = last / BIT_VEC64_ELEM_SZ; i < BNX2X_MCAST_VEC_SZ; i++) { + if (o->registry.aprox_match.vec[i]) + for (j = inner_start; j < BIT_VEC64_ELEM_SZ; j++) { + int cur_bit = j + BIT_VEC64_ELEM_SZ * i; + if (BIT_VEC64_TEST_BIT(o->registry.aprox_match. + vec, cur_bit)) { + return cur_bit; + } + } + inner_start = 0; + } + + /* None found */ + return -1; +} + +/** + * bnx2x_mcast_clear_first_bin - find the first set bin and clear it + * + * @o: + * + * returns the index of the found bin or -1 if none is found + */ +static inline int bnx2x_mcast_clear_first_bin(struct bnx2x_mcast_obj *o) +{ + int cur_bit = bnx2x_mcast_get_next_bin(o, 0); + + if (cur_bit >= 0) + BIT_VEC64_CLEAR_BIT(o->registry.aprox_match.vec, cur_bit); + + return cur_bit; +} + +static inline u8 bnx2x_mcast_get_rx_tx_flag(struct bnx2x_mcast_obj *o) +{ + struct bnx2x_raw_obj *raw = &o->raw; + u8 rx_tx_flag = 0; + + if ((raw->obj_type == BNX2X_OBJ_TYPE_TX) || + (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX)) + rx_tx_flag |= ETH_MULTICAST_RULES_CMD_TX_CMD; + + if ((raw->obj_type == BNX2X_OBJ_TYPE_RX) || + (raw->obj_type == BNX2X_OBJ_TYPE_RX_TX)) + rx_tx_flag |= ETH_MULTICAST_RULES_CMD_RX_CMD; + + return rx_tx_flag; +} + +static void bnx2x_mcast_set_one_rule_e2(struct bnx2x *bp, + struct bnx2x_mcast_obj *o, int idx, + union bnx2x_mcast_config_data *cfg_data, + int cmd) +{ + struct bnx2x_raw_obj *r = &o->raw; + struct eth_multicast_rules_ramrod_data *data = + (struct eth_multicast_rules_ramrod_data *)(r->rdata); + u8 func_id = r->func_id; + u8 rx_tx_add_flag = bnx2x_mcast_get_rx_tx_flag(o); + int bin; + + if ((cmd == BNX2X_MCAST_CMD_ADD) || (cmd == BNX2X_MCAST_CMD_RESTORE)) + rx_tx_add_flag |= ETH_MULTICAST_RULES_CMD_IS_ADD; + + data->rules[idx].cmd_general_data |= rx_tx_add_flag; + + /* Get a bin and update a bins' vector */ + switch (cmd) { + case BNX2X_MCAST_CMD_ADD: + bin = bnx2x_mcast_bin_from_mac(cfg_data->mac); + BIT_VEC64_SET_BIT(o->registry.aprox_match.vec, bin); + break; + + case BNX2X_MCAST_CMD_DEL: + /* If there were no more bins to clear + * (bnx2x_mcast_clear_first_bin() returns -1) then we would + * clear any (0xff) bin. + * See bnx2x_mcast_validate_e2() for explanation when it may + * happen. + */ + bin = bnx2x_mcast_clear_first_bin(o); + break; + + case BNX2X_MCAST_CMD_RESTORE: + bin = cfg_data->bin; + break; + + default: + BNX2X_ERR("Unknown command: %d\n", cmd); + return; + } + + DP(BNX2X_MSG_SP, "%s bin %d\n", + ((rx_tx_add_flag & ETH_MULTICAST_RULES_CMD_IS_ADD) ? + "Setting" : "Clearing"), bin); + + data->rules[idx].bin_id = (u8)bin; + data->rules[idx].func_id = func_id; + data->rules[idx].engine_id = o->engine_id; +} + +/** + * bnx2x_mcast_handle_restore_cmd_e2 - restore configuration from the registry + * + * @bp: device handle + * @o: + * @start_bin: index in the registry to start from (including) + * @rdata_idx: index in the ramrod data to start from + * + * returns last handled bin index or -1 if all bins have been handled + */ +static inline int bnx2x_mcast_handle_restore_cmd_e2( + struct bnx2x *bp, struct bnx2x_mcast_obj *o , int start_bin, + int *rdata_idx) +{ + int cur_bin, cnt = *rdata_idx; + union bnx2x_mcast_config_data cfg_data = {0}; + + /* go through the registry and configure the bins from it */ + for (cur_bin = bnx2x_mcast_get_next_bin(o, start_bin); cur_bin >= 0; + cur_bin = bnx2x_mcast_get_next_bin(o, cur_bin + 1)) { + + cfg_data.bin = (u8)cur_bin; + o->set_one_rule(bp, o, cnt, &cfg_data, + BNX2X_MCAST_CMD_RESTORE); + + cnt++; + + DP(BNX2X_MSG_SP, "About to configure a bin %d\n", cur_bin); + + /* Break if we reached the maximum number + * of rules. + */ + if (cnt >= o->max_cmd_len) + break; + } + + *rdata_idx = cnt; + + return cur_bin; +} + +static inline void bnx2x_mcast_hdl_pending_add_e2(struct bnx2x *bp, + struct bnx2x_mcast_obj *o, struct bnx2x_pending_mcast_cmd *cmd_pos, + int *line_idx) +{ + struct bnx2x_mcast_mac_elem *pmac_pos, *pmac_pos_n; + int cnt = *line_idx; + union bnx2x_mcast_config_data cfg_data = {0}; + + list_for_each_entry_safe(pmac_pos, pmac_pos_n, &cmd_pos->data.macs_head, + link) { + + cfg_data.mac = &pmac_pos->mac[0]; + o->set_one_rule(bp, o, cnt, &cfg_data, cmd_pos->type); + + cnt++; + + DP(BNX2X_MSG_SP, "About to configure "BNX2X_MAC_FMT + " mcast MAC\n", + BNX2X_MAC_PRN_LIST(pmac_pos->mac)); + + list_del(&pmac_pos->link); + + /* Break if we reached the maximum number + * of rules. + */ + if (cnt >= o->max_cmd_len) + break; + } + + *line_idx = cnt; + + /* if no more MACs to configure - we are done */ + if (list_empty(&cmd_pos->data.macs_head)) + cmd_pos->done = true; +} + +static inline void bnx2x_mcast_hdl_pending_del_e2(struct bnx2x *bp, + struct bnx2x_mcast_obj *o, struct bnx2x_pending_mcast_cmd *cmd_pos, + int *line_idx) +{ + int cnt = *line_idx; + + while (cmd_pos->data.macs_num) { + o->set_one_rule(bp, o, cnt, NULL, cmd_pos->type); + + cnt++; + + cmd_pos->data.macs_num--; + + DP(BNX2X_MSG_SP, "Deleting MAC. %d left,cnt is %d\n", + cmd_pos->data.macs_num, cnt); + + /* Break if we reached the maximum + * number of rules. + */ + if (cnt >= o->max_cmd_len) + break; + } + + *line_idx = cnt; + + /* If we cleared all bins - we are done */ + if (!cmd_pos->data.macs_num) + cmd_pos->done = true; +} + +static inline void bnx2x_mcast_hdl_pending_restore_e2(struct bnx2x *bp, + struct bnx2x_mcast_obj *o, struct bnx2x_pending_mcast_cmd *cmd_pos, + int *line_idx) +{ + cmd_pos->data.next_bin = o->hdl_restore(bp, o, cmd_pos->data.next_bin, + line_idx); + + if (cmd_pos->data.next_bin < 0) + /* If o->set_restore returned -1 we are done */ + cmd_pos->done = true; + else + /* Start from the next bin next time */ + cmd_pos->data.next_bin++; +} + +static inline int bnx2x_mcast_handle_pending_cmds_e2(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p) +{ + struct bnx2x_pending_mcast_cmd *cmd_pos, *cmd_pos_n; + int cnt = 0; + struct bnx2x_mcast_obj *o = p->mcast_obj; + + list_for_each_entry_safe(cmd_pos, cmd_pos_n, &o->pending_cmds_head, + link) { + switch (cmd_pos->type) { + case BNX2X_MCAST_CMD_ADD: + bnx2x_mcast_hdl_pending_add_e2(bp, o, cmd_pos, &cnt); + break; + + case BNX2X_MCAST_CMD_DEL: + bnx2x_mcast_hdl_pending_del_e2(bp, o, cmd_pos, &cnt); + break; + + case BNX2X_MCAST_CMD_RESTORE: + bnx2x_mcast_hdl_pending_restore_e2(bp, o, cmd_pos, + &cnt); + break; + + default: + BNX2X_ERR("Unknown command: %d\n", cmd_pos->type); + return -EINVAL; + } + + /* If the command has been completed - remove it from the list + * and free the memory + */ + if (cmd_pos->done) { + list_del(&cmd_pos->link); + kfree(cmd_pos); + } + + /* Break if we reached the maximum number of rules */ + if (cnt >= o->max_cmd_len) + break; + } + + return cnt; +} + +static inline void bnx2x_mcast_hdl_add(struct bnx2x *bp, + struct bnx2x_mcast_obj *o, struct bnx2x_mcast_ramrod_params *p, + int *line_idx) +{ + struct bnx2x_mcast_list_elem *mlist_pos; + union bnx2x_mcast_config_data cfg_data = {0}; + int cnt = *line_idx; + + list_for_each_entry(mlist_pos, &p->mcast_list, link) { + cfg_data.mac = mlist_pos->mac; + o->set_one_rule(bp, o, cnt, &cfg_data, BNX2X_MCAST_CMD_ADD); + + cnt++; + + DP(BNX2X_MSG_SP, "About to configure "BNX2X_MAC_FMT + " mcast MAC\n", + BNX2X_MAC_PRN_LIST(mlist_pos->mac)); + } + + *line_idx = cnt; +} + +static inline void bnx2x_mcast_hdl_del(struct bnx2x *bp, + struct bnx2x_mcast_obj *o, struct bnx2x_mcast_ramrod_params *p, + int *line_idx) +{ + int cnt = *line_idx, i; + + for (i = 0; i < p->mcast_list_len; i++) { + o->set_one_rule(bp, o, cnt, NULL, BNX2X_MCAST_CMD_DEL); + + cnt++; + + DP(BNX2X_MSG_SP, "Deleting MAC. %d left\n", + p->mcast_list_len - i - 1); + } + + *line_idx = cnt; +} + +/** + * bnx2x_mcast_handle_current_cmd - + * + * @bp: device handle + * @p: + * @cmd: + * @start_cnt: first line in the ramrod data that may be used + * + * This function is called iff there is enough place for the current command in + * the ramrod data. + * Returns number of lines filled in the ramrod data in total. + */ +static inline int bnx2x_mcast_handle_current_cmd(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, int cmd, + int start_cnt) +{ + struct bnx2x_mcast_obj *o = p->mcast_obj; + int cnt = start_cnt; + + DP(BNX2X_MSG_SP, "p->mcast_list_len=%d\n", p->mcast_list_len); + + switch (cmd) { + case BNX2X_MCAST_CMD_ADD: + bnx2x_mcast_hdl_add(bp, o, p, &cnt); + break; + + case BNX2X_MCAST_CMD_DEL: + bnx2x_mcast_hdl_del(bp, o, p, &cnt); + break; + + case BNX2X_MCAST_CMD_RESTORE: + o->hdl_restore(bp, o, 0, &cnt); + break; + + default: + BNX2X_ERR("Unknown command: %d\n", cmd); + return -EINVAL; + } + + /* The current command has been handled */ + p->mcast_list_len = 0; + + return cnt; +} + +static int bnx2x_mcast_validate_e2(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + int cmd) +{ + struct bnx2x_mcast_obj *o = p->mcast_obj; + int reg_sz = o->get_registry_size(o); + + switch (cmd) { + /* DEL command deletes all currently configured MACs */ + case BNX2X_MCAST_CMD_DEL: + o->set_registry_size(o, 0); + /* Don't break */ + + /* RESTORE command will restore the entire multicast configuration */ + case BNX2X_MCAST_CMD_RESTORE: + /* Here we set the approximate amount of work to do, which in + * fact may be only less as some MACs in postponed ADD + * command(s) scheduled before this command may fall into + * the same bin and the actual number of bins set in the + * registry would be less than we estimated here. See + * bnx2x_mcast_set_one_rule_e2() for further details. + */ + p->mcast_list_len = reg_sz; + break; + + case BNX2X_MCAST_CMD_ADD: + case BNX2X_MCAST_CMD_CONT: + /* Here we assume that all new MACs will fall into new bins. + * However we will correct the real registry size after we + * handle all pending commands. + */ + o->set_registry_size(o, reg_sz + p->mcast_list_len); + break; + + default: + BNX2X_ERR("Unknown command: %d\n", cmd); + return -EINVAL; + + } + + /* Increase the total number of MACs pending to be configured */ + o->total_pending_num += p->mcast_list_len; + + return 0; +} + +static void bnx2x_mcast_revert_e2(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + int old_num_bins) +{ + struct bnx2x_mcast_obj *o = p->mcast_obj; + + o->set_registry_size(o, old_num_bins); + o->total_pending_num -= p->mcast_list_len; +} + +/** + * bnx2x_mcast_set_rdata_hdr_e2 - sets a header values + * + * @bp: device handle + * @p: + * @len: number of rules to handle + */ +static inline void bnx2x_mcast_set_rdata_hdr_e2(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + u8 len) +{ + struct bnx2x_raw_obj *r = &p->mcast_obj->raw; + struct eth_multicast_rules_ramrod_data *data = + (struct eth_multicast_rules_ramrod_data *)(r->rdata); + + data->header.echo = ((r->cid & BNX2X_SWCID_MASK) | + (BNX2X_FILTER_MCAST_PENDING << BNX2X_SWCID_SHIFT)); + data->header.rule_cnt = len; +} + +/** + * bnx2x_mcast_refresh_registry_e2 - recalculate the actual number of set bins + * + * @bp: device handle + * @o: + * + * Recalculate the actual number of set bins in the registry using Brian + * Kernighan's algorithm: it's execution complexity is as a number of set bins. + * + * returns 0 for the compliance with bnx2x_mcast_refresh_registry_e1(). + */ +static inline int bnx2x_mcast_refresh_registry_e2(struct bnx2x *bp, + struct bnx2x_mcast_obj *o) +{ + int i, cnt = 0; + u64 elem; + + for (i = 0; i < BNX2X_MCAST_VEC_SZ; i++) { + elem = o->registry.aprox_match.vec[i]; + for (; elem; cnt++) + elem &= elem - 1; + } + + o->set_registry_size(o, cnt); + + return 0; +} + +static int bnx2x_mcast_setup_e2(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + int cmd) +{ + struct bnx2x_raw_obj *raw = &p->mcast_obj->raw; + struct bnx2x_mcast_obj *o = p->mcast_obj; + struct eth_multicast_rules_ramrod_data *data = + (struct eth_multicast_rules_ramrod_data *)(raw->rdata); + int cnt = 0, rc; + + /* Reset the ramrod data buffer */ + memset(data, 0, sizeof(*data)); + + cnt = bnx2x_mcast_handle_pending_cmds_e2(bp, p); + + /* If there are no more pending commands - clear SCHEDULED state */ + if (list_empty(&o->pending_cmds_head)) + o->clear_sched(o); + + /* The below may be true iff there was enough room in ramrod + * data for all pending commands and for the current + * command. Otherwise the current command would have been added + * to the pending commands and p->mcast_list_len would have been + * zeroed. + */ + if (p->mcast_list_len > 0) + cnt = bnx2x_mcast_handle_current_cmd(bp, p, cmd, cnt); + + /* We've pulled out some MACs - update the total number of + * outstanding. + */ + o->total_pending_num -= cnt; + + /* send a ramrod */ + WARN_ON(o->total_pending_num < 0); + WARN_ON(cnt > o->max_cmd_len); + + bnx2x_mcast_set_rdata_hdr_e2(bp, p, (u8)cnt); + + /* Update a registry size if there are no more pending operations. + * + * We don't want to change the value of the registry size if there are + * pending operations because we want it to always be equal to the + * exact or the approximate number (see bnx2x_mcast_validate_e2()) of + * set bins after the last requested operation in order to properly + * evaluate the size of the next DEL/RESTORE operation. + * + * Note that we update the registry itself during command(s) handling + * - see bnx2x_mcast_set_one_rule_e2(). That's because for 57712 we + * aggregate multiple commands (ADD/DEL/RESTORE) into one ramrod but + * with a limited amount of update commands (per MAC/bin) and we don't + * know in this scope what the actual state of bins configuration is + * going to be after this ramrod. + */ + if (!o->total_pending_num) + bnx2x_mcast_refresh_registry_e2(bp, o); + + /* + * If CLEAR_ONLY was requested - don't send a ramrod and clear + * RAMROD_PENDING status immediately. + */ + if (test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) { + raw->clear_pending(raw); + return 0; + } else { + /* + * No need for an explicit memory barrier here as long we would + * need to ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read and we will have to put a full memory barrier there + * (inside bnx2x_sp_post()). + */ + + /* Send a ramrod */ + rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_MULTICAST_RULES, + raw->cid, U64_HI(raw->rdata_mapping), + U64_LO(raw->rdata_mapping), + ETH_CONNECTION_TYPE); + if (rc) + return rc; + + /* Ramrod completion is pending */ + return 1; + } +} + +static int bnx2x_mcast_validate_e1h(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + int cmd) +{ + /* Mark, that there is a work to do */ + if ((cmd == BNX2X_MCAST_CMD_DEL) || (cmd == BNX2X_MCAST_CMD_RESTORE)) + p->mcast_list_len = 1; + + return 0; +} + +static void bnx2x_mcast_revert_e1h(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + int old_num_bins) +{ + /* Do nothing */ +} + +#define BNX2X_57711_SET_MC_FILTER(filter, bit) \ +do { \ + (filter)[(bit) >> 5] |= (1 << ((bit) & 0x1f)); \ +} while (0) + +static inline void bnx2x_mcast_hdl_add_e1h(struct bnx2x *bp, + struct bnx2x_mcast_obj *o, + struct bnx2x_mcast_ramrod_params *p, + u32 *mc_filter) +{ + struct bnx2x_mcast_list_elem *mlist_pos; + int bit; + + list_for_each_entry(mlist_pos, &p->mcast_list, link) { + bit = bnx2x_mcast_bin_from_mac(mlist_pos->mac); + BNX2X_57711_SET_MC_FILTER(mc_filter, bit); + + DP(BNX2X_MSG_SP, "About to configure " + BNX2X_MAC_FMT" mcast MAC, bin %d\n", + BNX2X_MAC_PRN_LIST(mlist_pos->mac), bit); + + /* bookkeeping... */ + BIT_VEC64_SET_BIT(o->registry.aprox_match.vec, + bit); + } +} + +static inline void bnx2x_mcast_hdl_restore_e1h(struct bnx2x *bp, + struct bnx2x_mcast_obj *o, struct bnx2x_mcast_ramrod_params *p, + u32 *mc_filter) +{ + int bit; + + for (bit = bnx2x_mcast_get_next_bin(o, 0); + bit >= 0; + bit = bnx2x_mcast_get_next_bin(o, bit + 1)) { + BNX2X_57711_SET_MC_FILTER(mc_filter, bit); + DP(BNX2X_MSG_SP, "About to set bin %d\n", bit); + } +} + +/* On 57711 we write the multicast MACs' aproximate match + * table by directly into the TSTORM's internal RAM. So we don't + * really need to handle any tricks to make it work. + */ +static int bnx2x_mcast_setup_e1h(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + int cmd) +{ + int i; + struct bnx2x_mcast_obj *o = p->mcast_obj; + struct bnx2x_raw_obj *r = &o->raw; + + /* If CLEAR_ONLY has been requested - clear the registry + * and clear a pending bit. + */ + if (!test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) { + u32 mc_filter[MC_HASH_SIZE] = {0}; + + /* Set the multicast filter bits before writing it into + * the internal memory. + */ + switch (cmd) { + case BNX2X_MCAST_CMD_ADD: + bnx2x_mcast_hdl_add_e1h(bp, o, p, mc_filter); + break; + + case BNX2X_MCAST_CMD_DEL: + DP(BNX2X_MSG_SP, "Invalidating multicast " + "MACs configuration\n"); + + /* clear the registry */ + memset(o->registry.aprox_match.vec, 0, + sizeof(o->registry.aprox_match.vec)); + break; + + case BNX2X_MCAST_CMD_RESTORE: + bnx2x_mcast_hdl_restore_e1h(bp, o, p, mc_filter); + break; + + default: + BNX2X_ERR("Unknown command: %d\n", cmd); + return -EINVAL; + } + + /* Set the mcast filter in the internal memory */ + for (i = 0; i < MC_HASH_SIZE; i++) + REG_WR(bp, MC_HASH_OFFSET(bp, i), mc_filter[i]); + } else + /* clear the registry */ + memset(o->registry.aprox_match.vec, 0, + sizeof(o->registry.aprox_match.vec)); + + /* We are done */ + r->clear_pending(r); + + return 0; +} + +static int bnx2x_mcast_validate_e1(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + int cmd) +{ + struct bnx2x_mcast_obj *o = p->mcast_obj; + int reg_sz = o->get_registry_size(o); + + switch (cmd) { + /* DEL command deletes all currently configured MACs */ + case BNX2X_MCAST_CMD_DEL: + o->set_registry_size(o, 0); + /* Don't break */ + + /* RESTORE command will restore the entire multicast configuration */ + case BNX2X_MCAST_CMD_RESTORE: + p->mcast_list_len = reg_sz; + DP(BNX2X_MSG_SP, "Command %d, p->mcast_list_len=%d\n", + cmd, p->mcast_list_len); + break; + + case BNX2X_MCAST_CMD_ADD: + case BNX2X_MCAST_CMD_CONT: + /* Multicast MACs on 57710 are configured as unicast MACs and + * there is only a limited number of CAM entries for that + * matter. + */ + if (p->mcast_list_len > o->max_cmd_len) { + BNX2X_ERR("Can't configure more than %d multicast MACs" + "on 57710\n", o->max_cmd_len); + return -EINVAL; + } + /* Every configured MAC should be cleared if DEL command is + * called. Only the last ADD command is relevant as long as + * every ADD commands overrides the previous configuration. + */ + DP(BNX2X_MSG_SP, "p->mcast_list_len=%d\n", p->mcast_list_len); + if (p->mcast_list_len > 0) + o->set_registry_size(o, p->mcast_list_len); + + break; + + default: + BNX2X_ERR("Unknown command: %d\n", cmd); + return -EINVAL; + + } + + /* We want to ensure that commands are executed one by one for 57710. + * Therefore each none-empty command will consume o->max_cmd_len. + */ + if (p->mcast_list_len) + o->total_pending_num += o->max_cmd_len; + + return 0; +} + +static void bnx2x_mcast_revert_e1(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + int old_num_macs) +{ + struct bnx2x_mcast_obj *o = p->mcast_obj; + + o->set_registry_size(o, old_num_macs); + + /* If current command hasn't been handled yet and we are + * here means that it's meant to be dropped and we have to + * update the number of outstandling MACs accordingly. + */ + if (p->mcast_list_len) + o->total_pending_num -= o->max_cmd_len; +} + +static void bnx2x_mcast_set_one_rule_e1(struct bnx2x *bp, + struct bnx2x_mcast_obj *o, int idx, + union bnx2x_mcast_config_data *cfg_data, + int cmd) +{ + struct bnx2x_raw_obj *r = &o->raw; + struct mac_configuration_cmd *data = + (struct mac_configuration_cmd *)(r->rdata); + + /* copy mac */ + if ((cmd == BNX2X_MCAST_CMD_ADD) || (cmd == BNX2X_MCAST_CMD_RESTORE)) { + bnx2x_set_fw_mac_addr(&data->config_table[idx].msb_mac_addr, + &data->config_table[idx].middle_mac_addr, + &data->config_table[idx].lsb_mac_addr, + cfg_data->mac); + + data->config_table[idx].vlan_id = 0; + data->config_table[idx].pf_id = r->func_id; + data->config_table[idx].clients_bit_vector = + cpu_to_le32(1 << r->cl_id); + + SET_FLAG(data->config_table[idx].flags, + MAC_CONFIGURATION_ENTRY_ACTION_TYPE, + T_ETH_MAC_COMMAND_SET); + } +} + +/** + * bnx2x_mcast_set_rdata_hdr_e1 - set header values in mac_configuration_cmd + * + * @bp: device handle + * @p: + * @len: number of rules to handle + */ +static inline void bnx2x_mcast_set_rdata_hdr_e1(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + u8 len) +{ + struct bnx2x_raw_obj *r = &p->mcast_obj->raw; + struct mac_configuration_cmd *data = + (struct mac_configuration_cmd *)(r->rdata); + + u8 offset = (CHIP_REV_IS_SLOW(bp) ? + BNX2X_MAX_EMUL_MULTI*(1 + r->func_id) : + BNX2X_MAX_MULTICAST*(1 + r->func_id)); + + data->hdr.offset = offset; + data->hdr.client_id = 0xff; + data->hdr.echo = ((r->cid & BNX2X_SWCID_MASK) | + (BNX2X_FILTER_MCAST_PENDING << BNX2X_SWCID_SHIFT)); + data->hdr.length = len; +} + +/** + * bnx2x_mcast_handle_restore_cmd_e1 - restore command for 57710 + * + * @bp: device handle + * @o: + * @start_idx: index in the registry to start from + * @rdata_idx: index in the ramrod data to start from + * + * restore command for 57710 is like all other commands - always a stand alone + * command - start_idx and rdata_idx will always be 0. This function will always + * succeed. + * returns -1 to comply with 57712 variant. + */ +static inline int bnx2x_mcast_handle_restore_cmd_e1( + struct bnx2x *bp, struct bnx2x_mcast_obj *o , int start_idx, + int *rdata_idx) +{ + struct bnx2x_mcast_mac_elem *elem; + int i = 0; + union bnx2x_mcast_config_data cfg_data = {0}; + + /* go through the registry and configure the MACs from it. */ + list_for_each_entry(elem, &o->registry.exact_match.macs, link) { + cfg_data.mac = &elem->mac[0]; + o->set_one_rule(bp, o, i, &cfg_data, BNX2X_MCAST_CMD_RESTORE); + + i++; + + DP(BNX2X_MSG_SP, "About to configure "BNX2X_MAC_FMT + " mcast MAC\n", + BNX2X_MAC_PRN_LIST(cfg_data.mac)); + } + + *rdata_idx = i; + + return -1; +} + + +static inline int bnx2x_mcast_handle_pending_cmds_e1( + struct bnx2x *bp, struct bnx2x_mcast_ramrod_params *p) +{ + struct bnx2x_pending_mcast_cmd *cmd_pos; + struct bnx2x_mcast_mac_elem *pmac_pos; + struct bnx2x_mcast_obj *o = p->mcast_obj; + union bnx2x_mcast_config_data cfg_data = {0}; + int cnt = 0; + + + /* If nothing to be done - return */ + if (list_empty(&o->pending_cmds_head)) + return 0; + + /* Handle the first command */ + cmd_pos = list_first_entry(&o->pending_cmds_head, + struct bnx2x_pending_mcast_cmd, link); + + switch (cmd_pos->type) { + case BNX2X_MCAST_CMD_ADD: + list_for_each_entry(pmac_pos, &cmd_pos->data.macs_head, link) { + cfg_data.mac = &pmac_pos->mac[0]; + o->set_one_rule(bp, o, cnt, &cfg_data, cmd_pos->type); + + cnt++; + + DP(BNX2X_MSG_SP, "About to configure "BNX2X_MAC_FMT + " mcast MAC\n", + BNX2X_MAC_PRN_LIST(pmac_pos->mac)); + } + break; + + case BNX2X_MCAST_CMD_DEL: + cnt = cmd_pos->data.macs_num; + DP(BNX2X_MSG_SP, "About to delete %d multicast MACs\n", cnt); + break; + + case BNX2X_MCAST_CMD_RESTORE: + o->hdl_restore(bp, o, 0, &cnt); + break; + + default: + BNX2X_ERR("Unknown command: %d\n", cmd_pos->type); + return -EINVAL; + } + + list_del(&cmd_pos->link); + kfree(cmd_pos); + + return cnt; +} + +/** + * bnx2x_get_fw_mac_addr - revert the bnx2x_set_fw_mac_addr(). + * + * @fw_hi: + * @fw_mid: + * @fw_lo: + * @mac: + */ +static inline void bnx2x_get_fw_mac_addr(__le16 *fw_hi, __le16 *fw_mid, + __le16 *fw_lo, u8 *mac) +{ + mac[1] = ((u8 *)fw_hi)[0]; + mac[0] = ((u8 *)fw_hi)[1]; + mac[3] = ((u8 *)fw_mid)[0]; + mac[2] = ((u8 *)fw_mid)[1]; + mac[5] = ((u8 *)fw_lo)[0]; + mac[4] = ((u8 *)fw_lo)[1]; +} + +/** + * bnx2x_mcast_refresh_registry_e1 - + * + * @bp: device handle + * @cnt: + * + * Check the ramrod data first entry flag to see if it's a DELETE or ADD command + * and update the registry correspondingly: if ADD - allocate a memory and add + * the entries to the registry (list), if DELETE - clear the registry and free + * the memory. + */ +static inline int bnx2x_mcast_refresh_registry_e1(struct bnx2x *bp, + struct bnx2x_mcast_obj *o) +{ + struct bnx2x_raw_obj *raw = &o->raw; + struct bnx2x_mcast_mac_elem *elem; + struct mac_configuration_cmd *data = + (struct mac_configuration_cmd *)(raw->rdata); + + /* If first entry contains a SET bit - the command was ADD, + * otherwise - DEL_ALL + */ + if (GET_FLAG(data->config_table[0].flags, + MAC_CONFIGURATION_ENTRY_ACTION_TYPE)) { + int i, len = data->hdr.length; + + /* Break if it was a RESTORE command */ + if (!list_empty(&o->registry.exact_match.macs)) + return 0; + + elem = kzalloc(sizeof(*elem)*len, GFP_ATOMIC); + if (!elem) { + BNX2X_ERR("Failed to allocate registry memory\n"); + return -ENOMEM; + } + + for (i = 0; i < len; i++, elem++) { + bnx2x_get_fw_mac_addr( + &data->config_table[i].msb_mac_addr, + &data->config_table[i].middle_mac_addr, + &data->config_table[i].lsb_mac_addr, + elem->mac); + DP(BNX2X_MSG_SP, "Adding registry entry for [" + BNX2X_MAC_FMT"]\n", + BNX2X_MAC_PRN_LIST(elem->mac)); + list_add_tail(&elem->link, + &o->registry.exact_match.macs); + } + } else { + elem = list_first_entry(&o->registry.exact_match.macs, + struct bnx2x_mcast_mac_elem, link); + DP(BNX2X_MSG_SP, "Deleting a registry\n"); + kfree(elem); + INIT_LIST_HEAD(&o->registry.exact_match.macs); + } + + return 0; +} + +static int bnx2x_mcast_setup_e1(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + int cmd) +{ + struct bnx2x_mcast_obj *o = p->mcast_obj; + struct bnx2x_raw_obj *raw = &o->raw; + struct mac_configuration_cmd *data = + (struct mac_configuration_cmd *)(raw->rdata); + int cnt = 0, i, rc; + + /* Reset the ramrod data buffer */ + memset(data, 0, sizeof(*data)); + + /* First set all entries as invalid */ + for (i = 0; i < o->max_cmd_len ; i++) + SET_FLAG(data->config_table[i].flags, + MAC_CONFIGURATION_ENTRY_ACTION_TYPE, + T_ETH_MAC_COMMAND_INVALIDATE); + + /* Handle pending commands first */ + cnt = bnx2x_mcast_handle_pending_cmds_e1(bp, p); + + /* If there are no more pending commands - clear SCHEDULED state */ + if (list_empty(&o->pending_cmds_head)) + o->clear_sched(o); + + /* The below may be true iff there were no pending commands */ + if (!cnt) + cnt = bnx2x_mcast_handle_current_cmd(bp, p, cmd, 0); + + /* For 57710 every command has o->max_cmd_len length to ensure that + * commands are done one at a time. + */ + o->total_pending_num -= o->max_cmd_len; + + /* send a ramrod */ + + WARN_ON(cnt > o->max_cmd_len); + + /* Set ramrod header (in particular, a number of entries to update) */ + bnx2x_mcast_set_rdata_hdr_e1(bp, p, (u8)cnt); + + /* update a registry: we need the registry contents to be always up + * to date in order to be able to execute a RESTORE opcode. Here + * we use the fact that for 57710 we sent one command at a time + * hence we may take the registry update out of the command handling + * and do it in a simpler way here. + */ + rc = bnx2x_mcast_refresh_registry_e1(bp, o); + if (rc) + return rc; + + /* + * If CLEAR_ONLY was requested - don't send a ramrod and clear + * RAMROD_PENDING status immediately. + */ + if (test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) { + raw->clear_pending(raw); + return 0; + } else { + /* + * No need for an explicit memory barrier here as long we would + * need to ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read and we will have to put a full memory barrier there + * (inside bnx2x_sp_post()). + */ + + /* Send a ramrod */ + rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, raw->cid, + U64_HI(raw->rdata_mapping), + U64_LO(raw->rdata_mapping), + ETH_CONNECTION_TYPE); + if (rc) + return rc; + + /* Ramrod completion is pending */ + return 1; + } + +} + +static int bnx2x_mcast_get_registry_size_exact(struct bnx2x_mcast_obj *o) +{ + return o->registry.exact_match.num_macs_set; +} + +static int bnx2x_mcast_get_registry_size_aprox(struct bnx2x_mcast_obj *o) +{ + return o->registry.aprox_match.num_bins_set; +} + +static void bnx2x_mcast_set_registry_size_exact(struct bnx2x_mcast_obj *o, + int n) +{ + o->registry.exact_match.num_macs_set = n; +} + +static void bnx2x_mcast_set_registry_size_aprox(struct bnx2x_mcast_obj *o, + int n) +{ + o->registry.aprox_match.num_bins_set = n; +} + +int bnx2x_config_mcast(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + int cmd) +{ + struct bnx2x_mcast_obj *o = p->mcast_obj; + struct bnx2x_raw_obj *r = &o->raw; + int rc = 0, old_reg_size; + + /* This is needed to recover number of currently configured mcast macs + * in case of failure. + */ + old_reg_size = o->get_registry_size(o); + + /* Do some calculations and checks */ + rc = o->validate(bp, p, cmd); + if (rc) + return rc; + + /* Return if there is no work to do */ + if ((!p->mcast_list_len) && (!o->check_sched(o))) + return 0; + + DP(BNX2X_MSG_SP, "o->total_pending_num=%d p->mcast_list_len=%d " + "o->max_cmd_len=%d\n", o->total_pending_num, + p->mcast_list_len, o->max_cmd_len); + + /* Enqueue the current command to the pending list if we can't complete + * it in the current iteration + */ + if (r->check_pending(r) || + ((o->max_cmd_len > 0) && (o->total_pending_num > o->max_cmd_len))) { + rc = o->enqueue_cmd(bp, p->mcast_obj, p, cmd); + if (rc < 0) + goto error_exit1; + + /* As long as the current command is in a command list we + * don't need to handle it separately. + */ + p->mcast_list_len = 0; + } + + if (!r->check_pending(r)) { + + /* Set 'pending' state */ + r->set_pending(r); + + /* Configure the new classification in the chip */ + rc = o->config_mcast(bp, p, cmd); + if (rc < 0) + goto error_exit2; + + /* Wait for a ramrod completion if was requested */ + if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags)) + rc = o->wait_comp(bp, o); + } + + return rc; + +error_exit2: + r->clear_pending(r); + +error_exit1: + o->revert(bp, p, old_reg_size); + + return rc; +} + +static void bnx2x_mcast_clear_sched(struct bnx2x_mcast_obj *o) +{ + smp_mb__before_clear_bit(); + clear_bit(o->sched_state, o->raw.pstate); + smp_mb__after_clear_bit(); +} + +static void bnx2x_mcast_set_sched(struct bnx2x_mcast_obj *o) +{ + smp_mb__before_clear_bit(); + set_bit(o->sched_state, o->raw.pstate); + smp_mb__after_clear_bit(); +} + +static bool bnx2x_mcast_check_sched(struct bnx2x_mcast_obj *o) +{ + return !!test_bit(o->sched_state, o->raw.pstate); +} + +static bool bnx2x_mcast_check_pending(struct bnx2x_mcast_obj *o) +{ + return o->raw.check_pending(&o->raw) || o->check_sched(o); +} + +void bnx2x_init_mcast_obj(struct bnx2x *bp, + struct bnx2x_mcast_obj *mcast_obj, + u8 mcast_cl_id, u32 mcast_cid, u8 func_id, + u8 engine_id, void *rdata, dma_addr_t rdata_mapping, + int state, unsigned long *pstate, bnx2x_obj_type type) +{ + memset(mcast_obj, 0, sizeof(*mcast_obj)); + + bnx2x_init_raw_obj(&mcast_obj->raw, mcast_cl_id, mcast_cid, func_id, + rdata, rdata_mapping, state, pstate, type); + + mcast_obj->engine_id = engine_id; + + INIT_LIST_HEAD(&mcast_obj->pending_cmds_head); + + mcast_obj->sched_state = BNX2X_FILTER_MCAST_SCHED; + mcast_obj->check_sched = bnx2x_mcast_check_sched; + mcast_obj->set_sched = bnx2x_mcast_set_sched; + mcast_obj->clear_sched = bnx2x_mcast_clear_sched; + + if (CHIP_IS_E1(bp)) { + mcast_obj->config_mcast = bnx2x_mcast_setup_e1; + mcast_obj->enqueue_cmd = bnx2x_mcast_enqueue_cmd; + mcast_obj->hdl_restore = + bnx2x_mcast_handle_restore_cmd_e1; + mcast_obj->check_pending = bnx2x_mcast_check_pending; + + if (CHIP_REV_IS_SLOW(bp)) + mcast_obj->max_cmd_len = BNX2X_MAX_EMUL_MULTI; + else + mcast_obj->max_cmd_len = BNX2X_MAX_MULTICAST; + + mcast_obj->wait_comp = bnx2x_mcast_wait; + mcast_obj->set_one_rule = bnx2x_mcast_set_one_rule_e1; + mcast_obj->validate = bnx2x_mcast_validate_e1; + mcast_obj->revert = bnx2x_mcast_revert_e1; + mcast_obj->get_registry_size = + bnx2x_mcast_get_registry_size_exact; + mcast_obj->set_registry_size = + bnx2x_mcast_set_registry_size_exact; + + /* 57710 is the only chip that uses the exact match for mcast + * at the moment. + */ + INIT_LIST_HEAD(&mcast_obj->registry.exact_match.macs); + + } else if (CHIP_IS_E1H(bp)) { + mcast_obj->config_mcast = bnx2x_mcast_setup_e1h; + mcast_obj->enqueue_cmd = NULL; + mcast_obj->hdl_restore = NULL; + mcast_obj->check_pending = bnx2x_mcast_check_pending; + + /* 57711 doesn't send a ramrod, so it has unlimited credit + * for one command. + */ + mcast_obj->max_cmd_len = -1; + mcast_obj->wait_comp = bnx2x_mcast_wait; + mcast_obj->set_one_rule = NULL; + mcast_obj->validate = bnx2x_mcast_validate_e1h; + mcast_obj->revert = bnx2x_mcast_revert_e1h; + mcast_obj->get_registry_size = + bnx2x_mcast_get_registry_size_aprox; + mcast_obj->set_registry_size = + bnx2x_mcast_set_registry_size_aprox; + } else { + mcast_obj->config_mcast = bnx2x_mcast_setup_e2; + mcast_obj->enqueue_cmd = bnx2x_mcast_enqueue_cmd; + mcast_obj->hdl_restore = + bnx2x_mcast_handle_restore_cmd_e2; + mcast_obj->check_pending = bnx2x_mcast_check_pending; + /* TODO: There should be a proper HSI define for this number!!! + */ + mcast_obj->max_cmd_len = 16; + mcast_obj->wait_comp = bnx2x_mcast_wait; + mcast_obj->set_one_rule = bnx2x_mcast_set_one_rule_e2; + mcast_obj->validate = bnx2x_mcast_validate_e2; + mcast_obj->revert = bnx2x_mcast_revert_e2; + mcast_obj->get_registry_size = + bnx2x_mcast_get_registry_size_aprox; + mcast_obj->set_registry_size = + bnx2x_mcast_set_registry_size_aprox; + } +} + +/*************************** Credit handling **********************************/ + +/** + * atomic_add_ifless - add if the result is less than a given value. + * + * @v: pointer of type atomic_t + * @a: the amount to add to v... + * @u: ...if (v + a) is less than u. + * + * returns true if (v + a) was less than u, and false otherwise. + * + */ +static inline bool __atomic_add_ifless(atomic_t *v, int a, int u) +{ + int c, old; + + c = atomic_read(v); + for (;;) { + if (unlikely(c + a >= u)) + return false; + + old = atomic_cmpxchg((v), c, c + a); + if (likely(old == c)) + break; + c = old; + } + + return true; +} + +/** + * atomic_dec_ifmoe - dec if the result is more or equal than a given value. + * + * @v: pointer of type atomic_t + * @a: the amount to dec from v... + * @u: ...if (v - a) is more or equal than u. + * + * returns true if (v - a) was more or equal than u, and false + * otherwise. + */ +static inline bool __atomic_dec_ifmoe(atomic_t *v, int a, int u) +{ + int c, old; + + c = atomic_read(v); + for (;;) { + if (unlikely(c - a < u)) + return false; + + old = atomic_cmpxchg((v), c, c - a); + if (likely(old == c)) + break; + c = old; + } + + return true; +} + +static bool bnx2x_credit_pool_get(struct bnx2x_credit_pool_obj *o, int cnt) +{ + bool rc; + + smp_mb(); + rc = __atomic_dec_ifmoe(&o->credit, cnt, 0); + smp_mb(); + + return rc; +} + +static bool bnx2x_credit_pool_put(struct bnx2x_credit_pool_obj *o, int cnt) +{ + bool rc; + + smp_mb(); + + /* Don't let to refill if credit + cnt > pool_sz */ + rc = __atomic_add_ifless(&o->credit, cnt, o->pool_sz + 1); + + smp_mb(); + + return rc; +} + +static int bnx2x_credit_pool_check(struct bnx2x_credit_pool_obj *o) +{ + int cur_credit; + + smp_mb(); + cur_credit = atomic_read(&o->credit); + + return cur_credit; +} + +static bool bnx2x_credit_pool_always_true(struct bnx2x_credit_pool_obj *o, + int cnt) +{ + return true; +} + + +static bool bnx2x_credit_pool_get_entry( + struct bnx2x_credit_pool_obj *o, + int *offset) +{ + int idx, vec, i; + + *offset = -1; + + /* Find "internal cam-offset" then add to base for this object... */ + for (vec = 0; vec < BNX2X_POOL_VEC_SIZE; vec++) { + + /* Skip the current vector if there are no free entries in it */ + if (!o->pool_mirror[vec]) + continue; + + /* If we've got here we are going to find a free entry */ + for (idx = vec * BNX2X_POOL_VEC_SIZE, i = 0; + i < BIT_VEC64_ELEM_SZ; idx++, i++) + + if (BIT_VEC64_TEST_BIT(o->pool_mirror, idx)) { + /* Got one!! */ + BIT_VEC64_CLEAR_BIT(o->pool_mirror, idx); + *offset = o->base_pool_offset + idx; + return true; + } + } + + return false; +} + +static bool bnx2x_credit_pool_put_entry( + struct bnx2x_credit_pool_obj *o, + int offset) +{ + if (offset < o->base_pool_offset) + return false; + + offset -= o->base_pool_offset; + + if (offset >= o->pool_sz) + return false; + + /* Return the entry to the pool */ + BIT_VEC64_SET_BIT(o->pool_mirror, offset); + + return true; +} + +static bool bnx2x_credit_pool_put_entry_always_true( + struct bnx2x_credit_pool_obj *o, + int offset) +{ + return true; +} + +static bool bnx2x_credit_pool_get_entry_always_true( + struct bnx2x_credit_pool_obj *o, + int *offset) +{ + *offset = -1; + return true; +} +/** + * bnx2x_init_credit_pool - initialize credit pool internals. + * + * @p: + * @base: Base entry in the CAM to use. + * @credit: pool size. + * + * If base is negative no CAM entries handling will be performed. + * If credit is negative pool operations will always succeed (unlimited pool). + * + */ +static inline void bnx2x_init_credit_pool(struct bnx2x_credit_pool_obj *p, + int base, int credit) +{ + /* Zero the object first */ + memset(p, 0, sizeof(*p)); + + /* Set the table to all 1s */ + memset(&p->pool_mirror, 0xff, sizeof(p->pool_mirror)); + + /* Init a pool as full */ + atomic_set(&p->credit, credit); + + /* The total poll size */ + p->pool_sz = credit; + + p->base_pool_offset = base; + + /* Commit the change */ + smp_mb(); + + p->check = bnx2x_credit_pool_check; + + /* if pool credit is negative - disable the checks */ + if (credit >= 0) { + p->put = bnx2x_credit_pool_put; + p->get = bnx2x_credit_pool_get; + p->put_entry = bnx2x_credit_pool_put_entry; + p->get_entry = bnx2x_credit_pool_get_entry; + } else { + p->put = bnx2x_credit_pool_always_true; + p->get = bnx2x_credit_pool_always_true; + p->put_entry = bnx2x_credit_pool_put_entry_always_true; + p->get_entry = bnx2x_credit_pool_get_entry_always_true; + } + + /* If base is negative - disable entries handling */ + if (base < 0) { + p->put_entry = bnx2x_credit_pool_put_entry_always_true; + p->get_entry = bnx2x_credit_pool_get_entry_always_true; + } +} + +void bnx2x_init_mac_credit_pool(struct bnx2x *bp, + struct bnx2x_credit_pool_obj *p, u8 func_id, + u8 func_num) +{ +/* TODO: this will be defined in consts as well... */ +#define BNX2X_CAM_SIZE_EMUL 5 + + int cam_sz; + + if (CHIP_IS_E1(bp)) { + /* In E1, Multicast is saved in cam... */ + if (!CHIP_REV_IS_SLOW(bp)) + cam_sz = (MAX_MAC_CREDIT_E1 / 2) - BNX2X_MAX_MULTICAST; + else + cam_sz = BNX2X_CAM_SIZE_EMUL - BNX2X_MAX_EMUL_MULTI; + + bnx2x_init_credit_pool(p, func_id * cam_sz, cam_sz); + + } else if (CHIP_IS_E1H(bp)) { + /* CAM credit is equaly divided between all active functions + * on the PORT!. + */ + if ((func_num > 0)) { + if (!CHIP_REV_IS_SLOW(bp)) + cam_sz = (MAX_MAC_CREDIT_E1H / (2*func_num)); + else + cam_sz = BNX2X_CAM_SIZE_EMUL; + bnx2x_init_credit_pool(p, func_id * cam_sz, cam_sz); + } else { + /* this should never happen! Block MAC operations. */ + bnx2x_init_credit_pool(p, 0, 0); + } + + } else { + + /* + * CAM credit is equaly divided between all active functions + * on the PATH. + */ + if ((func_num > 0)) { + if (!CHIP_REV_IS_SLOW(bp)) + cam_sz = (MAX_MAC_CREDIT_E2 / func_num); + else + cam_sz = BNX2X_CAM_SIZE_EMUL; + + /* + * No need for CAM entries handling for 57712 and + * newer. + */ + bnx2x_init_credit_pool(p, -1, cam_sz); + } else { + /* this should never happen! Block MAC operations. */ + bnx2x_init_credit_pool(p, 0, 0); + } + + } +} + +void bnx2x_init_vlan_credit_pool(struct bnx2x *bp, + struct bnx2x_credit_pool_obj *p, + u8 func_id, + u8 func_num) +{ + if (CHIP_IS_E1x(bp)) { + /* + * There is no VLAN credit in HW on 57710 and 57711 only + * MAC / MAC-VLAN can be set + */ + bnx2x_init_credit_pool(p, 0, -1); + } else { + /* + * CAM credit is equaly divided between all active functions + * on the PATH. + */ + if (func_num > 0) { + int credit = MAX_VLAN_CREDIT_E2 / func_num; + bnx2x_init_credit_pool(p, func_id * credit, credit); + } else + /* this should never happen! Block VLAN operations. */ + bnx2x_init_credit_pool(p, 0, 0); + } +} + +/****************** RSS Configuration ******************/ +/** + * bnx2x_debug_print_ind_table - prints the indirection table configuration. + * + * @bp: driver hanlde + * @p: pointer to rss configuration + * + * Prints it when NETIF_MSG_IFUP debug level is configured. + */ +static inline void bnx2x_debug_print_ind_table(struct bnx2x *bp, + struct bnx2x_config_rss_params *p) +{ + int i; + + DP(BNX2X_MSG_SP, "Setting indirection table to:\n"); + DP(BNX2X_MSG_SP, "0x0000: "); + for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { + DP_CONT(BNX2X_MSG_SP, "0x%02x ", p->ind_table[i]); + + /* Print 4 bytes in a line */ + if ((i + 1 < T_ETH_INDIRECTION_TABLE_SIZE) && + (((i + 1) & 0x3) == 0)) { + DP_CONT(BNX2X_MSG_SP, "\n"); + DP(BNX2X_MSG_SP, "0x%04x: ", i + 1); + } + } + + DP_CONT(BNX2X_MSG_SP, "\n"); +} + +/** + * bnx2x_setup_rss - configure RSS + * + * @bp: device handle + * @p: rss configuration + * + * sends on UPDATE ramrod for that matter. + */ +static int bnx2x_setup_rss(struct bnx2x *bp, + struct bnx2x_config_rss_params *p) +{ + struct bnx2x_rss_config_obj *o = p->rss_obj; + struct bnx2x_raw_obj *r = &o->raw; + struct eth_rss_update_ramrod_data *data = + (struct eth_rss_update_ramrod_data *)(r->rdata); + u8 rss_mode = 0; + int rc; + + memset(data, 0, sizeof(*data)); + + DP(BNX2X_MSG_SP, "Configuring RSS\n"); + + /* Set an echo field */ + data->echo = (r->cid & BNX2X_SWCID_MASK) | + (r->state << BNX2X_SWCID_SHIFT); + + /* RSS mode */ + if (test_bit(BNX2X_RSS_MODE_DISABLED, &p->rss_flags)) + rss_mode = ETH_RSS_MODE_DISABLED; + else if (test_bit(BNX2X_RSS_MODE_REGULAR, &p->rss_flags)) + rss_mode = ETH_RSS_MODE_REGULAR; + else if (test_bit(BNX2X_RSS_MODE_VLAN_PRI, &p->rss_flags)) + rss_mode = ETH_RSS_MODE_VLAN_PRI; + else if (test_bit(BNX2X_RSS_MODE_E1HOV_PRI, &p->rss_flags)) + rss_mode = ETH_RSS_MODE_E1HOV_PRI; + else if (test_bit(BNX2X_RSS_MODE_IP_DSCP, &p->rss_flags)) + rss_mode = ETH_RSS_MODE_IP_DSCP; + + data->rss_mode = rss_mode; + + DP(BNX2X_MSG_SP, "rss_mode=%d\n", rss_mode); + + /* RSS capabilities */ + if (test_bit(BNX2X_RSS_IPV4, &p->rss_flags)) + data->capabilities |= + ETH_RSS_UPDATE_RAMROD_DATA_IPV4_CAPABILITY; + + if (test_bit(BNX2X_RSS_IPV4_TCP, &p->rss_flags)) + data->capabilities |= + ETH_RSS_UPDATE_RAMROD_DATA_IPV4_TCP_CAPABILITY; + + if (test_bit(BNX2X_RSS_IPV6, &p->rss_flags)) + data->capabilities |= + ETH_RSS_UPDATE_RAMROD_DATA_IPV6_CAPABILITY; + + if (test_bit(BNX2X_RSS_IPV6_TCP, &p->rss_flags)) + data->capabilities |= + ETH_RSS_UPDATE_RAMROD_DATA_IPV6_TCP_CAPABILITY; + + /* Hashing mask */ + data->rss_result_mask = p->rss_result_mask; + + /* RSS engine ID */ + data->rss_engine_id = o->engine_id; + + DP(BNX2X_MSG_SP, "rss_engine_id=%d\n", data->rss_engine_id); + + /* Indirection table */ + memcpy(data->indirection_table, p->ind_table, + T_ETH_INDIRECTION_TABLE_SIZE); + + /* Remember the last configuration */ + memcpy(o->ind_table, p->ind_table, T_ETH_INDIRECTION_TABLE_SIZE); + + /* Print the indirection table */ + if (netif_msg_ifup(bp)) + bnx2x_debug_print_ind_table(bp, p); + + /* RSS keys */ + if (test_bit(BNX2X_RSS_SET_SRCH, &p->rss_flags)) { + memcpy(&data->rss_key[0], &p->rss_key[0], + sizeof(data->rss_key)); + data->capabilities |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY; + } + + /* + * No need for an explicit memory barrier here as long we would + * need to ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read and we will have to put a full memory barrier there + * (inside bnx2x_sp_post()). + */ + + /* Send a ramrod */ + rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_RSS_UPDATE, r->cid, + U64_HI(r->rdata_mapping), + U64_LO(r->rdata_mapping), + ETH_CONNECTION_TYPE); + + if (rc < 0) + return rc; + + return 1; +} + +void bnx2x_get_rss_ind_table(struct bnx2x_rss_config_obj *rss_obj, + u8 *ind_table) +{ + memcpy(ind_table, rss_obj->ind_table, sizeof(rss_obj->ind_table)); +} + +int bnx2x_config_rss(struct bnx2x *bp, + struct bnx2x_config_rss_params *p) +{ + int rc; + struct bnx2x_rss_config_obj *o = p->rss_obj; + struct bnx2x_raw_obj *r = &o->raw; + + /* Do nothing if only driver cleanup was requested */ + if (test_bit(RAMROD_DRV_CLR_ONLY, &p->ramrod_flags)) + return 0; + + r->set_pending(r); + + rc = o->config_rss(bp, p); + if (rc < 0) { + r->clear_pending(r); + return rc; + } + + if (test_bit(RAMROD_COMP_WAIT, &p->ramrod_flags)) + rc = r->wait_comp(bp, r); + + return rc; +} + + +void bnx2x_init_rss_config_obj(struct bnx2x *bp, + struct bnx2x_rss_config_obj *rss_obj, + u8 cl_id, u32 cid, u8 func_id, u8 engine_id, + void *rdata, dma_addr_t rdata_mapping, + int state, unsigned long *pstate, + bnx2x_obj_type type) +{ + bnx2x_init_raw_obj(&rss_obj->raw, cl_id, cid, func_id, rdata, + rdata_mapping, state, pstate, type); + + rss_obj->engine_id = engine_id; + rss_obj->config_rss = bnx2x_setup_rss; +} + +/********************** Queue state object ***********************************/ + +/** + * bnx2x_queue_state_change - perform Queue state change transition + * + * @bp: device handle + * @params: parameters to perform the transition + * + * returns 0 in case of successfully completed transition, negative error + * code in case of failure, positive (EBUSY) value if there is a completion + * to that is still pending (possible only if RAMROD_COMP_WAIT is + * not set in params->ramrod_flags for asynchronous commands). + * + */ +int bnx2x_queue_state_change(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_sp_obj *o = params->q_obj; + int rc, pending_bit; + unsigned long *pending = &o->pending; + + /* Check that the requested transition is legal */ + if (o->check_transition(bp, o, params)) + return -EINVAL; + + /* Set "pending" bit */ + pending_bit = o->set_pending(o, params); + + /* Don't send a command if only driver cleanup was requested */ + if (test_bit(RAMROD_DRV_CLR_ONLY, ¶ms->ramrod_flags)) + o->complete_cmd(bp, o, pending_bit); + else { + /* Send a ramrod */ + rc = o->send_cmd(bp, params); + if (rc) { + o->next_state = BNX2X_Q_STATE_MAX; + clear_bit(pending_bit, pending); + smp_mb__after_clear_bit(); + return rc; + } + + if (test_bit(RAMROD_COMP_WAIT, ¶ms->ramrod_flags)) { + rc = o->wait_comp(bp, o, pending_bit); + if (rc) + return rc; + + return 0; + } + } + + return !!test_bit(pending_bit, pending); +} + + +static int bnx2x_queue_set_pending(struct bnx2x_queue_sp_obj *obj, + struct bnx2x_queue_state_params *params) +{ + enum bnx2x_queue_cmd cmd = params->cmd, bit; + + /* ACTIVATE and DEACTIVATE commands are implemented on top of + * UPDATE command. + */ + if ((cmd == BNX2X_Q_CMD_ACTIVATE) || + (cmd == BNX2X_Q_CMD_DEACTIVATE)) + bit = BNX2X_Q_CMD_UPDATE; + else + bit = cmd; + + set_bit(bit, &obj->pending); + return bit; +} + +static int bnx2x_queue_wait_comp(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *o, + enum bnx2x_queue_cmd cmd) +{ + return bnx2x_state_wait(bp, cmd, &o->pending); +} + +/** + * bnx2x_queue_comp_cmd - complete the state change command. + * + * @bp: device handle + * @o: + * @cmd: + * + * Checks that the arrived completion is expected. + */ +static int bnx2x_queue_comp_cmd(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *o, + enum bnx2x_queue_cmd cmd) +{ + unsigned long cur_pending = o->pending; + + if (!test_and_clear_bit(cmd, &cur_pending)) { + BNX2X_ERR("Bad MC reply %d for queue %d in state %d " + "pending 0x%lx, next_state %d\n", cmd, + o->cids[BNX2X_PRIMARY_CID_INDEX], + o->state, cur_pending, o->next_state); + return -EINVAL; + } + + if (o->next_tx_only >= o->max_cos) + /* >= becuase tx only must always be smaller than cos since the + * primary connection suports COS 0 + */ + BNX2X_ERR("illegal value for next tx_only: %d. max cos was %d", + o->next_tx_only, o->max_cos); + + DP(BNX2X_MSG_SP, "Completing command %d for queue %d, " + "setting state to %d\n", cmd, + o->cids[BNX2X_PRIMARY_CID_INDEX], o->next_state); + + if (o->next_tx_only) /* print num tx-only if any exist */ + DP(BNX2X_MSG_SP, "primary cid %d: num tx-only cons %d", + o->cids[BNX2X_PRIMARY_CID_INDEX], o->next_tx_only); + + o->state = o->next_state; + o->num_tx_only = o->next_tx_only; + o->next_state = BNX2X_Q_STATE_MAX; + + /* It's important that o->state and o->next_state are + * updated before o->pending. + */ + wmb(); + + clear_bit(cmd, &o->pending); + smp_mb__after_clear_bit(); + + return 0; +} + +static void bnx2x_q_fill_setup_data_e2(struct bnx2x *bp, + struct bnx2x_queue_state_params *cmd_params, + struct client_init_ramrod_data *data) +{ + struct bnx2x_queue_setup_params *params = &cmd_params->params.setup; + + /* Rx data */ + + /* IPv6 TPA supported for E2 and above only */ + data->rx.tpa_en |= test_bit(BNX2X_Q_FLG_TPA_IPV6, ¶ms->flags) * + CLIENT_INIT_RX_DATA_TPA_EN_IPV6; +} + +static void bnx2x_q_fill_init_general_data(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *o, + struct bnx2x_general_setup_params *params, + struct client_init_general_data *gen_data, + unsigned long *flags) +{ + gen_data->client_id = o->cl_id; + + if (test_bit(BNX2X_Q_FLG_STATS, flags)) { + gen_data->statistics_counter_id = + params->stat_id; + gen_data->statistics_en_flg = 1; + gen_data->statistics_zero_flg = + test_bit(BNX2X_Q_FLG_ZERO_STATS, flags); + } else + gen_data->statistics_counter_id = + DISABLE_STATISTIC_COUNTER_ID_VALUE; + + gen_data->is_fcoe_flg = test_bit(BNX2X_Q_FLG_FCOE, flags); + gen_data->activate_flg = test_bit(BNX2X_Q_FLG_ACTIVE, flags); + gen_data->sp_client_id = params->spcl_id; + gen_data->mtu = cpu_to_le16(params->mtu); + gen_data->func_id = o->func_id; + + + gen_data->cos = params->cos; + + gen_data->traffic_type = + test_bit(BNX2X_Q_FLG_FCOE, flags) ? + LLFC_TRAFFIC_TYPE_FCOE : LLFC_TRAFFIC_TYPE_NW; + + DP(BNX2X_MSG_SP, "flags: active %d, cos %d, stats en %d", + gen_data->activate_flg, gen_data->cos, gen_data->statistics_en_flg); +} + +static void bnx2x_q_fill_init_tx_data(struct bnx2x_queue_sp_obj *o, + struct bnx2x_txq_setup_params *params, + struct client_init_tx_data *tx_data, + unsigned long *flags) +{ + tx_data->enforce_security_flg = + test_bit(BNX2X_Q_FLG_TX_SEC, flags); + tx_data->default_vlan = + cpu_to_le16(params->default_vlan); + tx_data->default_vlan_flg = + test_bit(BNX2X_Q_FLG_DEF_VLAN, flags); + tx_data->tx_switching_flg = + test_bit(BNX2X_Q_FLG_TX_SWITCH, flags); + tx_data->anti_spoofing_flg = + test_bit(BNX2X_Q_FLG_ANTI_SPOOF, flags); + tx_data->tx_status_block_id = params->fw_sb_id; + tx_data->tx_sb_index_number = params->sb_cq_index; + tx_data->tss_leading_client_id = params->tss_leading_cl_id; + + tx_data->tx_bd_page_base.lo = + cpu_to_le32(U64_LO(params->dscr_map)); + tx_data->tx_bd_page_base.hi = + cpu_to_le32(U64_HI(params->dscr_map)); + + /* Don't configure any Tx switching mode during queue SETUP */ + tx_data->state = 0; +} + +static void bnx2x_q_fill_init_pause_data(struct bnx2x_queue_sp_obj *o, + struct rxq_pause_params *params, + struct client_init_rx_data *rx_data) +{ + /* flow control data */ + rx_data->cqe_pause_thr_low = cpu_to_le16(params->rcq_th_lo); + rx_data->cqe_pause_thr_high = cpu_to_le16(params->rcq_th_hi); + rx_data->bd_pause_thr_low = cpu_to_le16(params->bd_th_lo); + rx_data->bd_pause_thr_high = cpu_to_le16(params->bd_th_hi); + rx_data->sge_pause_thr_low = cpu_to_le16(params->sge_th_lo); + rx_data->sge_pause_thr_high = cpu_to_le16(params->sge_th_hi); + rx_data->rx_cos_mask = cpu_to_le16(params->pri_map); +} + +static void bnx2x_q_fill_init_rx_data(struct bnx2x_queue_sp_obj *o, + struct bnx2x_rxq_setup_params *params, + struct client_init_rx_data *rx_data, + unsigned long *flags) +{ + /* Rx data */ + rx_data->tpa_en = test_bit(BNX2X_Q_FLG_TPA, flags) * + CLIENT_INIT_RX_DATA_TPA_EN_IPV4; + rx_data->vmqueue_mode_en_flg = 0; + + rx_data->cache_line_alignment_log_size = + params->cache_line_log; + rx_data->enable_dynamic_hc = + test_bit(BNX2X_Q_FLG_DHC, flags); + rx_data->max_sges_for_packet = params->max_sges_pkt; + rx_data->client_qzone_id = params->cl_qzone_id; + rx_data->max_agg_size = cpu_to_le16(params->tpa_agg_sz); + + /* Always start in DROP_ALL mode */ + rx_data->state = cpu_to_le16(CLIENT_INIT_RX_DATA_UCAST_DROP_ALL | + CLIENT_INIT_RX_DATA_MCAST_DROP_ALL); + + /* We don't set drop flags */ + rx_data->drop_ip_cs_err_flg = 0; + rx_data->drop_tcp_cs_err_flg = 0; + rx_data->drop_ttl0_flg = 0; + rx_data->drop_udp_cs_err_flg = 0; + rx_data->inner_vlan_removal_enable_flg = + test_bit(BNX2X_Q_FLG_VLAN, flags); + rx_data->outer_vlan_removal_enable_flg = + test_bit(BNX2X_Q_FLG_OV, flags); + rx_data->status_block_id = params->fw_sb_id; + rx_data->rx_sb_index_number = params->sb_cq_index; + rx_data->max_tpa_queues = params->max_tpa_queues; + rx_data->max_bytes_on_bd = cpu_to_le16(params->buf_sz); + rx_data->sge_buff_size = cpu_to_le16(params->sge_buf_sz); + rx_data->bd_page_base.lo = + cpu_to_le32(U64_LO(params->dscr_map)); + rx_data->bd_page_base.hi = + cpu_to_le32(U64_HI(params->dscr_map)); + rx_data->sge_page_base.lo = + cpu_to_le32(U64_LO(params->sge_map)); + rx_data->sge_page_base.hi = + cpu_to_le32(U64_HI(params->sge_map)); + rx_data->cqe_page_base.lo = + cpu_to_le32(U64_LO(params->rcq_map)); + rx_data->cqe_page_base.hi = + cpu_to_le32(U64_HI(params->rcq_map)); + rx_data->is_leading_rss = test_bit(BNX2X_Q_FLG_LEADING_RSS, flags); + + if (test_bit(BNX2X_Q_FLG_MCAST, flags)) { + rx_data->approx_mcast_engine_id = o->func_id; + rx_data->is_approx_mcast = 1; + } + + rx_data->rss_engine_id = params->rss_engine_id; + + /* silent vlan removal */ + rx_data->silent_vlan_removal_flg = + test_bit(BNX2X_Q_FLG_SILENT_VLAN_REM, flags); + rx_data->silent_vlan_value = + cpu_to_le16(params->silent_removal_value); + rx_data->silent_vlan_mask = + cpu_to_le16(params->silent_removal_mask); + +} + +/* initialize the general, tx and rx parts of a queue object */ +static void bnx2x_q_fill_setup_data_cmn(struct bnx2x *bp, + struct bnx2x_queue_state_params *cmd_params, + struct client_init_ramrod_data *data) +{ + bnx2x_q_fill_init_general_data(bp, cmd_params->q_obj, + &cmd_params->params.setup.gen_params, + &data->general, + &cmd_params->params.setup.flags); + + bnx2x_q_fill_init_tx_data(cmd_params->q_obj, + &cmd_params->params.setup.txq_params, + &data->tx, + &cmd_params->params.setup.flags); + + bnx2x_q_fill_init_rx_data(cmd_params->q_obj, + &cmd_params->params.setup.rxq_params, + &data->rx, + &cmd_params->params.setup.flags); + + bnx2x_q_fill_init_pause_data(cmd_params->q_obj, + &cmd_params->params.setup.pause_params, + &data->rx); +} + +/* initialize the general and tx parts of a tx-only queue object */ +static void bnx2x_q_fill_setup_tx_only(struct bnx2x *bp, + struct bnx2x_queue_state_params *cmd_params, + struct tx_queue_init_ramrod_data *data) +{ + bnx2x_q_fill_init_general_data(bp, cmd_params->q_obj, + &cmd_params->params.tx_only.gen_params, + &data->general, + &cmd_params->params.tx_only.flags); + + bnx2x_q_fill_init_tx_data(cmd_params->q_obj, + &cmd_params->params.tx_only.txq_params, + &data->tx, + &cmd_params->params.tx_only.flags); + + DP(BNX2X_MSG_SP, "cid %d, tx bd page lo %x hi %x",cmd_params->q_obj->cids[0], + data->tx.tx_bd_page_base.lo, data->tx.tx_bd_page_base.hi); +} + +/** + * bnx2x_q_init - init HW/FW queue + * + * @bp: device handle + * @params: + * + * HW/FW initial Queue configuration: + * - HC: Rx and Tx + * - CDU context validation + * + */ +static inline int bnx2x_q_init(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_sp_obj *o = params->q_obj; + struct bnx2x_queue_init_params *init = ¶ms->params.init; + u16 hc_usec; + u8 cos; + + /* Tx HC configuration */ + if (test_bit(BNX2X_Q_TYPE_HAS_TX, &o->type) && + test_bit(BNX2X_Q_FLG_HC, &init->tx.flags)) { + hc_usec = init->tx.hc_rate ? 1000000 / init->tx.hc_rate : 0; + + bnx2x_update_coalesce_sb_index(bp, init->tx.fw_sb_id, + init->tx.sb_cq_index, + !test_bit(BNX2X_Q_FLG_HC_EN, &init->tx.flags), + hc_usec); + } + + /* Rx HC configuration */ + if (test_bit(BNX2X_Q_TYPE_HAS_RX, &o->type) && + test_bit(BNX2X_Q_FLG_HC, &init->rx.flags)) { + hc_usec = init->rx.hc_rate ? 1000000 / init->rx.hc_rate : 0; + + bnx2x_update_coalesce_sb_index(bp, init->rx.fw_sb_id, + init->rx.sb_cq_index, + !test_bit(BNX2X_Q_FLG_HC_EN, &init->rx.flags), + hc_usec); + } + + /* Set CDU context validation values */ + for (cos = 0; cos < o->max_cos; cos++) { + DP(BNX2X_MSG_SP, "setting context validation. cid %d, cos %d", + o->cids[cos], cos); + DP(BNX2X_MSG_SP, "context pointer %p", init->cxts[cos]); + bnx2x_set_ctx_validation(bp, init->cxts[cos], o->cids[cos]); + } + + /* As no ramrod is sent, complete the command immediately */ + o->complete_cmd(bp, o, BNX2X_Q_CMD_INIT); + + mmiowb(); + smp_mb(); + + return 0; +} + +static inline int bnx2x_q_send_setup_e1x(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_sp_obj *o = params->q_obj; + struct client_init_ramrod_data *rdata = + (struct client_init_ramrod_data *)o->rdata; + dma_addr_t data_mapping = o->rdata_mapping; + int ramrod = RAMROD_CMD_ID_ETH_CLIENT_SETUP; + + /* Clear the ramrod data */ + memset(rdata, 0, sizeof(*rdata)); + + /* Fill the ramrod data */ + bnx2x_q_fill_setup_data_cmn(bp, params, rdata); + + /* + * No need for an explicit memory barrier here as long we would + * need to ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read and we will have to put a full memory barrier there + * (inside bnx2x_sp_post()). + */ + + return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX], + U64_HI(data_mapping), + U64_LO(data_mapping), ETH_CONNECTION_TYPE); +} + +static inline int bnx2x_q_send_setup_e2(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_sp_obj *o = params->q_obj; + struct client_init_ramrod_data *rdata = + (struct client_init_ramrod_data *)o->rdata; + dma_addr_t data_mapping = o->rdata_mapping; + int ramrod = RAMROD_CMD_ID_ETH_CLIENT_SETUP; + + /* Clear the ramrod data */ + memset(rdata, 0, sizeof(*rdata)); + + /* Fill the ramrod data */ + bnx2x_q_fill_setup_data_cmn(bp, params, rdata); + bnx2x_q_fill_setup_data_e2(bp, params, rdata); + + /* + * No need for an explicit memory barrier here as long we would + * need to ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read and we will have to put a full memory barrier there + * (inside bnx2x_sp_post()). + */ + + return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX], + U64_HI(data_mapping), + U64_LO(data_mapping), ETH_CONNECTION_TYPE); +} + +static inline int bnx2x_q_send_setup_tx_only(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_sp_obj *o = params->q_obj; + struct tx_queue_init_ramrod_data *rdata = + (struct tx_queue_init_ramrod_data *)o->rdata; + dma_addr_t data_mapping = o->rdata_mapping; + int ramrod = RAMROD_CMD_ID_ETH_TX_QUEUE_SETUP; + struct bnx2x_queue_setup_tx_only_params *tx_only_params = + ¶ms->params.tx_only; + u8 cid_index = tx_only_params->cid_index; + + + if (cid_index >= o->max_cos) { + BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n", + o->cl_id, cid_index); + return -EINVAL; + } + + DP(BNX2X_MSG_SP, "parameters received: cos: %d sp-id: %d", + tx_only_params->gen_params.cos, + tx_only_params->gen_params.spcl_id); + + /* Clear the ramrod data */ + memset(rdata, 0, sizeof(*rdata)); + + /* Fill the ramrod data */ + bnx2x_q_fill_setup_tx_only(bp, params, rdata); + + DP(BNX2X_MSG_SP, "sending tx-only ramrod: cid %d, client-id %d," + "sp-client id %d, cos %d", + o->cids[cid_index], + rdata->general.client_id, + rdata->general.sp_client_id, rdata->general.cos); + + /* + * No need for an explicit memory barrier here as long we would + * need to ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read and we will have to put a full memory barrier there + * (inside bnx2x_sp_post()). + */ + + return bnx2x_sp_post(bp, ramrod, o->cids[cid_index], + U64_HI(data_mapping), + U64_LO(data_mapping), ETH_CONNECTION_TYPE); +} + +static void bnx2x_q_fill_update_data(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *obj, + struct bnx2x_queue_update_params *params, + struct client_update_ramrod_data *data) +{ + /* Client ID of the client to update */ + data->client_id = obj->cl_id; + + /* Function ID of the client to update */ + data->func_id = obj->func_id; + + /* Default VLAN value */ + data->default_vlan = cpu_to_le16(params->def_vlan); + + /* Inner VLAN stripping */ + data->inner_vlan_removal_enable_flg = + test_bit(BNX2X_Q_UPDATE_IN_VLAN_REM, ¶ms->update_flags); + data->inner_vlan_removal_change_flg = + test_bit(BNX2X_Q_UPDATE_IN_VLAN_REM_CHNG, + ¶ms->update_flags); + + /* Outer VLAN sripping */ + data->outer_vlan_removal_enable_flg = + test_bit(BNX2X_Q_UPDATE_OUT_VLAN_REM, ¶ms->update_flags); + data->outer_vlan_removal_change_flg = + test_bit(BNX2X_Q_UPDATE_OUT_VLAN_REM_CHNG, + ¶ms->update_flags); + + /* Drop packets that have source MAC that doesn't belong to this + * Queue. + */ + data->anti_spoofing_enable_flg = + test_bit(BNX2X_Q_UPDATE_ANTI_SPOOF, ¶ms->update_flags); + data->anti_spoofing_change_flg = + test_bit(BNX2X_Q_UPDATE_ANTI_SPOOF_CHNG, ¶ms->update_flags); + + /* Activate/Deactivate */ + data->activate_flg = + test_bit(BNX2X_Q_UPDATE_ACTIVATE, ¶ms->update_flags); + data->activate_change_flg = + test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, ¶ms->update_flags); + + /* Enable default VLAN */ + data->default_vlan_enable_flg = + test_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN, ¶ms->update_flags); + data->default_vlan_change_flg = + test_bit(BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG, + ¶ms->update_flags); + + /* silent vlan removal */ + data->silent_vlan_change_flg = + test_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG, + ¶ms->update_flags); + data->silent_vlan_removal_flg = + test_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, ¶ms->update_flags); + data->silent_vlan_value = cpu_to_le16(params->silent_removal_value); + data->silent_vlan_mask = cpu_to_le16(params->silent_removal_mask); +} + +static inline int bnx2x_q_send_update(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_sp_obj *o = params->q_obj; + struct client_update_ramrod_data *rdata = + (struct client_update_ramrod_data *)o->rdata; + dma_addr_t data_mapping = o->rdata_mapping; + struct bnx2x_queue_update_params *update_params = + ¶ms->params.update; + u8 cid_index = update_params->cid_index; + + if (cid_index >= o->max_cos) { + BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n", + o->cl_id, cid_index); + return -EINVAL; + } + + + /* Clear the ramrod data */ + memset(rdata, 0, sizeof(*rdata)); + + /* Fill the ramrod data */ + bnx2x_q_fill_update_data(bp, o, update_params, rdata); + + /* + * No need for an explicit memory barrier here as long we would + * need to ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read and we will have to put a full memory barrier there + * (inside bnx2x_sp_post()). + */ + + return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_UPDATE, + o->cids[cid_index], U64_HI(data_mapping), + U64_LO(data_mapping), ETH_CONNECTION_TYPE); +} + +/** + * bnx2x_q_send_deactivate - send DEACTIVATE command + * + * @bp: device handle + * @params: + * + * implemented using the UPDATE command. + */ +static inline int bnx2x_q_send_deactivate(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_update_params *update = ¶ms->params.update; + + memset(update, 0, sizeof(*update)); + + __set_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, &update->update_flags); + + return bnx2x_q_send_update(bp, params); +} + +/** + * bnx2x_q_send_activate - send ACTIVATE command + * + * @bp: device handle + * @params: + * + * implemented using the UPDATE command. + */ +static inline int bnx2x_q_send_activate(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_update_params *update = ¶ms->params.update; + + memset(update, 0, sizeof(*update)); + + __set_bit(BNX2X_Q_UPDATE_ACTIVATE, &update->update_flags); + __set_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, &update->update_flags); + + return bnx2x_q_send_update(bp, params); +} + +static inline int bnx2x_q_send_update_tpa(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + /* TODO: Not implemented yet. */ + return -1; +} + +static inline int bnx2x_q_send_halt(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_sp_obj *o = params->q_obj; + + return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_HALT, + o->cids[BNX2X_PRIMARY_CID_INDEX], 0, o->cl_id, + ETH_CONNECTION_TYPE); +} + +static inline int bnx2x_q_send_cfc_del(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_sp_obj *o = params->q_obj; + u8 cid_idx = params->params.cfc_del.cid_index; + + if (cid_idx >= o->max_cos) { + BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n", + o->cl_id, cid_idx); + return -EINVAL; + } + + return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_CFC_DEL, + o->cids[cid_idx], 0, 0, NONE_CONNECTION_TYPE); +} + +static inline int bnx2x_q_send_terminate(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_sp_obj *o = params->q_obj; + u8 cid_index = params->params.terminate.cid_index; + + if (cid_index >= o->max_cos) { + BNX2X_ERR("queue[%d]: cid_index (%d) is out of range\n", + o->cl_id, cid_index); + return -EINVAL; + } + + return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_TERMINATE, + o->cids[cid_index], 0, 0, ETH_CONNECTION_TYPE); +} + +static inline int bnx2x_q_send_empty(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + struct bnx2x_queue_sp_obj *o = params->q_obj; + + return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_EMPTY, + o->cids[BNX2X_PRIMARY_CID_INDEX], 0, 0, + ETH_CONNECTION_TYPE); +} + +static inline int bnx2x_queue_send_cmd_cmn(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + switch (params->cmd) { + case BNX2X_Q_CMD_INIT: + return bnx2x_q_init(bp, params); + case BNX2X_Q_CMD_SETUP_TX_ONLY: + return bnx2x_q_send_setup_tx_only(bp, params); + case BNX2X_Q_CMD_DEACTIVATE: + return bnx2x_q_send_deactivate(bp, params); + case BNX2X_Q_CMD_ACTIVATE: + return bnx2x_q_send_activate(bp, params); + case BNX2X_Q_CMD_UPDATE: + return bnx2x_q_send_update(bp, params); + case BNX2X_Q_CMD_UPDATE_TPA: + return bnx2x_q_send_update_tpa(bp, params); + case BNX2X_Q_CMD_HALT: + return bnx2x_q_send_halt(bp, params); + case BNX2X_Q_CMD_CFC_DEL: + return bnx2x_q_send_cfc_del(bp, params); + case BNX2X_Q_CMD_TERMINATE: + return bnx2x_q_send_terminate(bp, params); + case BNX2X_Q_CMD_EMPTY: + return bnx2x_q_send_empty(bp, params); + default: + BNX2X_ERR("Unknown command: %d\n", params->cmd); + return -EINVAL; + } +} + +static int bnx2x_queue_send_cmd_e1x(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + switch (params->cmd) { + case BNX2X_Q_CMD_SETUP: + return bnx2x_q_send_setup_e1x(bp, params); + case BNX2X_Q_CMD_INIT: + case BNX2X_Q_CMD_SETUP_TX_ONLY: + case BNX2X_Q_CMD_DEACTIVATE: + case BNX2X_Q_CMD_ACTIVATE: + case BNX2X_Q_CMD_UPDATE: + case BNX2X_Q_CMD_UPDATE_TPA: + case BNX2X_Q_CMD_HALT: + case BNX2X_Q_CMD_CFC_DEL: + case BNX2X_Q_CMD_TERMINATE: + case BNX2X_Q_CMD_EMPTY: + return bnx2x_queue_send_cmd_cmn(bp, params); + default: + BNX2X_ERR("Unknown command: %d\n", params->cmd); + return -EINVAL; + } +} + +static int bnx2x_queue_send_cmd_e2(struct bnx2x *bp, + struct bnx2x_queue_state_params *params) +{ + switch (params->cmd) { + case BNX2X_Q_CMD_SETUP: + return bnx2x_q_send_setup_e2(bp, params); + case BNX2X_Q_CMD_INIT: + case BNX2X_Q_CMD_SETUP_TX_ONLY: + case BNX2X_Q_CMD_DEACTIVATE: + case BNX2X_Q_CMD_ACTIVATE: + case BNX2X_Q_CMD_UPDATE: + case BNX2X_Q_CMD_UPDATE_TPA: + case BNX2X_Q_CMD_HALT: + case BNX2X_Q_CMD_CFC_DEL: + case BNX2X_Q_CMD_TERMINATE: + case BNX2X_Q_CMD_EMPTY: + return bnx2x_queue_send_cmd_cmn(bp, params); + default: + BNX2X_ERR("Unknown command: %d\n", params->cmd); + return -EINVAL; + } +} + +/** + * bnx2x_queue_chk_transition - check state machine of a regular Queue + * + * @bp: device handle + * @o: + * @params: + * + * (not Forwarding) + * It both checks if the requested command is legal in a current + * state and, if it's legal, sets a `next_state' in the object + * that will be used in the completion flow to set the `state' + * of the object. + * + * returns 0 if a requested command is a legal transition, + * -EINVAL otherwise. + */ +static int bnx2x_queue_chk_transition(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *o, + struct bnx2x_queue_state_params *params) +{ + enum bnx2x_q_state state = o->state, next_state = BNX2X_Q_STATE_MAX; + enum bnx2x_queue_cmd cmd = params->cmd; + struct bnx2x_queue_update_params *update_params = + ¶ms->params.update; + u8 next_tx_only = o->num_tx_only; + + /* + * Forget all pending for completion commands if a driver only state + * transition has been requested. + */ + if (test_bit(RAMROD_DRV_CLR_ONLY, ¶ms->ramrod_flags)) { + o->pending = 0; + o->next_state = BNX2X_Q_STATE_MAX; + } + + /* + * Don't allow a next state transition if we are in the middle of + * the previous one. + */ + if (o->pending) + return -EBUSY; + + switch (state) { + case BNX2X_Q_STATE_RESET: + if (cmd == BNX2X_Q_CMD_INIT) + next_state = BNX2X_Q_STATE_INITIALIZED; + + break; + case BNX2X_Q_STATE_INITIALIZED: + if (cmd == BNX2X_Q_CMD_SETUP) { + if (test_bit(BNX2X_Q_FLG_ACTIVE, + ¶ms->params.setup.flags)) + next_state = BNX2X_Q_STATE_ACTIVE; + else + next_state = BNX2X_Q_STATE_INACTIVE; + } + + break; + case BNX2X_Q_STATE_ACTIVE: + if (cmd == BNX2X_Q_CMD_DEACTIVATE) + next_state = BNX2X_Q_STATE_INACTIVE; + + else if ((cmd == BNX2X_Q_CMD_EMPTY) || + (cmd == BNX2X_Q_CMD_UPDATE_TPA)) + next_state = BNX2X_Q_STATE_ACTIVE; + + else if (cmd == BNX2X_Q_CMD_SETUP_TX_ONLY) { + next_state = BNX2X_Q_STATE_MULTI_COS; + next_tx_only = 1; + } + + else if (cmd == BNX2X_Q_CMD_HALT) + next_state = BNX2X_Q_STATE_STOPPED; + + else if (cmd == BNX2X_Q_CMD_UPDATE) { + /* If "active" state change is requested, update the + * state accordingly. + */ + if (test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, + &update_params->update_flags) && + !test_bit(BNX2X_Q_UPDATE_ACTIVATE, + &update_params->update_flags)) + next_state = BNX2X_Q_STATE_INACTIVE; + else + next_state = BNX2X_Q_STATE_ACTIVE; + } + + break; + case BNX2X_Q_STATE_MULTI_COS: + if (cmd == BNX2X_Q_CMD_TERMINATE) + next_state = BNX2X_Q_STATE_MCOS_TERMINATED; + + else if (cmd == BNX2X_Q_CMD_SETUP_TX_ONLY) { + next_state = BNX2X_Q_STATE_MULTI_COS; + next_tx_only = o->num_tx_only + 1; + } + + else if ((cmd == BNX2X_Q_CMD_EMPTY) || + (cmd == BNX2X_Q_CMD_UPDATE_TPA)) + next_state = BNX2X_Q_STATE_MULTI_COS; + + else if (cmd == BNX2X_Q_CMD_UPDATE) { + /* If "active" state change is requested, update the + * state accordingly. + */ + if (test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, + &update_params->update_flags) && + !test_bit(BNX2X_Q_UPDATE_ACTIVATE, + &update_params->update_flags)) + next_state = BNX2X_Q_STATE_INACTIVE; + else + next_state = BNX2X_Q_STATE_MULTI_COS; + } + + break; + case BNX2X_Q_STATE_MCOS_TERMINATED: + if (cmd == BNX2X_Q_CMD_CFC_DEL) { + next_tx_only = o->num_tx_only - 1; + if (next_tx_only == 0) + next_state = BNX2X_Q_STATE_ACTIVE; + else + next_state = BNX2X_Q_STATE_MULTI_COS; + } + + break; + case BNX2X_Q_STATE_INACTIVE: + if (cmd == BNX2X_Q_CMD_ACTIVATE) + next_state = BNX2X_Q_STATE_ACTIVE; + + else if ((cmd == BNX2X_Q_CMD_EMPTY) || + (cmd == BNX2X_Q_CMD_UPDATE_TPA)) + next_state = BNX2X_Q_STATE_INACTIVE; + + else if (cmd == BNX2X_Q_CMD_HALT) + next_state = BNX2X_Q_STATE_STOPPED; + + else if (cmd == BNX2X_Q_CMD_UPDATE) { + /* If "active" state change is requested, update the + * state accordingly. + */ + if (test_bit(BNX2X_Q_UPDATE_ACTIVATE_CHNG, + &update_params->update_flags) && + test_bit(BNX2X_Q_UPDATE_ACTIVATE, + &update_params->update_flags)){ + if (o->num_tx_only == 0) + next_state = BNX2X_Q_STATE_ACTIVE; + else /* tx only queues exist for this queue */ + next_state = BNX2X_Q_STATE_MULTI_COS; + } else + next_state = BNX2X_Q_STATE_INACTIVE; + } + + break; + case BNX2X_Q_STATE_STOPPED: + if (cmd == BNX2X_Q_CMD_TERMINATE) + next_state = BNX2X_Q_STATE_TERMINATED; + + break; + case BNX2X_Q_STATE_TERMINATED: + if (cmd == BNX2X_Q_CMD_CFC_DEL) + next_state = BNX2X_Q_STATE_RESET; + + break; + default: + BNX2X_ERR("Illegal state: %d\n", state); + } + + /* Transition is assured */ + if (next_state != BNX2X_Q_STATE_MAX) { + DP(BNX2X_MSG_SP, "Good state transition: %d(%d)->%d\n", + state, cmd, next_state); + o->next_state = next_state; + o->next_tx_only = next_tx_only; + return 0; + } + + DP(BNX2X_MSG_SP, "Bad state transition request: %d %d\n", state, cmd); + + return -EINVAL; +} + +void bnx2x_init_queue_obj(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *obj, + u8 cl_id, u32 *cids, u8 cid_cnt, u8 func_id, + void *rdata, + dma_addr_t rdata_mapping, unsigned long type) +{ + memset(obj, 0, sizeof(*obj)); + + /* We support only BNX2X_MULTI_TX_COS Tx CoS at the moment */ + BUG_ON(BNX2X_MULTI_TX_COS < cid_cnt); + + memcpy(obj->cids, cids, sizeof(obj->cids[0]) * cid_cnt); + obj->max_cos = cid_cnt; + obj->cl_id = cl_id; + obj->func_id = func_id; + obj->rdata = rdata; + obj->rdata_mapping = rdata_mapping; + obj->type = type; + obj->next_state = BNX2X_Q_STATE_MAX; + + if (CHIP_IS_E1x(bp)) + obj->send_cmd = bnx2x_queue_send_cmd_e1x; + else + obj->send_cmd = bnx2x_queue_send_cmd_e2; + + obj->check_transition = bnx2x_queue_chk_transition; + + obj->complete_cmd = bnx2x_queue_comp_cmd; + obj->wait_comp = bnx2x_queue_wait_comp; + obj->set_pending = bnx2x_queue_set_pending; +} + +void bnx2x_queue_set_cos_cid(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *obj, + u32 cid, u8 index) +{ + obj->cids[index] = cid; +} + +/********************** Function state object *********************************/ +enum bnx2x_func_state bnx2x_func_get_state(struct bnx2x *bp, + struct bnx2x_func_sp_obj *o) +{ + /* in the middle of transaction - return INVALID state */ + if (o->pending) + return BNX2X_F_STATE_MAX; + + /* + * unsure the order of reading of o->pending and o->state + * o->pending should be read first + */ + rmb(); + + return o->state; +} + +static int bnx2x_func_wait_comp(struct bnx2x *bp, + struct bnx2x_func_sp_obj *o, + enum bnx2x_func_cmd cmd) +{ + return bnx2x_state_wait(bp, cmd, &o->pending); +} + +/** + * bnx2x_func_state_change_comp - complete the state machine transition + * + * @bp: device handle + * @o: + * @cmd: + * + * Called on state change transition. Completes the state + * machine transition only - no HW interaction. + */ +static inline int bnx2x_func_state_change_comp(struct bnx2x *bp, + struct bnx2x_func_sp_obj *o, + enum bnx2x_func_cmd cmd) +{ + unsigned long cur_pending = o->pending; + + if (!test_and_clear_bit(cmd, &cur_pending)) { + BNX2X_ERR("Bad MC reply %d for func %d in state %d " + "pending 0x%lx, next_state %d\n", cmd, BP_FUNC(bp), + o->state, cur_pending, o->next_state); + return -EINVAL; + } + + DP(BNX2X_MSG_SP, "Completing command %d for func %d, setting state to " + "%d\n", cmd, BP_FUNC(bp), o->next_state); + + o->state = o->next_state; + o->next_state = BNX2X_F_STATE_MAX; + + /* It's important that o->state and o->next_state are + * updated before o->pending. + */ + wmb(); + + clear_bit(cmd, &o->pending); + smp_mb__after_clear_bit(); + + return 0; +} + +/** + * bnx2x_func_comp_cmd - complete the state change command + * + * @bp: device handle + * @o: + * @cmd: + * + * Checks that the arrived completion is expected. + */ +static int bnx2x_func_comp_cmd(struct bnx2x *bp, + struct bnx2x_func_sp_obj *o, + enum bnx2x_func_cmd cmd) +{ + /* Complete the state machine part first, check if it's a + * legal completion. + */ + int rc = bnx2x_func_state_change_comp(bp, o, cmd); + return rc; +} + +/** + * bnx2x_func_chk_transition - perform function state machine transition + * + * @bp: device handle + * @o: + * @params: + * + * It both checks if the requested command is legal in a current + * state and, if it's legal, sets a `next_state' in the object + * that will be used in the completion flow to set the `state' + * of the object. + * + * returns 0 if a requested command is a legal transition, + * -EINVAL otherwise. + */ +static int bnx2x_func_chk_transition(struct bnx2x *bp, + struct bnx2x_func_sp_obj *o, + struct bnx2x_func_state_params *params) +{ + enum bnx2x_func_state state = o->state, next_state = BNX2X_F_STATE_MAX; + enum bnx2x_func_cmd cmd = params->cmd; + + /* + * Forget all pending for completion commands if a driver only state + * transition has been requested. + */ + if (test_bit(RAMROD_DRV_CLR_ONLY, ¶ms->ramrod_flags)) { + o->pending = 0; + o->next_state = BNX2X_F_STATE_MAX; + } + + /* + * Don't allow a next state transition if we are in the middle of + * the previous one. + */ + if (o->pending) + return -EBUSY; + + switch (state) { + case BNX2X_F_STATE_RESET: + if (cmd == BNX2X_F_CMD_HW_INIT) + next_state = BNX2X_F_STATE_INITIALIZED; + + break; + case BNX2X_F_STATE_INITIALIZED: + if (cmd == BNX2X_F_CMD_START) + next_state = BNX2X_F_STATE_STARTED; + + else if (cmd == BNX2X_F_CMD_HW_RESET) + next_state = BNX2X_F_STATE_RESET; + + break; + case BNX2X_F_STATE_STARTED: + if (cmd == BNX2X_F_CMD_STOP) + next_state = BNX2X_F_STATE_INITIALIZED; + else if (cmd == BNX2X_F_CMD_TX_STOP) + next_state = BNX2X_F_STATE_TX_STOPPED; + + break; + case BNX2X_F_STATE_TX_STOPPED: + if (cmd == BNX2X_F_CMD_TX_START) + next_state = BNX2X_F_STATE_STARTED; + + break; + default: + BNX2X_ERR("Unknown state: %d\n", state); + } + + /* Transition is assured */ + if (next_state != BNX2X_F_STATE_MAX) { + DP(BNX2X_MSG_SP, "Good function state transition: %d(%d)->%d\n", + state, cmd, next_state); + o->next_state = next_state; + return 0; + } + + DP(BNX2X_MSG_SP, "Bad function state transition request: %d %d\n", + state, cmd); + + return -EINVAL; +} + +/** + * bnx2x_func_init_func - performs HW init at function stage + * + * @bp: device handle + * @drv: + * + * Init HW when the current phase is + * FW_MSG_CODE_DRV_LOAD_FUNCTION: initialize only FUNCTION-only + * HW blocks. + */ +static inline int bnx2x_func_init_func(struct bnx2x *bp, + const struct bnx2x_func_sp_drv_ops *drv) +{ + return drv->init_hw_func(bp); +} + +/** + * bnx2x_func_init_port - performs HW init at port stage + * + * @bp: device handle + * @drv: + * + * Init HW when the current phase is + * FW_MSG_CODE_DRV_LOAD_PORT: initialize PORT-only and + * FUNCTION-only HW blocks. + * + */ +static inline int bnx2x_func_init_port(struct bnx2x *bp, + const struct bnx2x_func_sp_drv_ops *drv) +{ + int rc = drv->init_hw_port(bp); + if (rc) + return rc; + + return bnx2x_func_init_func(bp, drv); +} + +/** + * bnx2x_func_init_cmn_chip - performs HW init at chip-common stage + * + * @bp: device handle + * @drv: + * + * Init HW when the current phase is + * FW_MSG_CODE_DRV_LOAD_COMMON_CHIP: initialize COMMON_CHIP, + * PORT-only and FUNCTION-only HW blocks. + */ +static inline int bnx2x_func_init_cmn_chip(struct bnx2x *bp, + const struct bnx2x_func_sp_drv_ops *drv) +{ + int rc = drv->init_hw_cmn_chip(bp); + if (rc) + return rc; + + return bnx2x_func_init_port(bp, drv); +} + +/** + * bnx2x_func_init_cmn - performs HW init at common stage + * + * @bp: device handle + * @drv: + * + * Init HW when the current phase is + * FW_MSG_CODE_DRV_LOAD_COMMON_CHIP: initialize COMMON, + * PORT-only and FUNCTION-only HW blocks. + */ +static inline int bnx2x_func_init_cmn(struct bnx2x *bp, + const struct bnx2x_func_sp_drv_ops *drv) +{ + int rc = drv->init_hw_cmn(bp); + if (rc) + return rc; + + return bnx2x_func_init_port(bp, drv); +} + +static int bnx2x_func_hw_init(struct bnx2x *bp, + struct bnx2x_func_state_params *params) +{ + u32 load_code = params->params.hw_init.load_phase; + struct bnx2x_func_sp_obj *o = params->f_obj; + const struct bnx2x_func_sp_drv_ops *drv = o->drv; + int rc = 0; + + DP(BNX2X_MSG_SP, "function %d load_code %x\n", + BP_ABS_FUNC(bp), load_code); + + /* Prepare buffers for unzipping the FW */ + rc = drv->gunzip_init(bp); + if (rc) + return rc; + + /* Prepare FW */ + rc = drv->init_fw(bp); + if (rc) { + BNX2X_ERR("Error loading firmware\n"); + goto fw_init_err; + } + + /* Handle the beginning of COMMON_XXX pases separatelly... */ + switch (load_code) { + case FW_MSG_CODE_DRV_LOAD_COMMON_CHIP: + rc = bnx2x_func_init_cmn_chip(bp, drv); + if (rc) + goto init_hw_err; + + break; + case FW_MSG_CODE_DRV_LOAD_COMMON: + rc = bnx2x_func_init_cmn(bp, drv); + if (rc) + goto init_hw_err; + + break; + case FW_MSG_CODE_DRV_LOAD_PORT: + rc = bnx2x_func_init_port(bp, drv); + if (rc) + goto init_hw_err; + + break; + case FW_MSG_CODE_DRV_LOAD_FUNCTION: + rc = bnx2x_func_init_func(bp, drv); + if (rc) + goto init_hw_err; + + break; + default: + BNX2X_ERR("Unknown load_code (0x%x) from MCP\n", load_code); + rc = -EINVAL; + } + +init_hw_err: + drv->release_fw(bp); + +fw_init_err: + drv->gunzip_end(bp); + + /* In case of success, complete the comand immediatelly: no ramrods + * have been sent. + */ + if (!rc) + o->complete_cmd(bp, o, BNX2X_F_CMD_HW_INIT); + + return rc; +} + +/** + * bnx2x_func_reset_func - reset HW at function stage + * + * @bp: device handle + * @drv: + * + * Reset HW at FW_MSG_CODE_DRV_UNLOAD_FUNCTION stage: reset only + * FUNCTION-only HW blocks. + */ +static inline void bnx2x_func_reset_func(struct bnx2x *bp, + const struct bnx2x_func_sp_drv_ops *drv) +{ + drv->reset_hw_func(bp); +} + +/** + * bnx2x_func_reset_port - reser HW at port stage + * + * @bp: device handle + * @drv: + * + * Reset HW at FW_MSG_CODE_DRV_UNLOAD_PORT stage: reset + * FUNCTION-only and PORT-only HW blocks. + * + * !!!IMPORTANT!!! + * + * It's important to call reset_port before reset_func() as the last thing + * reset_func does is pf_disable() thus disabling PGLUE_B, which + * makes impossible any DMAE transactions. + */ +static inline void bnx2x_func_reset_port(struct bnx2x *bp, + const struct bnx2x_func_sp_drv_ops *drv) +{ + drv->reset_hw_port(bp); + bnx2x_func_reset_func(bp, drv); +} + +/** + * bnx2x_func_reset_cmn - reser HW at common stage + * + * @bp: device handle + * @drv: + * + * Reset HW at FW_MSG_CODE_DRV_UNLOAD_COMMON and + * FW_MSG_CODE_DRV_UNLOAD_COMMON_CHIP stages: reset COMMON, + * COMMON_CHIP, FUNCTION-only and PORT-only HW blocks. + */ +static inline void bnx2x_func_reset_cmn(struct bnx2x *bp, + const struct bnx2x_func_sp_drv_ops *drv) +{ + bnx2x_func_reset_port(bp, drv); + drv->reset_hw_cmn(bp); +} + + +static inline int bnx2x_func_hw_reset(struct bnx2x *bp, + struct bnx2x_func_state_params *params) +{ + u32 reset_phase = params->params.hw_reset.reset_phase; + struct bnx2x_func_sp_obj *o = params->f_obj; + const struct bnx2x_func_sp_drv_ops *drv = o->drv; + + DP(BNX2X_MSG_SP, "function %d reset_phase %x\n", BP_ABS_FUNC(bp), + reset_phase); + + switch (reset_phase) { + case FW_MSG_CODE_DRV_UNLOAD_COMMON: + bnx2x_func_reset_cmn(bp, drv); + break; + case FW_MSG_CODE_DRV_UNLOAD_PORT: + bnx2x_func_reset_port(bp, drv); + break; + case FW_MSG_CODE_DRV_UNLOAD_FUNCTION: + bnx2x_func_reset_func(bp, drv); + break; + default: + BNX2X_ERR("Unknown reset_phase (0x%x) from MCP\n", + reset_phase); + break; + } + + /* Complete the comand immediatelly: no ramrods have been sent. */ + o->complete_cmd(bp, o, BNX2X_F_CMD_HW_RESET); + + return 0; +} + +static inline int bnx2x_func_send_start(struct bnx2x *bp, + struct bnx2x_func_state_params *params) +{ + struct bnx2x_func_sp_obj *o = params->f_obj; + struct function_start_data *rdata = + (struct function_start_data *)o->rdata; + dma_addr_t data_mapping = o->rdata_mapping; + struct bnx2x_func_start_params *start_params = ¶ms->params.start; + + memset(rdata, 0, sizeof(*rdata)); + + /* Fill the ramrod data with provided parameters */ + rdata->function_mode = cpu_to_le16(start_params->mf_mode); + rdata->sd_vlan_tag = start_params->sd_vlan_tag; + rdata->path_id = BP_PATH(bp); + rdata->network_cos_mode = start_params->network_cos_mode; + + /* + * No need for an explicit memory barrier here as long we would + * need to ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read and we will have to put a full memory barrier there + * (inside bnx2x_sp_post()). + */ + + return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_START, 0, + U64_HI(data_mapping), + U64_LO(data_mapping), NONE_CONNECTION_TYPE); +} + +static inline int bnx2x_func_send_stop(struct bnx2x *bp, + struct bnx2x_func_state_params *params) +{ + return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_STOP, 0, 0, 0, + NONE_CONNECTION_TYPE); +} + +static inline int bnx2x_func_send_tx_stop(struct bnx2x *bp, + struct bnx2x_func_state_params *params) +{ + return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STOP_TRAFFIC, 0, 0, 0, + NONE_CONNECTION_TYPE); +} +static inline int bnx2x_func_send_tx_start(struct bnx2x *bp, + struct bnx2x_func_state_params *params) +{ + struct bnx2x_func_sp_obj *o = params->f_obj; + struct flow_control_configuration *rdata = + (struct flow_control_configuration *)o->rdata; + dma_addr_t data_mapping = o->rdata_mapping; + struct bnx2x_func_tx_start_params *tx_start_params = + ¶ms->params.tx_start; + int i; + + memset(rdata, 0, sizeof(*rdata)); + + rdata->dcb_enabled = tx_start_params->dcb_enabled; + rdata->dcb_version = tx_start_params->dcb_version; + rdata->dont_add_pri_0_en = tx_start_params->dont_add_pri_0_en; + + for (i = 0; i < ARRAY_SIZE(rdata->traffic_type_to_priority_cos); i++) + rdata->traffic_type_to_priority_cos[i] = + tx_start_params->traffic_type_to_priority_cos[i]; + + return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC, 0, + U64_HI(data_mapping), + U64_LO(data_mapping), NONE_CONNECTION_TYPE); +} + +static int bnx2x_func_send_cmd(struct bnx2x *bp, + struct bnx2x_func_state_params *params) +{ + switch (params->cmd) { + case BNX2X_F_CMD_HW_INIT: + return bnx2x_func_hw_init(bp, params); + case BNX2X_F_CMD_START: + return bnx2x_func_send_start(bp, params); + case BNX2X_F_CMD_STOP: + return bnx2x_func_send_stop(bp, params); + case BNX2X_F_CMD_HW_RESET: + return bnx2x_func_hw_reset(bp, params); + case BNX2X_F_CMD_TX_STOP: + return bnx2x_func_send_tx_stop(bp, params); + case BNX2X_F_CMD_TX_START: + return bnx2x_func_send_tx_start(bp, params); + default: + BNX2X_ERR("Unknown command: %d\n", params->cmd); + return -EINVAL; + } +} + +void bnx2x_init_func_obj(struct bnx2x *bp, + struct bnx2x_func_sp_obj *obj, + void *rdata, dma_addr_t rdata_mapping, + struct bnx2x_func_sp_drv_ops *drv_iface) +{ + memset(obj, 0, sizeof(*obj)); + + mutex_init(&obj->one_pending_mutex); + + obj->rdata = rdata; + obj->rdata_mapping = rdata_mapping; + + obj->send_cmd = bnx2x_func_send_cmd; + obj->check_transition = bnx2x_func_chk_transition; + obj->complete_cmd = bnx2x_func_comp_cmd; + obj->wait_comp = bnx2x_func_wait_comp; + + obj->drv = drv_iface; +} + +/** + * bnx2x_func_state_change - perform Function state change transition + * + * @bp: device handle + * @params: parameters to perform the transaction + * + * returns 0 in case of successfully completed transition, + * negative error code in case of failure, positive + * (EBUSY) value if there is a completion to that is + * still pending (possible only if RAMROD_COMP_WAIT is + * not set in params->ramrod_flags for asynchronous + * commands). + */ +int bnx2x_func_state_change(struct bnx2x *bp, + struct bnx2x_func_state_params *params) +{ + struct bnx2x_func_sp_obj *o = params->f_obj; + int rc; + enum bnx2x_func_cmd cmd = params->cmd; + unsigned long *pending = &o->pending; + + mutex_lock(&o->one_pending_mutex); + + /* Check that the requested transition is legal */ + if (o->check_transition(bp, o, params)) { + mutex_unlock(&o->one_pending_mutex); + return -EINVAL; + } + + /* Set "pending" bit */ + set_bit(cmd, pending); + + /* Don't send a command if only driver cleanup was requested */ + if (test_bit(RAMROD_DRV_CLR_ONLY, ¶ms->ramrod_flags)) { + bnx2x_func_state_change_comp(bp, o, cmd); + mutex_unlock(&o->one_pending_mutex); + } else { + /* Send a ramrod */ + rc = o->send_cmd(bp, params); + + mutex_unlock(&o->one_pending_mutex); + + if (rc) { + o->next_state = BNX2X_F_STATE_MAX; + clear_bit(cmd, pending); + smp_mb__after_clear_bit(); + return rc; + } + + if (test_bit(RAMROD_COMP_WAIT, ¶ms->ramrod_flags)) { + rc = o->wait_comp(bp, o, cmd); + if (rc) + return rc; + + return 0; + } + } + + return !!test_bit(cmd, pending); +} diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h new file mode 100644 index 000000000000..9a517c2e9f1b --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h @@ -0,0 +1,1297 @@ +/* bnx2x_sp.h: Broadcom Everest network driver. + * + * Copyright 2011 Broadcom Corporation + * + * Unless you and Broadcom execute a separate written software license + * agreement governing use of this software, this software is licensed to you + * under the terms of the GNU General Public License version 2, available + * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * + * Notwithstanding the above, under no circumstances may you combine this + * software in any way with any other Broadcom software provided under a + * license other than the GPL, without Broadcom's express prior written + * consent. + * + * Maintained by: Eilon Greenstein + * Written by: Vladislav Zolotarov + * + */ +#ifndef BNX2X_SP_VERBS +#define BNX2X_SP_VERBS + +struct bnx2x; +struct eth_context; + +/* Bits representing general command's configuration */ +enum { + RAMROD_TX, + RAMROD_RX, + /* Wait until all pending commands complete */ + RAMROD_COMP_WAIT, + /* Don't send a ramrod, only update a registry */ + RAMROD_DRV_CLR_ONLY, + /* Configure HW according to the current object state */ + RAMROD_RESTORE, + /* Execute the next command now */ + RAMROD_EXEC, + /* + * Don't add a new command and continue execution of posponed + * commands. If not set a new command will be added to the + * pending commands list. + */ + RAMROD_CONT, +}; + +typedef enum { + BNX2X_OBJ_TYPE_RX, + BNX2X_OBJ_TYPE_TX, + BNX2X_OBJ_TYPE_RX_TX, +} bnx2x_obj_type; + +/* Filtering states */ +enum { + BNX2X_FILTER_MAC_PENDING, + BNX2X_FILTER_VLAN_PENDING, + BNX2X_FILTER_VLAN_MAC_PENDING, + BNX2X_FILTER_RX_MODE_PENDING, + BNX2X_FILTER_RX_MODE_SCHED, + BNX2X_FILTER_ISCSI_ETH_START_SCHED, + BNX2X_FILTER_ISCSI_ETH_STOP_SCHED, + BNX2X_FILTER_FCOE_ETH_START_SCHED, + BNX2X_FILTER_FCOE_ETH_STOP_SCHED, + BNX2X_FILTER_MCAST_PENDING, + BNX2X_FILTER_MCAST_SCHED, + BNX2X_FILTER_RSS_CONF_PENDING, +}; + +struct bnx2x_raw_obj { + u8 func_id; + + /* Queue params */ + u8 cl_id; + u32 cid; + + /* Ramrod data buffer params */ + void *rdata; + dma_addr_t rdata_mapping; + + /* Ramrod state params */ + int state; /* "ramrod is pending" state bit */ + unsigned long *pstate; /* pointer to state buffer */ + + bnx2x_obj_type obj_type; + + int (*wait_comp)(struct bnx2x *bp, + struct bnx2x_raw_obj *o); + + bool (*check_pending)(struct bnx2x_raw_obj *o); + void (*clear_pending)(struct bnx2x_raw_obj *o); + void (*set_pending)(struct bnx2x_raw_obj *o); +}; + +/************************* VLAN-MAC commands related parameters ***************/ +struct bnx2x_mac_ramrod_data { + u8 mac[ETH_ALEN]; +}; + +struct bnx2x_vlan_ramrod_data { + u16 vlan; +}; + +struct bnx2x_vlan_mac_ramrod_data { + u8 mac[ETH_ALEN]; + u16 vlan; +}; + +union bnx2x_classification_ramrod_data { + struct bnx2x_mac_ramrod_data mac; + struct bnx2x_vlan_ramrod_data vlan; + struct bnx2x_vlan_mac_ramrod_data vlan_mac; +}; + +/* VLAN_MAC commands */ +enum bnx2x_vlan_mac_cmd { + BNX2X_VLAN_MAC_ADD, + BNX2X_VLAN_MAC_DEL, + BNX2X_VLAN_MAC_MOVE, +}; + +struct bnx2x_vlan_mac_data { + /* Requested command: BNX2X_VLAN_MAC_XX */ + enum bnx2x_vlan_mac_cmd cmd; + /* + * used to contain the data related vlan_mac_flags bits from + * ramrod parameters. + */ + unsigned long vlan_mac_flags; + + /* Needed for MOVE command */ + struct bnx2x_vlan_mac_obj *target_obj; + + union bnx2x_classification_ramrod_data u; +}; + +/*************************** Exe Queue obj ************************************/ +union bnx2x_exe_queue_cmd_data { + struct bnx2x_vlan_mac_data vlan_mac; + + struct { + /* TODO */ + } mcast; +}; + +struct bnx2x_exeq_elem { + struct list_head link; + + /* Length of this element in the exe_chunk. */ + int cmd_len; + + union bnx2x_exe_queue_cmd_data cmd_data; +}; + +union bnx2x_qable_obj; + +union bnx2x_exeq_comp_elem { + union event_ring_elem *elem; +}; + +struct bnx2x_exe_queue_obj; + +typedef int (*exe_q_validate)(struct bnx2x *bp, + union bnx2x_qable_obj *o, + struct bnx2x_exeq_elem *elem); + +/** + * @return positive is entry was optimized, 0 - if not, negative + * in case of an error. + */ +typedef int (*exe_q_optimize)(struct bnx2x *bp, + union bnx2x_qable_obj *o, + struct bnx2x_exeq_elem *elem); +typedef int (*exe_q_execute)(struct bnx2x *bp, + union bnx2x_qable_obj *o, + struct list_head *exe_chunk, + unsigned long *ramrod_flags); +typedef struct bnx2x_exeq_elem * + (*exe_q_get)(struct bnx2x_exe_queue_obj *o, + struct bnx2x_exeq_elem *elem); + +struct bnx2x_exe_queue_obj { + /* + * Commands pending for an execution. + */ + struct list_head exe_queue; + + /* + * Commands pending for an completion. + */ + struct list_head pending_comp; + + spinlock_t lock; + + /* Maximum length of commands' list for one execution */ + int exe_chunk_len; + + union bnx2x_qable_obj *owner; + + /****** Virtual functions ******/ + /** + * Called before commands execution for commands that are really + * going to be executed (after 'optimize'). + * + * Must run under exe_queue->lock + */ + exe_q_validate validate; + + + /** + * This will try to cancel the current pending commands list + * considering the new command. + * + * Must run under exe_queue->lock + */ + exe_q_optimize optimize; + + /** + * Run the next commands chunk (owner specific). + */ + exe_q_execute execute; + + /** + * Return the exe_queue element containing the specific command + * if any. Otherwise return NULL. + */ + exe_q_get get; +}; +/***************** Classification verbs: Set/Del MAC/VLAN/VLAN-MAC ************/ +/* + * Element in the VLAN_MAC registry list having all currenty configured + * rules. + */ +struct bnx2x_vlan_mac_registry_elem { + struct list_head link; + + /* + * Used to store the cam offset used for the mac/vlan/vlan-mac. + * Relevant for 57710 and 57711 only. VLANs and MACs share the + * same CAM for these chips. + */ + int cam_offset; + + /* Needed for DEL and RESTORE flows */ + unsigned long vlan_mac_flags; + + union bnx2x_classification_ramrod_data u; +}; + +/* Bits representing VLAN_MAC commands specific flags */ +enum { + BNX2X_UC_LIST_MAC, + BNX2X_ETH_MAC, + BNX2X_ISCSI_ETH_MAC, + BNX2X_NETQ_ETH_MAC, + BNX2X_DONT_CONSUME_CAM_CREDIT, + BNX2X_DONT_CONSUME_CAM_CREDIT_DEST, +}; + +struct bnx2x_vlan_mac_ramrod_params { + /* Object to run the command from */ + struct bnx2x_vlan_mac_obj *vlan_mac_obj; + + /* General command flags: COMP_WAIT, etc. */ + unsigned long ramrod_flags; + + /* Command specific configuration request */ + struct bnx2x_vlan_mac_data user_req; +}; + +struct bnx2x_vlan_mac_obj { + struct bnx2x_raw_obj raw; + + /* Bookkeeping list: will prevent the addition of already existing + * entries. + */ + struct list_head head; + + /* TODO: Add it's initialization in the init functions */ + struct bnx2x_exe_queue_obj exe_queue; + + /* MACs credit pool */ + struct bnx2x_credit_pool_obj *macs_pool; + + /* VLANs credit pool */ + struct bnx2x_credit_pool_obj *vlans_pool; + + /* RAMROD command to be used */ + int ramrod_cmd; + + /** + * Checks if ADD-ramrod with the given params may be performed. + * + * @return zero if the element may be added + */ + + int (*check_add)(struct bnx2x_vlan_mac_obj *o, + union bnx2x_classification_ramrod_data *data); + + /** + * Checks if DEL-ramrod with the given params may be performed. + * + * @return true if the element may be deleted + */ + struct bnx2x_vlan_mac_registry_elem * + (*check_del)(struct bnx2x_vlan_mac_obj *o, + union bnx2x_classification_ramrod_data *data); + + /** + * Checks if DEL-ramrod with the given params may be performed. + * + * @return true if the element may be deleted + */ + bool (*check_move)(struct bnx2x_vlan_mac_obj *src_o, + struct bnx2x_vlan_mac_obj *dst_o, + union bnx2x_classification_ramrod_data *data); + + /** + * Update the relevant credit object(s) (consume/return + * correspondingly). + */ + bool (*get_credit)(struct bnx2x_vlan_mac_obj *o); + bool (*put_credit)(struct bnx2x_vlan_mac_obj *o); + bool (*get_cam_offset)(struct bnx2x_vlan_mac_obj *o, int *offset); + bool (*put_cam_offset)(struct bnx2x_vlan_mac_obj *o, int offset); + + /** + * Configures one rule in the ramrod data buffer. + */ + void (*set_one_rule)(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + struct bnx2x_exeq_elem *elem, int rule_idx, + int cam_offset); + + /** + * Delete all configured elements having the given + * vlan_mac_flags specification. Assumes no pending for + * execution commands. Will schedule all all currently + * configured MACs/VLANs/VLAN-MACs matching the vlan_mac_flags + * specification for deletion and will use the given + * ramrod_flags for the last DEL operation. + * + * @param bp + * @param o + * @param ramrod_flags RAMROD_XX flags + * + * @return 0 if the last operation has completed successfully + * and there are no more elements left, positive value + * if there are pending for completion commands, + * negative value in case of failure. + */ + int (*delete_all)(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *o, + unsigned long *vlan_mac_flags, + unsigned long *ramrod_flags); + + /** + * Reconfigures the next MAC/VLAN/VLAN-MAC element from the previously + * configured elements list. + * + * @param bp + * @param p Command parameters (RAMROD_COMP_WAIT bit in + * ramrod_flags is only taken into an account) + * @param ppos a pointer to the cooky that should be given back in the + * next call to make function handle the next element. If + * *ppos is set to NULL it will restart the iterator. + * If returned *ppos == NULL this means that the last + * element has been handled. + * + * @return int + */ + int (*restore)(struct bnx2x *bp, + struct bnx2x_vlan_mac_ramrod_params *p, + struct bnx2x_vlan_mac_registry_elem **ppos); + + /** + * Should be called on a completion arival. + * + * @param bp + * @param o + * @param cqe Completion element we are handling + * @param ramrod_flags if RAMROD_CONT is set the next bulk of + * pending commands will be executed. + * RAMROD_DRV_CLR_ONLY and RAMROD_RESTORE + * may also be set if needed. + * + * @return 0 if there are neither pending nor waiting for + * completion commands. Positive value if there are + * pending for execution or for completion commands. + * Negative value in case of an error (including an + * error in the cqe). + */ + int (*complete)(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o, + union event_ring_elem *cqe, + unsigned long *ramrod_flags); + + /** + * Wait for completion of all commands. Don't schedule new ones, + * just wait. It assumes that the completion code will schedule + * for new commands. + */ + int (*wait)(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o); +}; + +/** RX_MODE verbs:DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */ + +/* RX_MODE ramrod spesial flags: set in rx_mode_flags field in + * a bnx2x_rx_mode_ramrod_params. + */ +enum { + BNX2X_RX_MODE_FCOE_ETH, + BNX2X_RX_MODE_ISCSI_ETH, +}; + +enum { + BNX2X_ACCEPT_UNICAST, + BNX2X_ACCEPT_MULTICAST, + BNX2X_ACCEPT_ALL_UNICAST, + BNX2X_ACCEPT_ALL_MULTICAST, + BNX2X_ACCEPT_BROADCAST, + BNX2X_ACCEPT_UNMATCHED, + BNX2X_ACCEPT_ANY_VLAN +}; + +struct bnx2x_rx_mode_ramrod_params { + struct bnx2x_rx_mode_obj *rx_mode_obj; + unsigned long *pstate; + int state; + u8 cl_id; + u32 cid; + u8 func_id; + unsigned long ramrod_flags; + unsigned long rx_mode_flags; + + /* + * rdata is either a pointer to eth_filter_rules_ramrod_data(e2) or to + * a tstorm_eth_mac_filter_config (e1x). + */ + void *rdata; + dma_addr_t rdata_mapping; + + /* Rx mode settings */ + unsigned long rx_accept_flags; + + /* internal switching settings */ + unsigned long tx_accept_flags; +}; + +struct bnx2x_rx_mode_obj { + int (*config_rx_mode)(struct bnx2x *bp, + struct bnx2x_rx_mode_ramrod_params *p); + + int (*wait_comp)(struct bnx2x *bp, + struct bnx2x_rx_mode_ramrod_params *p); +}; + +/********************** Set multicast group ***********************************/ + +struct bnx2x_mcast_list_elem { + struct list_head link; + u8 *mac; +}; + +union bnx2x_mcast_config_data { + u8 *mac; + u8 bin; /* used in a RESTORE flow */ +}; + +struct bnx2x_mcast_ramrod_params { + struct bnx2x_mcast_obj *mcast_obj; + + /* Relevant options are RAMROD_COMP_WAIT and RAMROD_DRV_CLR_ONLY */ + unsigned long ramrod_flags; + + struct list_head mcast_list; /* list of struct bnx2x_mcast_list_elem */ + /** TODO: + * - rename it to macs_num. + * - Add a new command type for handling pending commands + * (remove "zero semantics"). + * + * Length of mcast_list. If zero and ADD_CONT command - post + * pending commands. + */ + int mcast_list_len; +}; + +enum { + BNX2X_MCAST_CMD_ADD, + BNX2X_MCAST_CMD_CONT, + BNX2X_MCAST_CMD_DEL, + BNX2X_MCAST_CMD_RESTORE, +}; + +struct bnx2x_mcast_obj { + struct bnx2x_raw_obj raw; + + union { + struct { + #define BNX2X_MCAST_BINS_NUM 256 + #define BNX2X_MCAST_VEC_SZ (BNX2X_MCAST_BINS_NUM / 64) + u64 vec[BNX2X_MCAST_VEC_SZ]; + + /** Number of BINs to clear. Should be updated + * immediately when a command arrives in order to + * properly create DEL commands. + */ + int num_bins_set; + } aprox_match; + + struct { + struct list_head macs; + int num_macs_set; + } exact_match; + } registry; + + /* Pending commands */ + struct list_head pending_cmds_head; + + /* A state that is set in raw.pstate, when there are pending commands */ + int sched_state; + + /* Maximal number of mcast MACs configured in one command */ + int max_cmd_len; + + /* Total number of currently pending MACs to configure: both + * in the pending commands list and in the current command. + */ + int total_pending_num; + + u8 engine_id; + + /** + * @param cmd command to execute (BNX2X_MCAST_CMD_X, see above) + */ + int (*config_mcast)(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, int cmd); + + /** + * Fills the ramrod data during the RESTORE flow. + * + * @param bp + * @param o + * @param start_idx Registry index to start from + * @param rdata_idx Index in the ramrod data to start from + * + * @return -1 if we handled the whole registry or index of the last + * handled registry element. + */ + int (*hdl_restore)(struct bnx2x *bp, struct bnx2x_mcast_obj *o, + int start_bin, int *rdata_idx); + + int (*enqueue_cmd)(struct bnx2x *bp, struct bnx2x_mcast_obj *o, + struct bnx2x_mcast_ramrod_params *p, int cmd); + + void (*set_one_rule)(struct bnx2x *bp, + struct bnx2x_mcast_obj *o, int idx, + union bnx2x_mcast_config_data *cfg_data, int cmd); + + /** Checks if there are more mcast MACs to be set or a previous + * command is still pending. + */ + bool (*check_pending)(struct bnx2x_mcast_obj *o); + + /** + * Set/Clear/Check SCHEDULED state of the object + */ + void (*set_sched)(struct bnx2x_mcast_obj *o); + void (*clear_sched)(struct bnx2x_mcast_obj *o); + bool (*check_sched)(struct bnx2x_mcast_obj *o); + + /* Wait until all pending commands complete */ + int (*wait_comp)(struct bnx2x *bp, struct bnx2x_mcast_obj *o); + + /** + * Handle the internal object counters needed for proper + * commands handling. Checks that the provided parameters are + * feasible. + */ + int (*validate)(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, int cmd); + + /** + * Restore the values of internal counters in case of a failure. + */ + void (*revert)(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, + int old_num_bins); + + int (*get_registry_size)(struct bnx2x_mcast_obj *o); + void (*set_registry_size)(struct bnx2x_mcast_obj *o, int n); +}; + +/*************************** Credit handling **********************************/ +struct bnx2x_credit_pool_obj { + + /* Current amount of credit in the pool */ + atomic_t credit; + + /* Maximum allowed credit. put() will check against it. */ + int pool_sz; + + /* + * Allocate a pool table statically. + * + * Currently the mamimum allowed size is MAX_MAC_CREDIT_E2(272) + * + * The set bit in the table will mean that the entry is available. + */ +#define BNX2X_POOL_VEC_SIZE (MAX_MAC_CREDIT_E2 / 64) + u64 pool_mirror[BNX2X_POOL_VEC_SIZE]; + + /* Base pool offset (initialized differently */ + int base_pool_offset; + + /** + * Get the next free pool entry. + * + * @return true if there was a free entry in the pool + */ + bool (*get_entry)(struct bnx2x_credit_pool_obj *o, int *entry); + + /** + * Return the entry back to the pool. + * + * @return true if entry is legal and has been successfully + * returned to the pool. + */ + bool (*put_entry)(struct bnx2x_credit_pool_obj *o, int entry); + + /** + * Get the requested amount of credit from the pool. + * + * @param cnt Amount of requested credit + * @return true if the operation is successful + */ + bool (*get)(struct bnx2x_credit_pool_obj *o, int cnt); + + /** + * Returns the credit to the pool. + * + * @param cnt Amount of credit to return + * @return true if the operation is successful + */ + bool (*put)(struct bnx2x_credit_pool_obj *o, int cnt); + + /** + * Reads the current amount of credit. + */ + int (*check)(struct bnx2x_credit_pool_obj *o); +}; + +/*************************** RSS configuration ********************************/ +enum { + /* RSS_MODE bits are mutually exclusive */ + BNX2X_RSS_MODE_DISABLED, + BNX2X_RSS_MODE_REGULAR, + BNX2X_RSS_MODE_VLAN_PRI, + BNX2X_RSS_MODE_E1HOV_PRI, + BNX2X_RSS_MODE_IP_DSCP, + + BNX2X_RSS_SET_SRCH, /* Setup searcher, E1x specific flag */ + + BNX2X_RSS_IPV4, + BNX2X_RSS_IPV4_TCP, + BNX2X_RSS_IPV6, + BNX2X_RSS_IPV6_TCP, +}; + +struct bnx2x_config_rss_params { + struct bnx2x_rss_config_obj *rss_obj; + + /* may have RAMROD_COMP_WAIT set only */ + unsigned long ramrod_flags; + + /* BNX2X_RSS_X bits */ + unsigned long rss_flags; + + /* Number hash bits to take into an account */ + u8 rss_result_mask; + + /* Indirection table */ + u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE]; + + /* RSS hash values */ + u32 rss_key[10]; + + /* valid only iff BNX2X_RSS_UPDATE_TOE is set */ + u16 toe_rss_bitmap; +}; + +struct bnx2x_rss_config_obj { + struct bnx2x_raw_obj raw; + + /* RSS engine to use */ + u8 engine_id; + + /* Last configured indirection table */ + u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE]; + + int (*config_rss)(struct bnx2x *bp, + struct bnx2x_config_rss_params *p); +}; + +/*********************** Queue state update ***********************************/ + +/* UPDATE command options */ +enum { + BNX2X_Q_UPDATE_IN_VLAN_REM, + BNX2X_Q_UPDATE_IN_VLAN_REM_CHNG, + BNX2X_Q_UPDATE_OUT_VLAN_REM, + BNX2X_Q_UPDATE_OUT_VLAN_REM_CHNG, + BNX2X_Q_UPDATE_ANTI_SPOOF, + BNX2X_Q_UPDATE_ANTI_SPOOF_CHNG, + BNX2X_Q_UPDATE_ACTIVATE, + BNX2X_Q_UPDATE_ACTIVATE_CHNG, + BNX2X_Q_UPDATE_DEF_VLAN_EN, + BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG, + BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG, + BNX2X_Q_UPDATE_SILENT_VLAN_REM +}; + +/* Allowed Queue states */ +enum bnx2x_q_state { + BNX2X_Q_STATE_RESET, + BNX2X_Q_STATE_INITIALIZED, + BNX2X_Q_STATE_ACTIVE, + BNX2X_Q_STATE_MULTI_COS, + BNX2X_Q_STATE_MCOS_TERMINATED, + BNX2X_Q_STATE_INACTIVE, + BNX2X_Q_STATE_STOPPED, + BNX2X_Q_STATE_TERMINATED, + BNX2X_Q_STATE_FLRED, + BNX2X_Q_STATE_MAX, +}; + +/* Allowed commands */ +enum bnx2x_queue_cmd { + BNX2X_Q_CMD_INIT, + BNX2X_Q_CMD_SETUP, + BNX2X_Q_CMD_SETUP_TX_ONLY, + BNX2X_Q_CMD_DEACTIVATE, + BNX2X_Q_CMD_ACTIVATE, + BNX2X_Q_CMD_UPDATE, + BNX2X_Q_CMD_UPDATE_TPA, + BNX2X_Q_CMD_HALT, + BNX2X_Q_CMD_CFC_DEL, + BNX2X_Q_CMD_TERMINATE, + BNX2X_Q_CMD_EMPTY, + BNX2X_Q_CMD_MAX, +}; + +/* queue SETUP + INIT flags */ +enum { + BNX2X_Q_FLG_TPA, + BNX2X_Q_FLG_TPA_IPV6, + BNX2X_Q_FLG_STATS, + BNX2X_Q_FLG_ZERO_STATS, + BNX2X_Q_FLG_ACTIVE, + BNX2X_Q_FLG_OV, + BNX2X_Q_FLG_VLAN, + BNX2X_Q_FLG_COS, + BNX2X_Q_FLG_HC, + BNX2X_Q_FLG_HC_EN, + BNX2X_Q_FLG_DHC, + BNX2X_Q_FLG_FCOE, + BNX2X_Q_FLG_LEADING_RSS, + BNX2X_Q_FLG_MCAST, + BNX2X_Q_FLG_DEF_VLAN, + BNX2X_Q_FLG_TX_SWITCH, + BNX2X_Q_FLG_TX_SEC, + BNX2X_Q_FLG_ANTI_SPOOF, + BNX2X_Q_FLG_SILENT_VLAN_REM +}; + +/* Queue type options: queue type may be a compination of below. */ +enum bnx2x_q_type { + /** TODO: Consider moving both these flags into the init() + * ramrod params. + */ + BNX2X_Q_TYPE_HAS_RX, + BNX2X_Q_TYPE_HAS_TX, +}; + +#define BNX2X_PRIMARY_CID_INDEX 0 +#define BNX2X_MULTI_TX_COS_E1X 1 +#define BNX2X_MULTI_TX_COS_E2_E3A0 2 +#define BNX2X_MULTI_TX_COS_E3B0 3 +#define BNX2X_MULTI_TX_COS BNX2X_MULTI_TX_COS_E3B0 + + +struct bnx2x_queue_init_params { + struct { + unsigned long flags; + u16 hc_rate; + u8 fw_sb_id; + u8 sb_cq_index; + } tx; + + struct { + unsigned long flags; + u16 hc_rate; + u8 fw_sb_id; + u8 sb_cq_index; + } rx; + + /* CID context in the host memory */ + struct eth_context *cxts[BNX2X_MULTI_TX_COS]; + + /* maximum number of cos supported by hardware */ + u8 max_cos; +}; + +struct bnx2x_queue_terminate_params { + /* index within the tx_only cids of this queue object */ + u8 cid_index; +}; + +struct bnx2x_queue_cfc_del_params { + /* index within the tx_only cids of this queue object */ + u8 cid_index; +}; + +struct bnx2x_queue_update_params { + unsigned long update_flags; /* BNX2X_Q_UPDATE_XX bits */ + u16 def_vlan; + u16 silent_removal_value; + u16 silent_removal_mask; +/* index within the tx_only cids of this queue object */ + u8 cid_index; +}; + +struct rxq_pause_params { + u16 bd_th_lo; + u16 bd_th_hi; + u16 rcq_th_lo; + u16 rcq_th_hi; + u16 sge_th_lo; /* valid iff BNX2X_Q_FLG_TPA */ + u16 sge_th_hi; /* valid iff BNX2X_Q_FLG_TPA */ + u16 pri_map; +}; + +/* general */ +struct bnx2x_general_setup_params { + /* valid iff BNX2X_Q_FLG_STATS */ + u8 stat_id; + + u8 spcl_id; + u16 mtu; + u8 cos; +}; + +struct bnx2x_rxq_setup_params { + /* dma */ + dma_addr_t dscr_map; + dma_addr_t sge_map; + dma_addr_t rcq_map; + dma_addr_t rcq_np_map; + + u16 drop_flags; + u16 buf_sz; + u8 fw_sb_id; + u8 cl_qzone_id; + + /* valid iff BNX2X_Q_FLG_TPA */ + u16 tpa_agg_sz; + u16 sge_buf_sz; + u8 max_sges_pkt; + u8 max_tpa_queues; + u8 rss_engine_id; + + u8 cache_line_log; + + u8 sb_cq_index; + + /* valid iff BXN2X_Q_FLG_SILENT_VLAN_REM */ + u16 silent_removal_value; + u16 silent_removal_mask; +}; + +struct bnx2x_txq_setup_params { + /* dma */ + dma_addr_t dscr_map; + + u8 fw_sb_id; + u8 sb_cq_index; + u8 cos; /* valid iff BNX2X_Q_FLG_COS */ + u16 traffic_type; + /* equals to the leading rss client id, used for TX classification*/ + u8 tss_leading_cl_id; + + /* valid iff BNX2X_Q_FLG_DEF_VLAN */ + u16 default_vlan; +}; + +struct bnx2x_queue_setup_params { + struct bnx2x_general_setup_params gen_params; + struct bnx2x_txq_setup_params txq_params; + struct bnx2x_rxq_setup_params rxq_params; + struct rxq_pause_params pause_params; + unsigned long flags; +}; + +struct bnx2x_queue_setup_tx_only_params { + struct bnx2x_general_setup_params gen_params; + struct bnx2x_txq_setup_params txq_params; + unsigned long flags; + /* index within the tx_only cids of this queue object */ + u8 cid_index; +}; + +struct bnx2x_queue_state_params { + struct bnx2x_queue_sp_obj *q_obj; + + /* Current command */ + enum bnx2x_queue_cmd cmd; + + /* may have RAMROD_COMP_WAIT set only */ + unsigned long ramrod_flags; + + /* Params according to the current command */ + union { + struct bnx2x_queue_update_params update; + struct bnx2x_queue_setup_params setup; + struct bnx2x_queue_init_params init; + struct bnx2x_queue_setup_tx_only_params tx_only; + struct bnx2x_queue_terminate_params terminate; + struct bnx2x_queue_cfc_del_params cfc_del; + } params; +}; + +struct bnx2x_queue_sp_obj { + u32 cids[BNX2X_MULTI_TX_COS]; + u8 cl_id; + u8 func_id; + + /* + * number of traffic classes supported by queue. + * The primary connection of the queue suppotrs the first traffic + * class. Any further traffic class is suppoted by a tx-only + * connection. + * + * Therefore max_cos is also a number of valid entries in the cids + * array. + */ + u8 max_cos; + u8 num_tx_only, next_tx_only; + + enum bnx2x_q_state state, next_state; + + /* bits from enum bnx2x_q_type */ + unsigned long type; + + /* BNX2X_Q_CMD_XX bits. This object implements "one + * pending" paradigm but for debug and tracing purposes it's + * more convinient to have different bits for different + * commands. + */ + unsigned long pending; + + /* Buffer to use as a ramrod data and its mapping */ + void *rdata; + dma_addr_t rdata_mapping; + + /** + * Performs one state change according to the given parameters. + * + * @return 0 in case of success and negative value otherwise. + */ + int (*send_cmd)(struct bnx2x *bp, + struct bnx2x_queue_state_params *params); + + /** + * Sets the pending bit according to the requested transition. + */ + int (*set_pending)(struct bnx2x_queue_sp_obj *o, + struct bnx2x_queue_state_params *params); + + /** + * Checks that the requested state transition is legal. + */ + int (*check_transition)(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *o, + struct bnx2x_queue_state_params *params); + + /** + * Completes the pending command. + */ + int (*complete_cmd)(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *o, + enum bnx2x_queue_cmd); + + int (*wait_comp)(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *o, + enum bnx2x_queue_cmd cmd); +}; + +/********************** Function state update *********************************/ +/* Allowed Function states */ +enum bnx2x_func_state { + BNX2X_F_STATE_RESET, + BNX2X_F_STATE_INITIALIZED, + BNX2X_F_STATE_STARTED, + BNX2X_F_STATE_TX_STOPPED, + BNX2X_F_STATE_MAX, +}; + +/* Allowed Function commands */ +enum bnx2x_func_cmd { + BNX2X_F_CMD_HW_INIT, + BNX2X_F_CMD_START, + BNX2X_F_CMD_STOP, + BNX2X_F_CMD_HW_RESET, + BNX2X_F_CMD_TX_STOP, + BNX2X_F_CMD_TX_START, + BNX2X_F_CMD_MAX, +}; + +struct bnx2x_func_hw_init_params { + /* A load phase returned by MCP. + * + * May be: + * FW_MSG_CODE_DRV_LOAD_COMMON_CHIP + * FW_MSG_CODE_DRV_LOAD_COMMON + * FW_MSG_CODE_DRV_LOAD_PORT + * FW_MSG_CODE_DRV_LOAD_FUNCTION + */ + u32 load_phase; +}; + +struct bnx2x_func_hw_reset_params { + /* A load phase returned by MCP. + * + * May be: + * FW_MSG_CODE_DRV_LOAD_COMMON_CHIP + * FW_MSG_CODE_DRV_LOAD_COMMON + * FW_MSG_CODE_DRV_LOAD_PORT + * FW_MSG_CODE_DRV_LOAD_FUNCTION + */ + u32 reset_phase; +}; + +struct bnx2x_func_start_params { + /* Multi Function mode: + * - Single Function + * - Switch Dependent + * - Switch Independent + */ + u16 mf_mode; + + /* Switch Dependent mode outer VLAN tag */ + u16 sd_vlan_tag; + + /* Function cos mode */ + u8 network_cos_mode; +}; + +struct bnx2x_func_tx_start_params { + struct priority_cos traffic_type_to_priority_cos[MAX_TRAFFIC_TYPES]; + u8 dcb_enabled; + u8 dcb_version; + u8 dont_add_pri_0_en; +}; + +struct bnx2x_func_state_params { + struct bnx2x_func_sp_obj *f_obj; + + /* Current command */ + enum bnx2x_func_cmd cmd; + + /* may have RAMROD_COMP_WAIT set only */ + unsigned long ramrod_flags; + + /* Params according to the current command */ + union { + struct bnx2x_func_hw_init_params hw_init; + struct bnx2x_func_hw_reset_params hw_reset; + struct bnx2x_func_start_params start; + struct bnx2x_func_tx_start_params tx_start; + } params; +}; + +struct bnx2x_func_sp_drv_ops { + /* Init tool + runtime initialization: + * - Common Chip + * - Common (per Path) + * - Port + * - Function phases + */ + int (*init_hw_cmn_chip)(struct bnx2x *bp); + int (*init_hw_cmn)(struct bnx2x *bp); + int (*init_hw_port)(struct bnx2x *bp); + int (*init_hw_func)(struct bnx2x *bp); + + /* Reset Function HW: Common, Port, Function phases. */ + void (*reset_hw_cmn)(struct bnx2x *bp); + void (*reset_hw_port)(struct bnx2x *bp); + void (*reset_hw_func)(struct bnx2x *bp); + + /* Init/Free GUNZIP resources */ + int (*gunzip_init)(struct bnx2x *bp); + void (*gunzip_end)(struct bnx2x *bp); + + /* Prepare/Release FW resources */ + int (*init_fw)(struct bnx2x *bp); + void (*release_fw)(struct bnx2x *bp); +}; + +struct bnx2x_func_sp_obj { + enum bnx2x_func_state state, next_state; + + /* BNX2X_FUNC_CMD_XX bits. This object implements "one + * pending" paradigm but for debug and tracing purposes it's + * more convinient to have different bits for different + * commands. + */ + unsigned long pending; + + /* Buffer to use as a ramrod data and its mapping */ + void *rdata; + dma_addr_t rdata_mapping; + + /* this mutex validates that when pending flag is taken, the next + * ramrod to be sent will be the one set the pending bit + */ + struct mutex one_pending_mutex; + + /* Driver interface */ + struct bnx2x_func_sp_drv_ops *drv; + + /** + * Performs one state change according to the given parameters. + * + * @return 0 in case of success and negative value otherwise. + */ + int (*send_cmd)(struct bnx2x *bp, + struct bnx2x_func_state_params *params); + + /** + * Checks that the requested state transition is legal. + */ + int (*check_transition)(struct bnx2x *bp, + struct bnx2x_func_sp_obj *o, + struct bnx2x_func_state_params *params); + + /** + * Completes the pending command. + */ + int (*complete_cmd)(struct bnx2x *bp, + struct bnx2x_func_sp_obj *o, + enum bnx2x_func_cmd cmd); + + int (*wait_comp)(struct bnx2x *bp, struct bnx2x_func_sp_obj *o, + enum bnx2x_func_cmd cmd); +}; + +/********************** Interfaces ********************************************/ +/* Queueable objects set */ +union bnx2x_qable_obj { + struct bnx2x_vlan_mac_obj vlan_mac; +}; +/************** Function state update *********/ +void bnx2x_init_func_obj(struct bnx2x *bp, + struct bnx2x_func_sp_obj *obj, + void *rdata, dma_addr_t rdata_mapping, + struct bnx2x_func_sp_drv_ops *drv_iface); + +int bnx2x_func_state_change(struct bnx2x *bp, + struct bnx2x_func_state_params *params); + +enum bnx2x_func_state bnx2x_func_get_state(struct bnx2x *bp, + struct bnx2x_func_sp_obj *o); +/******************* Queue State **************/ +void bnx2x_init_queue_obj(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *obj, u8 cl_id, u32 *cids, + u8 cid_cnt, u8 func_id, void *rdata, + dma_addr_t rdata_mapping, unsigned long type); + +int bnx2x_queue_state_change(struct bnx2x *bp, + struct bnx2x_queue_state_params *params); + +/********************* VLAN-MAC ****************/ +void bnx2x_init_mac_obj(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *mac_obj, + u8 cl_id, u32 cid, u8 func_id, void *rdata, + dma_addr_t rdata_mapping, int state, + unsigned long *pstate, bnx2x_obj_type type, + struct bnx2x_credit_pool_obj *macs_pool); + +void bnx2x_init_vlan_obj(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *vlan_obj, + u8 cl_id, u32 cid, u8 func_id, void *rdata, + dma_addr_t rdata_mapping, int state, + unsigned long *pstate, bnx2x_obj_type type, + struct bnx2x_credit_pool_obj *vlans_pool); + +void bnx2x_init_vlan_mac_obj(struct bnx2x *bp, + struct bnx2x_vlan_mac_obj *vlan_mac_obj, + u8 cl_id, u32 cid, u8 func_id, void *rdata, + dma_addr_t rdata_mapping, int state, + unsigned long *pstate, bnx2x_obj_type type, + struct bnx2x_credit_pool_obj *macs_pool, + struct bnx2x_credit_pool_obj *vlans_pool); + +int bnx2x_config_vlan_mac(struct bnx2x *bp, + struct bnx2x_vlan_mac_ramrod_params *p); + +int bnx2x_vlan_mac_move(struct bnx2x *bp, + struct bnx2x_vlan_mac_ramrod_params *p, + struct bnx2x_vlan_mac_obj *dest_o); + +/********************* RX MODE ****************/ + +void bnx2x_init_rx_mode_obj(struct bnx2x *bp, + struct bnx2x_rx_mode_obj *o); + +/** + * Send and RX_MODE ramrod according to the provided parameters. + * + * @param bp + * @param p Command parameters + * + * @return 0 - if operation was successfull and there is no pending completions, + * positive number - if there are pending completions, + * negative - if there were errors + */ +int bnx2x_config_rx_mode(struct bnx2x *bp, + struct bnx2x_rx_mode_ramrod_params *p); + +/****************** MULTICASTS ****************/ + +void bnx2x_init_mcast_obj(struct bnx2x *bp, + struct bnx2x_mcast_obj *mcast_obj, + u8 mcast_cl_id, u32 mcast_cid, u8 func_id, + u8 engine_id, void *rdata, dma_addr_t rdata_mapping, + int state, unsigned long *pstate, + bnx2x_obj_type type); + +/** + * Configure multicast MACs list. May configure a new list + * provided in p->mcast_list (BNX2X_MCAST_CMD_ADD), clean up + * (BNX2X_MCAST_CMD_DEL) or restore (BNX2X_MCAST_CMD_RESTORE) a current + * configuration, continue to execute the pending commands + * (BNX2X_MCAST_CMD_CONT). + * + * If previous command is still pending or if number of MACs to + * configure is more that maximum number of MACs in one command, + * the current command will be enqueued to the tail of the + * pending commands list. + * + * @param bp + * @param p + * @param command to execute: BNX2X_MCAST_CMD_X + * + * @return 0 is operation was sucessfull and there are no pending completions, + * negative if there were errors, positive if there are pending + * completions. + */ +int bnx2x_config_mcast(struct bnx2x *bp, + struct bnx2x_mcast_ramrod_params *p, int cmd); + +/****************** CREDIT POOL ****************/ +void bnx2x_init_mac_credit_pool(struct bnx2x *bp, + struct bnx2x_credit_pool_obj *p, u8 func_id, + u8 func_num); +void bnx2x_init_vlan_credit_pool(struct bnx2x *bp, + struct bnx2x_credit_pool_obj *p, u8 func_id, + u8 func_num); + + +/****************** RSS CONFIGURATION ****************/ +void bnx2x_init_rss_config_obj(struct bnx2x *bp, + struct bnx2x_rss_config_obj *rss_obj, + u8 cl_id, u32 cid, u8 func_id, u8 engine_id, + void *rdata, dma_addr_t rdata_mapping, + int state, unsigned long *pstate, + bnx2x_obj_type type); + +/** + * Updates RSS configuration according to provided parameters. + * + * @param bp + * @param p + * + * @return 0 in case of success + */ +int bnx2x_config_rss(struct bnx2x *bp, + struct bnx2x_config_rss_params *p); + +/** + * Return the current ind_table configuration. + * + * @param bp + * @param ind_table buffer to fill with the current indirection + * table content. Should be at least + * T_ETH_INDIRECTION_TABLE_SIZE bytes long. + */ +void bnx2x_get_rss_ind_table(struct bnx2x_rss_config_obj *rss_obj, + u8 *ind_table); + +#endif /* BNX2X_SP_VERBS */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c new file mode 100644 index 000000000000..771f6803b238 --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c @@ -0,0 +1,1598 @@ +/* bnx2x_stats.c: Broadcom Everest network driver. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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: Eilon Greenstein + * 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 + * + */ +#include "bnx2x_stats.h" +#include "bnx2x_cmn.h" + + +/* Statistics */ + +/* + * General service functions + */ + +static inline long bnx2x_hilo(u32 *hiref) +{ + u32 lo = *(hiref + 1); +#if (BITS_PER_LONG == 64) + u32 hi = *hiref; + + return HILO_U64(hi, lo); +#else + return lo; +#endif +} + +/* + * Init service functions + */ + +/* Post the next statistics ramrod. Protect it with the spin in + * order to ensure the strict order between statistics ramrods + * (each ramrod has a sequence number passed in a + * bp->fw_stats_req->hdr.drv_stats_counter and ramrods must be + * sent in order). + */ +static void bnx2x_storm_stats_post(struct bnx2x *bp) +{ + if (!bp->stats_pending) { + int rc; + + spin_lock_bh(&bp->stats_lock); + + if (bp->stats_pending) { + spin_unlock_bh(&bp->stats_lock); + return; + } + + bp->fw_stats_req->hdr.drv_stats_counter = + cpu_to_le16(bp->stats_counter++); + + DP(NETIF_MSG_TIMER, "Sending statistics ramrod %d\n", + bp->fw_stats_req->hdr.drv_stats_counter); + + + + /* send FW stats ramrod */ + rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_STAT_QUERY, 0, + U64_HI(bp->fw_stats_req_mapping), + U64_LO(bp->fw_stats_req_mapping), + NONE_CONNECTION_TYPE); + if (rc == 0) + bp->stats_pending = 1; + + spin_unlock_bh(&bp->stats_lock); + } +} + +static void bnx2x_hw_stats_post(struct bnx2x *bp) +{ + struct dmae_command *dmae = &bp->stats_dmae; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + *stats_comp = DMAE_COMP_VAL; + if (CHIP_REV_IS_SLOW(bp)) + return; + + /* loader */ + if (bp->executer_idx) { + int loader_idx = PMF_DMAE_C(bp); + u32 opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_PCI, DMAE_DST_GRC, + true, DMAE_COMP_GRC); + opcode = bnx2x_dmae_opcode_clr_src_reset(opcode); + + memset(dmae, 0, sizeof(struct dmae_command)); + dmae->opcode = opcode; + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, dmae[0])); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, dmae[0])); + dmae->dst_addr_lo = (DMAE_REG_CMD_MEM + + sizeof(struct dmae_command) * + (loader_idx + 1)) >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct dmae_command) >> 2; + if (CHIP_IS_E1(bp)) + dmae->len--; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx + 1] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + *stats_comp = 0; + bnx2x_post_dmae(bp, dmae, loader_idx); + + } else if (bp->func_stx) { + *stats_comp = 0; + bnx2x_post_dmae(bp, dmae, INIT_DMAE_C(bp)); + } +} + +static int bnx2x_stats_comp(struct bnx2x *bp) +{ + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + int cnt = 10; + + might_sleep(); + while (*stats_comp != DMAE_COMP_VAL) { + if (!cnt) { + BNX2X_ERR("timeout waiting for stats finished\n"); + break; + } + cnt--; + usleep_range(1000, 1000); + } + return 1; +} + +/* + * Statistics service functions + */ + +static void bnx2x_stats_pmf_update(struct bnx2x *bp) +{ + struct dmae_command *dmae; + u32 opcode; + int loader_idx = PMF_DMAE_C(bp); + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!IS_MF(bp) || !bp->port.pmf || !bp->port.port_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + + opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_GRC, DMAE_DST_PCI, false, 0); + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = bnx2x_dmae_opcode_add_comp(opcode, DMAE_COMP_GRC); + dmae->src_addr_lo = bp->port.port_stx >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats)); + dmae->len = DMAE_LEN32_RD_MAX; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = bnx2x_dmae_opcode_add_comp(opcode, DMAE_COMP_PCI); + dmae->src_addr_lo = (bp->port.port_stx >> 2) + DMAE_LEN32_RD_MAX; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats) + + DMAE_LEN32_RD_MAX * 4); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats) + + DMAE_LEN32_RD_MAX * 4); + dmae->len = (sizeof(struct host_port_stats) >> 2) - DMAE_LEN32_RD_MAX; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); +} + +static void bnx2x_port_stats_init(struct bnx2x *bp) +{ + struct dmae_command *dmae; + int port = BP_PORT(bp); + u32 opcode; + int loader_idx = PMF_DMAE_C(bp); + u32 mac_addr; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!bp->link_vars.link_up || !bp->port.pmf) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + + /* MCP */ + opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_PCI, DMAE_DST_GRC, + true, DMAE_COMP_GRC); + + if (bp->port.port_stx) { + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats)); + dmae->dst_addr_lo = bp->port.port_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_port_stats) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } + + if (bp->func_stx) { + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats)); + dmae->dst_addr_lo = bp->func_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_func_stats) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } + + /* MAC */ + opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_GRC, DMAE_DST_PCI, + true, DMAE_COMP_GRC); + + /* EMAC is special */ + if (bp->link_vars.mac_type == MAC_TYPE_EMAC) { + mac_addr = (port ? GRCBASE_EMAC1 : GRCBASE_EMAC0); + + /* EMAC_REG_EMAC_RX_STAT_AC (EMAC_REG_EMAC_RX_STAT_AC_COUNT)*/ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + EMAC_REG_EMAC_RX_STAT_AC) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats)); + dmae->len = EMAC_REG_EMAC_RX_STAT_AC_COUNT; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + /* EMAC_REG_EMAC_RX_STAT_AC_28 */ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + EMAC_REG_EMAC_RX_STAT_AC_28) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, rx_stat_falsecarriererrors)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, rx_stat_falsecarriererrors)); + dmae->len = 1; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + /* EMAC_REG_EMAC_TX_STAT_AC (EMAC_REG_EMAC_TX_STAT_AC_COUNT)*/ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (mac_addr + + EMAC_REG_EMAC_TX_STAT_AC) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, tx_stat_ifhcoutoctets)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats) + + offsetof(struct emac_stats, tx_stat_ifhcoutoctets)); + dmae->len = EMAC_REG_EMAC_TX_STAT_AC_COUNT; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } else { + u32 tx_src_addr_lo, rx_src_addr_lo; + u16 rx_len, tx_len; + + /* configure the params according to MAC type */ + switch (bp->link_vars.mac_type) { + case MAC_TYPE_BMAC: + mac_addr = (port ? NIG_REG_INGRESS_BMAC1_MEM : + NIG_REG_INGRESS_BMAC0_MEM); + + /* BIGMAC_REGISTER_TX_STAT_GTPKT .. + BIGMAC_REGISTER_TX_STAT_GTBYT */ + if (CHIP_IS_E1x(bp)) { + tx_src_addr_lo = (mac_addr + + BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2; + tx_len = (8 + BIGMAC_REGISTER_TX_STAT_GTBYT - + BIGMAC_REGISTER_TX_STAT_GTPKT) >> 2; + rx_src_addr_lo = (mac_addr + + BIGMAC_REGISTER_RX_STAT_GR64) >> 2; + rx_len = (8 + BIGMAC_REGISTER_RX_STAT_GRIPJ - + BIGMAC_REGISTER_RX_STAT_GR64) >> 2; + } else { + tx_src_addr_lo = (mac_addr + + BIGMAC2_REGISTER_TX_STAT_GTPOK) >> 2; + tx_len = (8 + BIGMAC2_REGISTER_TX_STAT_GTBYT - + BIGMAC2_REGISTER_TX_STAT_GTPOK) >> 2; + rx_src_addr_lo = (mac_addr + + BIGMAC2_REGISTER_RX_STAT_GR64) >> 2; + rx_len = (8 + BIGMAC2_REGISTER_RX_STAT_GRIPJ - + BIGMAC2_REGISTER_RX_STAT_GR64) >> 2; + } + break; + + case MAC_TYPE_UMAC: /* handled by MSTAT */ + case MAC_TYPE_XMAC: /* handled by MSTAT */ + default: + mac_addr = port ? GRCBASE_MSTAT1 : GRCBASE_MSTAT0; + tx_src_addr_lo = (mac_addr + + MSTAT_REG_TX_STAT_GTXPOK_LO) >> 2; + rx_src_addr_lo = (mac_addr + + MSTAT_REG_RX_STAT_GR64_LO) >> 2; + tx_len = sizeof(bp->slowpath-> + mac_stats.mstat_stats.stats_tx) >> 2; + rx_len = sizeof(bp->slowpath-> + mac_stats.mstat_stats.stats_rx) >> 2; + break; + } + + /* TX stats */ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = tx_src_addr_lo; + dmae->src_addr_hi = 0; + dmae->len = tx_len; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, mac_stats)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, mac_stats)); + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + /* RX stats */ + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_hi = 0; + dmae->src_addr_lo = rx_src_addr_lo; + dmae->dst_addr_lo = + U64_LO(bnx2x_sp_mapping(bp, mac_stats) + (tx_len << 2)); + dmae->dst_addr_hi = + U64_HI(bnx2x_sp_mapping(bp, mac_stats) + (tx_len << 2)); + dmae->len = rx_len; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } + + /* NIG */ + if (!CHIP_IS_E3(bp)) { + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT0 : + NIG_REG_STAT0_EGRESS_MAC_PKT0) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) + + offsetof(struct nig_stats, egress_mac_pkt0_lo)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) + + offsetof(struct nig_stats, egress_mac_pkt0_lo)); + dmae->len = (2*sizeof(u32)) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = opcode; + dmae->src_addr_lo = (port ? NIG_REG_STAT1_EGRESS_MAC_PKT1 : + NIG_REG_STAT0_EGRESS_MAC_PKT1) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats) + + offsetof(struct nig_stats, egress_mac_pkt1_lo)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats) + + offsetof(struct nig_stats, egress_mac_pkt1_lo)); + dmae->len = (2*sizeof(u32)) >> 2; + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_GRC, DMAE_DST_PCI, + true, DMAE_COMP_PCI); + dmae->src_addr_lo = (port ? NIG_REG_STAT1_BRB_DISCARD : + NIG_REG_STAT0_BRB_DISCARD) >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, nig_stats)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, nig_stats)); + dmae->len = (sizeof(struct nig_stats) - 4*sizeof(u32)) >> 2; + + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; +} + +static void bnx2x_func_stats_init(struct bnx2x *bp) +{ + struct dmae_command *dmae = &bp->stats_dmae; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!bp->func_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + memset(dmae, 0, sizeof(struct dmae_command)); + + dmae->opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_PCI, DMAE_DST_GRC, + true, DMAE_COMP_PCI); + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats)); + dmae->dst_addr_lo = bp->func_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_func_stats) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; +} + +static void bnx2x_stats_start(struct bnx2x *bp) +{ + if (bp->port.pmf) + bnx2x_port_stats_init(bp); + + else if (bp->func_stx) + bnx2x_func_stats_init(bp); + + bnx2x_hw_stats_post(bp); + bnx2x_storm_stats_post(bp); +} + +static void bnx2x_stats_pmf_start(struct bnx2x *bp) +{ + bnx2x_stats_comp(bp); + bnx2x_stats_pmf_update(bp); + bnx2x_stats_start(bp); +} + +static void bnx2x_stats_restart(struct bnx2x *bp) +{ + bnx2x_stats_comp(bp); + bnx2x_stats_start(bp); +} + +static void bnx2x_bmac_stats_update(struct bnx2x *bp) +{ + struct host_port_stats *pstats = bnx2x_sp(bp, port_stats); + struct bnx2x_eth_stats *estats = &bp->eth_stats; + struct { + u32 lo; + u32 hi; + } diff; + + if (CHIP_IS_E1x(bp)) { + struct bmac1_stats *new = bnx2x_sp(bp, mac_stats.bmac1_stats); + + /* the macros below will use "bmac1_stats" type */ + UPDATE_STAT64(rx_stat_grerb, rx_stat_ifhcinbadoctets); + UPDATE_STAT64(rx_stat_grfcs, rx_stat_dot3statsfcserrors); + UPDATE_STAT64(rx_stat_grund, rx_stat_etherstatsundersizepkts); + UPDATE_STAT64(rx_stat_grovr, rx_stat_dot3statsframestoolong); + UPDATE_STAT64(rx_stat_grfrg, rx_stat_etherstatsfragments); + UPDATE_STAT64(rx_stat_grjbr, rx_stat_etherstatsjabbers); + UPDATE_STAT64(rx_stat_grxcf, rx_stat_maccontrolframesreceived); + UPDATE_STAT64(rx_stat_grxpf, rx_stat_xoffstateentered); + UPDATE_STAT64(rx_stat_grxpf, rx_stat_mac_xpf); + + UPDATE_STAT64(tx_stat_gtxpf, tx_stat_outxoffsent); + UPDATE_STAT64(tx_stat_gtxpf, tx_stat_flowcontroldone); + UPDATE_STAT64(tx_stat_gt64, tx_stat_etherstatspkts64octets); + UPDATE_STAT64(tx_stat_gt127, + tx_stat_etherstatspkts65octetsto127octets); + UPDATE_STAT64(tx_stat_gt255, + tx_stat_etherstatspkts128octetsto255octets); + UPDATE_STAT64(tx_stat_gt511, + tx_stat_etherstatspkts256octetsto511octets); + UPDATE_STAT64(tx_stat_gt1023, + tx_stat_etherstatspkts512octetsto1023octets); + UPDATE_STAT64(tx_stat_gt1518, + tx_stat_etherstatspkts1024octetsto1522octets); + UPDATE_STAT64(tx_stat_gt2047, tx_stat_mac_2047); + UPDATE_STAT64(tx_stat_gt4095, tx_stat_mac_4095); + UPDATE_STAT64(tx_stat_gt9216, tx_stat_mac_9216); + UPDATE_STAT64(tx_stat_gt16383, tx_stat_mac_16383); + UPDATE_STAT64(tx_stat_gterr, + tx_stat_dot3statsinternalmactransmiterrors); + UPDATE_STAT64(tx_stat_gtufl, tx_stat_mac_ufl); + + } else { + struct bmac2_stats *new = bnx2x_sp(bp, mac_stats.bmac2_stats); + + /* the macros below will use "bmac2_stats" type */ + UPDATE_STAT64(rx_stat_grerb, rx_stat_ifhcinbadoctets); + UPDATE_STAT64(rx_stat_grfcs, rx_stat_dot3statsfcserrors); + UPDATE_STAT64(rx_stat_grund, rx_stat_etherstatsundersizepkts); + UPDATE_STAT64(rx_stat_grovr, rx_stat_dot3statsframestoolong); + UPDATE_STAT64(rx_stat_grfrg, rx_stat_etherstatsfragments); + UPDATE_STAT64(rx_stat_grjbr, rx_stat_etherstatsjabbers); + UPDATE_STAT64(rx_stat_grxcf, rx_stat_maccontrolframesreceived); + UPDATE_STAT64(rx_stat_grxpf, rx_stat_xoffstateentered); + UPDATE_STAT64(rx_stat_grxpf, rx_stat_mac_xpf); + UPDATE_STAT64(tx_stat_gtxpf, tx_stat_outxoffsent); + UPDATE_STAT64(tx_stat_gtxpf, tx_stat_flowcontroldone); + UPDATE_STAT64(tx_stat_gt64, tx_stat_etherstatspkts64octets); + UPDATE_STAT64(tx_stat_gt127, + tx_stat_etherstatspkts65octetsto127octets); + UPDATE_STAT64(tx_stat_gt255, + tx_stat_etherstatspkts128octetsto255octets); + UPDATE_STAT64(tx_stat_gt511, + tx_stat_etherstatspkts256octetsto511octets); + UPDATE_STAT64(tx_stat_gt1023, + tx_stat_etherstatspkts512octetsto1023octets); + UPDATE_STAT64(tx_stat_gt1518, + tx_stat_etherstatspkts1024octetsto1522octets); + UPDATE_STAT64(tx_stat_gt2047, tx_stat_mac_2047); + UPDATE_STAT64(tx_stat_gt4095, tx_stat_mac_4095); + UPDATE_STAT64(tx_stat_gt9216, tx_stat_mac_9216); + UPDATE_STAT64(tx_stat_gt16383, tx_stat_mac_16383); + UPDATE_STAT64(tx_stat_gterr, + tx_stat_dot3statsinternalmactransmiterrors); + UPDATE_STAT64(tx_stat_gtufl, tx_stat_mac_ufl); + } + + estats->pause_frames_received_hi = + pstats->mac_stx[1].rx_stat_mac_xpf_hi; + estats->pause_frames_received_lo = + pstats->mac_stx[1].rx_stat_mac_xpf_lo; + + estats->pause_frames_sent_hi = + pstats->mac_stx[1].tx_stat_outxoffsent_hi; + estats->pause_frames_sent_lo = + pstats->mac_stx[1].tx_stat_outxoffsent_lo; +} + +static void bnx2x_mstat_stats_update(struct bnx2x *bp) +{ + struct host_port_stats *pstats = bnx2x_sp(bp, port_stats); + struct bnx2x_eth_stats *estats = &bp->eth_stats; + + struct mstat_stats *new = bnx2x_sp(bp, mac_stats.mstat_stats); + + ADD_STAT64(stats_rx.rx_grerb, rx_stat_ifhcinbadoctets); + ADD_STAT64(stats_rx.rx_grfcs, rx_stat_dot3statsfcserrors); + ADD_STAT64(stats_rx.rx_grund, rx_stat_etherstatsundersizepkts); + ADD_STAT64(stats_rx.rx_grovr, rx_stat_dot3statsframestoolong); + ADD_STAT64(stats_rx.rx_grfrg, rx_stat_etherstatsfragments); + ADD_STAT64(stats_rx.rx_grxcf, rx_stat_maccontrolframesreceived); + ADD_STAT64(stats_rx.rx_grxpf, rx_stat_xoffstateentered); + ADD_STAT64(stats_rx.rx_grxpf, rx_stat_mac_xpf); + ADD_STAT64(stats_tx.tx_gtxpf, tx_stat_outxoffsent); + ADD_STAT64(stats_tx.tx_gtxpf, tx_stat_flowcontroldone); + + + ADD_STAT64(stats_tx.tx_gt64, tx_stat_etherstatspkts64octets); + ADD_STAT64(stats_tx.tx_gt127, + tx_stat_etherstatspkts65octetsto127octets); + ADD_STAT64(stats_tx.tx_gt255, + tx_stat_etherstatspkts128octetsto255octets); + ADD_STAT64(stats_tx.tx_gt511, + tx_stat_etherstatspkts256octetsto511octets); + ADD_STAT64(stats_tx.tx_gt1023, + tx_stat_etherstatspkts512octetsto1023octets); + ADD_STAT64(stats_tx.tx_gt1518, + tx_stat_etherstatspkts1024octetsto1522octets); + ADD_STAT64(stats_tx.tx_gt2047, tx_stat_mac_2047); + + ADD_STAT64(stats_tx.tx_gt4095, tx_stat_mac_4095); + ADD_STAT64(stats_tx.tx_gt9216, tx_stat_mac_9216); + ADD_STAT64(stats_tx.tx_gt16383, tx_stat_mac_16383); + + ADD_STAT64(stats_tx.tx_gterr, + tx_stat_dot3statsinternalmactransmiterrors); + ADD_STAT64(stats_tx.tx_gtufl, tx_stat_mac_ufl); + + ADD_64(estats->etherstatspkts1024octetsto1522octets_hi, + new->stats_tx.tx_gt1518_hi, + estats->etherstatspkts1024octetsto1522octets_lo, + new->stats_tx.tx_gt1518_lo); + + ADD_64(estats->etherstatspktsover1522octets_hi, + new->stats_tx.tx_gt2047_hi, + estats->etherstatspktsover1522octets_lo, + new->stats_tx.tx_gt2047_lo); + + ADD_64(estats->etherstatspktsover1522octets_hi, + new->stats_tx.tx_gt4095_hi, + estats->etherstatspktsover1522octets_lo, + new->stats_tx.tx_gt4095_lo); + + ADD_64(estats->etherstatspktsover1522octets_hi, + new->stats_tx.tx_gt9216_hi, + estats->etherstatspktsover1522octets_lo, + new->stats_tx.tx_gt9216_lo); + + + ADD_64(estats->etherstatspktsover1522octets_hi, + new->stats_tx.tx_gt16383_hi, + estats->etherstatspktsover1522octets_lo, + new->stats_tx.tx_gt16383_lo); + + estats->pause_frames_received_hi = + pstats->mac_stx[1].rx_stat_mac_xpf_hi; + estats->pause_frames_received_lo = + pstats->mac_stx[1].rx_stat_mac_xpf_lo; + + estats->pause_frames_sent_hi = + pstats->mac_stx[1].tx_stat_outxoffsent_hi; + estats->pause_frames_sent_lo = + pstats->mac_stx[1].tx_stat_outxoffsent_lo; +} + +static void bnx2x_emac_stats_update(struct bnx2x *bp) +{ + struct emac_stats *new = bnx2x_sp(bp, mac_stats.emac_stats); + struct host_port_stats *pstats = bnx2x_sp(bp, port_stats); + struct bnx2x_eth_stats *estats = &bp->eth_stats; + + UPDATE_EXTEND_STAT(rx_stat_ifhcinbadoctets); + UPDATE_EXTEND_STAT(tx_stat_ifhcoutbadoctets); + UPDATE_EXTEND_STAT(rx_stat_dot3statsfcserrors); + UPDATE_EXTEND_STAT(rx_stat_dot3statsalignmenterrors); + UPDATE_EXTEND_STAT(rx_stat_dot3statscarriersenseerrors); + UPDATE_EXTEND_STAT(rx_stat_falsecarriererrors); + UPDATE_EXTEND_STAT(rx_stat_etherstatsundersizepkts); + UPDATE_EXTEND_STAT(rx_stat_dot3statsframestoolong); + UPDATE_EXTEND_STAT(rx_stat_etherstatsfragments); + UPDATE_EXTEND_STAT(rx_stat_etherstatsjabbers); + UPDATE_EXTEND_STAT(rx_stat_maccontrolframesreceived); + UPDATE_EXTEND_STAT(rx_stat_xoffstateentered); + UPDATE_EXTEND_STAT(rx_stat_xonpauseframesreceived); + UPDATE_EXTEND_STAT(rx_stat_xoffpauseframesreceived); + UPDATE_EXTEND_STAT(tx_stat_outxonsent); + UPDATE_EXTEND_STAT(tx_stat_outxoffsent); + UPDATE_EXTEND_STAT(tx_stat_flowcontroldone); + UPDATE_EXTEND_STAT(tx_stat_etherstatscollisions); + UPDATE_EXTEND_STAT(tx_stat_dot3statssinglecollisionframes); + UPDATE_EXTEND_STAT(tx_stat_dot3statsmultiplecollisionframes); + UPDATE_EXTEND_STAT(tx_stat_dot3statsdeferredtransmissions); + UPDATE_EXTEND_STAT(tx_stat_dot3statsexcessivecollisions); + UPDATE_EXTEND_STAT(tx_stat_dot3statslatecollisions); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts64octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts65octetsto127octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts128octetsto255octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts256octetsto511octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts512octetsto1023octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspkts1024octetsto1522octets); + UPDATE_EXTEND_STAT(tx_stat_etherstatspktsover1522octets); + UPDATE_EXTEND_STAT(tx_stat_dot3statsinternalmactransmiterrors); + + estats->pause_frames_received_hi = + pstats->mac_stx[1].rx_stat_xonpauseframesreceived_hi; + estats->pause_frames_received_lo = + pstats->mac_stx[1].rx_stat_xonpauseframesreceived_lo; + ADD_64(estats->pause_frames_received_hi, + pstats->mac_stx[1].rx_stat_xoffpauseframesreceived_hi, + estats->pause_frames_received_lo, + pstats->mac_stx[1].rx_stat_xoffpauseframesreceived_lo); + + estats->pause_frames_sent_hi = + pstats->mac_stx[1].tx_stat_outxonsent_hi; + estats->pause_frames_sent_lo = + pstats->mac_stx[1].tx_stat_outxonsent_lo; + ADD_64(estats->pause_frames_sent_hi, + pstats->mac_stx[1].tx_stat_outxoffsent_hi, + estats->pause_frames_sent_lo, + pstats->mac_stx[1].tx_stat_outxoffsent_lo); +} + +static int bnx2x_hw_stats_update(struct bnx2x *bp) +{ + struct nig_stats *new = bnx2x_sp(bp, nig_stats); + struct nig_stats *old = &(bp->port.old_nig_stats); + struct host_port_stats *pstats = bnx2x_sp(bp, port_stats); + struct bnx2x_eth_stats *estats = &bp->eth_stats; + struct { + u32 lo; + u32 hi; + } diff; + + switch (bp->link_vars.mac_type) { + case MAC_TYPE_BMAC: + bnx2x_bmac_stats_update(bp); + break; + + case MAC_TYPE_EMAC: + bnx2x_emac_stats_update(bp); + break; + + case MAC_TYPE_UMAC: + case MAC_TYPE_XMAC: + bnx2x_mstat_stats_update(bp); + break; + + case MAC_TYPE_NONE: /* unreached */ + BNX2X_ERR("stats updated by DMAE but no MAC active\n"); + return -1; + + default: /* unreached */ + BNX2X_ERR("Unknown MAC type\n"); + } + + ADD_EXTEND_64(pstats->brb_drop_hi, pstats->brb_drop_lo, + new->brb_discard - old->brb_discard); + ADD_EXTEND_64(estats->brb_truncate_hi, estats->brb_truncate_lo, + new->brb_truncate - old->brb_truncate); + + if (!CHIP_IS_E3(bp)) { + UPDATE_STAT64_NIG(egress_mac_pkt0, + etherstatspkts1024octetsto1522octets); + UPDATE_STAT64_NIG(egress_mac_pkt1, + etherstatspktsover1522octets); + } + + memcpy(old, new, sizeof(struct nig_stats)); + + memcpy(&(estats->rx_stat_ifhcinbadoctets_hi), &(pstats->mac_stx[1]), + sizeof(struct mac_stx)); + estats->brb_drop_hi = pstats->brb_drop_hi; + estats->brb_drop_lo = pstats->brb_drop_lo; + + pstats->host_port_stats_start = ++pstats->host_port_stats_end; + + if (!BP_NOMCP(bp)) { + u32 nig_timer_max = + SHMEM_RD(bp, port_mb[BP_PORT(bp)].stat_nig_timer); + if (nig_timer_max != estats->nig_timer_max) { + estats->nig_timer_max = nig_timer_max; + BNX2X_ERR("NIG timer max (%u)\n", + estats->nig_timer_max); + } + } + + return 0; +} + +static int bnx2x_storm_stats_update(struct bnx2x *bp) +{ + struct tstorm_per_port_stats *tport = + &bp->fw_stats_data->port.tstorm_port_statistics; + struct tstorm_per_pf_stats *tfunc = + &bp->fw_stats_data->pf.tstorm_pf_statistics; + struct host_func_stats *fstats = bnx2x_sp(bp, func_stats); + struct bnx2x_eth_stats *estats = &bp->eth_stats; + struct stats_counter *counters = &bp->fw_stats_data->storm_counters; + int i; + u16 cur_stats_counter; + + /* Make sure we use the value of the counter + * used for sending the last stats ramrod. + */ + spin_lock_bh(&bp->stats_lock); + cur_stats_counter = bp->stats_counter - 1; + spin_unlock_bh(&bp->stats_lock); + + /* are storm stats valid? */ + if (le16_to_cpu(counters->xstats_counter) != cur_stats_counter) { + DP(BNX2X_MSG_STATS, "stats not updated by xstorm" + " xstorm counter (0x%x) != stats_counter (0x%x)\n", + le16_to_cpu(counters->xstats_counter), bp->stats_counter); + return -EAGAIN; + } + + if (le16_to_cpu(counters->ustats_counter) != cur_stats_counter) { + DP(BNX2X_MSG_STATS, "stats not updated by ustorm" + " ustorm counter (0x%x) != stats_counter (0x%x)\n", + le16_to_cpu(counters->ustats_counter), bp->stats_counter); + return -EAGAIN; + } + + if (le16_to_cpu(counters->cstats_counter) != cur_stats_counter) { + DP(BNX2X_MSG_STATS, "stats not updated by cstorm" + " cstorm counter (0x%x) != stats_counter (0x%x)\n", + le16_to_cpu(counters->cstats_counter), bp->stats_counter); + return -EAGAIN; + } + + if (le16_to_cpu(counters->tstats_counter) != cur_stats_counter) { + DP(BNX2X_MSG_STATS, "stats not updated by tstorm" + " tstorm counter (0x%x) != stats_counter (0x%x)\n", + le16_to_cpu(counters->tstats_counter), bp->stats_counter); + return -EAGAIN; + } + + memcpy(&(fstats->total_bytes_received_hi), + &(bnx2x_sp(bp, func_stats_base)->total_bytes_received_hi), + sizeof(struct host_func_stats) - 2*sizeof(u32)); + estats->error_bytes_received_hi = 0; + estats->error_bytes_received_lo = 0; + estats->etherstatsoverrsizepkts_hi = 0; + estats->etherstatsoverrsizepkts_lo = 0; + estats->no_buff_discard_hi = 0; + estats->no_buff_discard_lo = 0; + estats->total_tpa_aggregations_hi = 0; + estats->total_tpa_aggregations_lo = 0; + estats->total_tpa_aggregated_frames_hi = 0; + estats->total_tpa_aggregated_frames_lo = 0; + estats->total_tpa_bytes_hi = 0; + estats->total_tpa_bytes_lo = 0; + + for_each_eth_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + struct tstorm_per_queue_stats *tclient = + &bp->fw_stats_data->queue_stats[i]. + tstorm_queue_statistics; + struct tstorm_per_queue_stats *old_tclient = &fp->old_tclient; + struct ustorm_per_queue_stats *uclient = + &bp->fw_stats_data->queue_stats[i]. + ustorm_queue_statistics; + struct ustorm_per_queue_stats *old_uclient = &fp->old_uclient; + struct xstorm_per_queue_stats *xclient = + &bp->fw_stats_data->queue_stats[i]. + xstorm_queue_statistics; + struct xstorm_per_queue_stats *old_xclient = &fp->old_xclient; + struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats; + u32 diff; + + DP(BNX2X_MSG_STATS, "queue[%d]: ucast_sent 0x%x, " + "bcast_sent 0x%x mcast_sent 0x%x\n", + i, xclient->ucast_pkts_sent, + xclient->bcast_pkts_sent, xclient->mcast_pkts_sent); + + DP(BNX2X_MSG_STATS, "---------------\n"); + + qstats->total_broadcast_bytes_received_hi = + le32_to_cpu(tclient->rcv_bcast_bytes.hi); + qstats->total_broadcast_bytes_received_lo = + le32_to_cpu(tclient->rcv_bcast_bytes.lo); + + qstats->total_multicast_bytes_received_hi = + le32_to_cpu(tclient->rcv_mcast_bytes.hi); + qstats->total_multicast_bytes_received_lo = + le32_to_cpu(tclient->rcv_mcast_bytes.lo); + + qstats->total_unicast_bytes_received_hi = + le32_to_cpu(tclient->rcv_ucast_bytes.hi); + qstats->total_unicast_bytes_received_lo = + le32_to_cpu(tclient->rcv_ucast_bytes.lo); + + /* + * sum to total_bytes_received all + * unicast/multicast/broadcast + */ + qstats->total_bytes_received_hi = + qstats->total_broadcast_bytes_received_hi; + qstats->total_bytes_received_lo = + qstats->total_broadcast_bytes_received_lo; + + ADD_64(qstats->total_bytes_received_hi, + qstats->total_multicast_bytes_received_hi, + qstats->total_bytes_received_lo, + qstats->total_multicast_bytes_received_lo); + + ADD_64(qstats->total_bytes_received_hi, + qstats->total_unicast_bytes_received_hi, + qstats->total_bytes_received_lo, + qstats->total_unicast_bytes_received_lo); + + qstats->valid_bytes_received_hi = + qstats->total_bytes_received_hi; + qstats->valid_bytes_received_lo = + qstats->total_bytes_received_lo; + + + UPDATE_EXTEND_TSTAT(rcv_ucast_pkts, + total_unicast_packets_received); + UPDATE_EXTEND_TSTAT(rcv_mcast_pkts, + total_multicast_packets_received); + UPDATE_EXTEND_TSTAT(rcv_bcast_pkts, + total_broadcast_packets_received); + UPDATE_EXTEND_TSTAT(pkts_too_big_discard, + etherstatsoverrsizepkts); + UPDATE_EXTEND_TSTAT(no_buff_discard, no_buff_discard); + + SUB_EXTEND_USTAT(ucast_no_buff_pkts, + total_unicast_packets_received); + SUB_EXTEND_USTAT(mcast_no_buff_pkts, + total_multicast_packets_received); + SUB_EXTEND_USTAT(bcast_no_buff_pkts, + total_broadcast_packets_received); + UPDATE_EXTEND_USTAT(ucast_no_buff_pkts, no_buff_discard); + UPDATE_EXTEND_USTAT(mcast_no_buff_pkts, no_buff_discard); + UPDATE_EXTEND_USTAT(bcast_no_buff_pkts, no_buff_discard); + + qstats->total_broadcast_bytes_transmitted_hi = + le32_to_cpu(xclient->bcast_bytes_sent.hi); + qstats->total_broadcast_bytes_transmitted_lo = + le32_to_cpu(xclient->bcast_bytes_sent.lo); + + qstats->total_multicast_bytes_transmitted_hi = + le32_to_cpu(xclient->mcast_bytes_sent.hi); + qstats->total_multicast_bytes_transmitted_lo = + le32_to_cpu(xclient->mcast_bytes_sent.lo); + + qstats->total_unicast_bytes_transmitted_hi = + le32_to_cpu(xclient->ucast_bytes_sent.hi); + qstats->total_unicast_bytes_transmitted_lo = + le32_to_cpu(xclient->ucast_bytes_sent.lo); + /* + * sum to total_bytes_transmitted all + * unicast/multicast/broadcast + */ + qstats->total_bytes_transmitted_hi = + qstats->total_unicast_bytes_transmitted_hi; + qstats->total_bytes_transmitted_lo = + qstats->total_unicast_bytes_transmitted_lo; + + ADD_64(qstats->total_bytes_transmitted_hi, + qstats->total_broadcast_bytes_transmitted_hi, + qstats->total_bytes_transmitted_lo, + qstats->total_broadcast_bytes_transmitted_lo); + + ADD_64(qstats->total_bytes_transmitted_hi, + qstats->total_multicast_bytes_transmitted_hi, + qstats->total_bytes_transmitted_lo, + qstats->total_multicast_bytes_transmitted_lo); + + UPDATE_EXTEND_XSTAT(ucast_pkts_sent, + total_unicast_packets_transmitted); + UPDATE_EXTEND_XSTAT(mcast_pkts_sent, + total_multicast_packets_transmitted); + UPDATE_EXTEND_XSTAT(bcast_pkts_sent, + total_broadcast_packets_transmitted); + + UPDATE_EXTEND_TSTAT(checksum_discard, + total_packets_received_checksum_discarded); + UPDATE_EXTEND_TSTAT(ttl0_discard, + total_packets_received_ttl0_discarded); + + UPDATE_EXTEND_XSTAT(error_drop_pkts, + total_transmitted_dropped_packets_error); + + /* TPA aggregations completed */ + UPDATE_EXTEND_USTAT(coalesced_events, total_tpa_aggregations); + /* Number of network frames aggregated by TPA */ + UPDATE_EXTEND_USTAT(coalesced_pkts, + total_tpa_aggregated_frames); + /* Total number of bytes in completed TPA aggregations */ + qstats->total_tpa_bytes_lo = + le32_to_cpu(uclient->coalesced_bytes.lo); + qstats->total_tpa_bytes_hi = + le32_to_cpu(uclient->coalesced_bytes.hi); + + /* TPA stats per-function */ + ADD_64(estats->total_tpa_aggregations_hi, + qstats->total_tpa_aggregations_hi, + estats->total_tpa_aggregations_lo, + qstats->total_tpa_aggregations_lo); + ADD_64(estats->total_tpa_aggregated_frames_hi, + qstats->total_tpa_aggregated_frames_hi, + estats->total_tpa_aggregated_frames_lo, + qstats->total_tpa_aggregated_frames_lo); + ADD_64(estats->total_tpa_bytes_hi, + qstats->total_tpa_bytes_hi, + estats->total_tpa_bytes_lo, + qstats->total_tpa_bytes_lo); + + ADD_64(fstats->total_bytes_received_hi, + qstats->total_bytes_received_hi, + fstats->total_bytes_received_lo, + qstats->total_bytes_received_lo); + ADD_64(fstats->total_bytes_transmitted_hi, + qstats->total_bytes_transmitted_hi, + fstats->total_bytes_transmitted_lo, + qstats->total_bytes_transmitted_lo); + ADD_64(fstats->total_unicast_packets_received_hi, + qstats->total_unicast_packets_received_hi, + fstats->total_unicast_packets_received_lo, + qstats->total_unicast_packets_received_lo); + ADD_64(fstats->total_multicast_packets_received_hi, + qstats->total_multicast_packets_received_hi, + fstats->total_multicast_packets_received_lo, + qstats->total_multicast_packets_received_lo); + ADD_64(fstats->total_broadcast_packets_received_hi, + qstats->total_broadcast_packets_received_hi, + fstats->total_broadcast_packets_received_lo, + qstats->total_broadcast_packets_received_lo); + ADD_64(fstats->total_unicast_packets_transmitted_hi, + qstats->total_unicast_packets_transmitted_hi, + fstats->total_unicast_packets_transmitted_lo, + qstats->total_unicast_packets_transmitted_lo); + ADD_64(fstats->total_multicast_packets_transmitted_hi, + qstats->total_multicast_packets_transmitted_hi, + fstats->total_multicast_packets_transmitted_lo, + qstats->total_multicast_packets_transmitted_lo); + ADD_64(fstats->total_broadcast_packets_transmitted_hi, + qstats->total_broadcast_packets_transmitted_hi, + fstats->total_broadcast_packets_transmitted_lo, + qstats->total_broadcast_packets_transmitted_lo); + ADD_64(fstats->valid_bytes_received_hi, + qstats->valid_bytes_received_hi, + fstats->valid_bytes_received_lo, + qstats->valid_bytes_received_lo); + + ADD_64(estats->etherstatsoverrsizepkts_hi, + qstats->etherstatsoverrsizepkts_hi, + estats->etherstatsoverrsizepkts_lo, + qstats->etherstatsoverrsizepkts_lo); + ADD_64(estats->no_buff_discard_hi, qstats->no_buff_discard_hi, + estats->no_buff_discard_lo, qstats->no_buff_discard_lo); + } + + ADD_64(fstats->total_bytes_received_hi, + estats->rx_stat_ifhcinbadoctets_hi, + fstats->total_bytes_received_lo, + estats->rx_stat_ifhcinbadoctets_lo); + + ADD_64(fstats->total_bytes_received_hi, + tfunc->rcv_error_bytes.hi, + fstats->total_bytes_received_lo, + tfunc->rcv_error_bytes.lo); + + memcpy(estats, &(fstats->total_bytes_received_hi), + sizeof(struct host_func_stats) - 2*sizeof(u32)); + + ADD_64(estats->error_bytes_received_hi, + tfunc->rcv_error_bytes.hi, + estats->error_bytes_received_lo, + tfunc->rcv_error_bytes.lo); + + ADD_64(estats->etherstatsoverrsizepkts_hi, + estats->rx_stat_dot3statsframestoolong_hi, + estats->etherstatsoverrsizepkts_lo, + estats->rx_stat_dot3statsframestoolong_lo); + ADD_64(estats->error_bytes_received_hi, + estats->rx_stat_ifhcinbadoctets_hi, + estats->error_bytes_received_lo, + estats->rx_stat_ifhcinbadoctets_lo); + + if (bp->port.pmf) { + estats->mac_filter_discard = + le32_to_cpu(tport->mac_filter_discard); + estats->mf_tag_discard = + le32_to_cpu(tport->mf_tag_discard); + estats->brb_truncate_discard = + le32_to_cpu(tport->brb_truncate_discard); + estats->mac_discard = le32_to_cpu(tport->mac_discard); + } + + fstats->host_func_stats_start = ++fstats->host_func_stats_end; + + bp->stats_pending = 0; + + return 0; +} + +static void bnx2x_net_stats_update(struct bnx2x *bp) +{ + struct bnx2x_eth_stats *estats = &bp->eth_stats; + struct net_device_stats *nstats = &bp->dev->stats; + unsigned long tmp; + int i; + + nstats->rx_packets = + bnx2x_hilo(&estats->total_unicast_packets_received_hi) + + bnx2x_hilo(&estats->total_multicast_packets_received_hi) + + bnx2x_hilo(&estats->total_broadcast_packets_received_hi); + + nstats->tx_packets = + bnx2x_hilo(&estats->total_unicast_packets_transmitted_hi) + + bnx2x_hilo(&estats->total_multicast_packets_transmitted_hi) + + bnx2x_hilo(&estats->total_broadcast_packets_transmitted_hi); + + nstats->rx_bytes = bnx2x_hilo(&estats->total_bytes_received_hi); + + nstats->tx_bytes = bnx2x_hilo(&estats->total_bytes_transmitted_hi); + + tmp = estats->mac_discard; + for_each_rx_queue(bp, i) + tmp += le32_to_cpu(bp->fp[i].old_tclient.checksum_discard); + nstats->rx_dropped = tmp; + + nstats->tx_dropped = 0; + + nstats->multicast = + bnx2x_hilo(&estats->total_multicast_packets_received_hi); + + nstats->collisions = + bnx2x_hilo(&estats->tx_stat_etherstatscollisions_hi); + + nstats->rx_length_errors = + bnx2x_hilo(&estats->rx_stat_etherstatsundersizepkts_hi) + + bnx2x_hilo(&estats->etherstatsoverrsizepkts_hi); + nstats->rx_over_errors = bnx2x_hilo(&estats->brb_drop_hi) + + bnx2x_hilo(&estats->brb_truncate_hi); + nstats->rx_crc_errors = + bnx2x_hilo(&estats->rx_stat_dot3statsfcserrors_hi); + nstats->rx_frame_errors = + bnx2x_hilo(&estats->rx_stat_dot3statsalignmenterrors_hi); + nstats->rx_fifo_errors = bnx2x_hilo(&estats->no_buff_discard_hi); + nstats->rx_missed_errors = 0; + + nstats->rx_errors = nstats->rx_length_errors + + nstats->rx_over_errors + + nstats->rx_crc_errors + + nstats->rx_frame_errors + + nstats->rx_fifo_errors + + nstats->rx_missed_errors; + + nstats->tx_aborted_errors = + bnx2x_hilo(&estats->tx_stat_dot3statslatecollisions_hi) + + bnx2x_hilo(&estats->tx_stat_dot3statsexcessivecollisions_hi); + nstats->tx_carrier_errors = + bnx2x_hilo(&estats->rx_stat_dot3statscarriersenseerrors_hi); + nstats->tx_fifo_errors = 0; + nstats->tx_heartbeat_errors = 0; + nstats->tx_window_errors = 0; + + nstats->tx_errors = nstats->tx_aborted_errors + + nstats->tx_carrier_errors + + bnx2x_hilo(&estats->tx_stat_dot3statsinternalmactransmiterrors_hi); +} + +static void bnx2x_drv_stats_update(struct bnx2x *bp) +{ + struct bnx2x_eth_stats *estats = &bp->eth_stats; + int i; + + estats->driver_xoff = 0; + estats->rx_err_discard_pkt = 0; + estats->rx_skb_alloc_failed = 0; + estats->hw_csum_err = 0; + for_each_queue(bp, i) { + struct bnx2x_eth_q_stats *qstats = &bp->fp[i].eth_q_stats; + + estats->driver_xoff += qstats->driver_xoff; + estats->rx_err_discard_pkt += qstats->rx_err_discard_pkt; + estats->rx_skb_alloc_failed += qstats->rx_skb_alloc_failed; + estats->hw_csum_err += qstats->hw_csum_err; + } +} + +static bool bnx2x_edebug_stats_stopped(struct bnx2x *bp) +{ + u32 val; + + if (SHMEM2_HAS(bp, edebug_driver_if[1])) { + val = SHMEM2_RD(bp, edebug_driver_if[1]); + + if (val == EDEBUG_DRIVER_IF_OP_CODE_DISABLE_STAT) + return true; + } + + return false; +} + +static void bnx2x_stats_update(struct bnx2x *bp) +{ + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + if (bnx2x_edebug_stats_stopped(bp)) + return; + + if (*stats_comp != DMAE_COMP_VAL) + return; + + if (bp->port.pmf) + bnx2x_hw_stats_update(bp); + + if (bnx2x_storm_stats_update(bp) && (bp->stats_pending++ == 3)) { + BNX2X_ERR("storm stats were not updated for 3 times\n"); + bnx2x_panic(); + return; + } + + bnx2x_net_stats_update(bp); + bnx2x_drv_stats_update(bp); + + if (netif_msg_timer(bp)) { + struct bnx2x_eth_stats *estats = &bp->eth_stats; + int i, cos; + + netdev_dbg(bp->dev, "brb drops %u brb truncate %u\n", + estats->brb_drop_lo, estats->brb_truncate_lo); + + for_each_eth_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats; + + printk(KERN_DEBUG "%s: rx usage(%4u) *rx_cons_sb(%u)" + " rx pkt(%lu) rx calls(%lu %lu)\n", + fp->name, (le16_to_cpu(*fp->rx_cons_sb) - + fp->rx_comp_cons), + le16_to_cpu(*fp->rx_cons_sb), + bnx2x_hilo(&qstats-> + total_unicast_packets_received_hi), + fp->rx_calls, fp->rx_pkt); + } + + for_each_eth_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + struct bnx2x_fp_txdata *txdata; + struct bnx2x_eth_q_stats *qstats = &fp->eth_q_stats; + struct netdev_queue *txq; + + printk(KERN_DEBUG "%s: tx pkt(%lu) (Xoff events %u)", + fp->name, bnx2x_hilo( + &qstats->total_unicast_packets_transmitted_hi), + qstats->driver_xoff); + + for_each_cos_in_tx_queue(fp, cos) { + txdata = &fp->txdata[cos]; + txq = netdev_get_tx_queue(bp->dev, + FP_COS_TO_TXQ(fp, cos)); + + printk(KERN_DEBUG "%d: tx avail(%4u)" + " *tx_cons_sb(%u)" + " tx calls (%lu)" + " %s\n", + cos, + bnx2x_tx_avail(bp, txdata), + le16_to_cpu(*txdata->tx_cons_sb), + txdata->tx_pkt, + (netif_tx_queue_stopped(txq) ? + "Xoff" : "Xon") + ); + } + } + } + + bnx2x_hw_stats_post(bp); + bnx2x_storm_stats_post(bp); +} + +static void bnx2x_port_stats_stop(struct bnx2x *bp) +{ + struct dmae_command *dmae; + u32 opcode; + int loader_idx = PMF_DMAE_C(bp); + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + bp->executer_idx = 0; + + opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_PCI, DMAE_DST_GRC, false, 0); + + if (bp->port.port_stx) { + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + if (bp->func_stx) + dmae->opcode = bnx2x_dmae_opcode_add_comp( + opcode, DMAE_COMP_GRC); + else + dmae->opcode = bnx2x_dmae_opcode_add_comp( + opcode, DMAE_COMP_PCI); + + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats)); + dmae->dst_addr_lo = bp->port.port_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_port_stats) >> 2; + if (bp->func_stx) { + dmae->comp_addr_lo = dmae_reg_go_c[loader_idx] >> 2; + dmae->comp_addr_hi = 0; + dmae->comp_val = 1; + } else { + dmae->comp_addr_lo = + U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = + U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + } + } + + if (bp->func_stx) { + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = + bnx2x_dmae_opcode_add_comp(opcode, DMAE_COMP_PCI); + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats)); + dmae->dst_addr_lo = bp->func_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_func_stats) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + } +} + +static void bnx2x_stats_stop(struct bnx2x *bp) +{ + int update = 0; + + bnx2x_stats_comp(bp); + + if (bp->port.pmf) + update = (bnx2x_hw_stats_update(bp) == 0); + + update |= (bnx2x_storm_stats_update(bp) == 0); + + if (update) { + bnx2x_net_stats_update(bp); + + if (bp->port.pmf) + bnx2x_port_stats_stop(bp); + + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); + } +} + +static void bnx2x_stats_do_nothing(struct bnx2x *bp) +{ +} + +static const struct { + void (*action)(struct bnx2x *bp); + enum bnx2x_stats_state next_state; +} bnx2x_stats_stm[STATS_STATE_MAX][STATS_EVENT_MAX] = { +/* state event */ +{ +/* DISABLED PMF */ {bnx2x_stats_pmf_update, STATS_STATE_DISABLED}, +/* LINK_UP */ {bnx2x_stats_start, STATS_STATE_ENABLED}, +/* UPDATE */ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED}, +/* STOP */ {bnx2x_stats_do_nothing, STATS_STATE_DISABLED} +}, +{ +/* ENABLED PMF */ {bnx2x_stats_pmf_start, STATS_STATE_ENABLED}, +/* LINK_UP */ {bnx2x_stats_restart, STATS_STATE_ENABLED}, +/* UPDATE */ {bnx2x_stats_update, STATS_STATE_ENABLED}, +/* STOP */ {bnx2x_stats_stop, STATS_STATE_DISABLED} +} +}; + +void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event) +{ + enum bnx2x_stats_state state; + if (unlikely(bp->panic)) + return; + bnx2x_stats_stm[bp->stats_state][event].action(bp); + spin_lock_bh(&bp->stats_lock); + state = bp->stats_state; + bp->stats_state = bnx2x_stats_stm[state][event].next_state; + spin_unlock_bh(&bp->stats_lock); + + if ((event != STATS_EVENT_UPDATE) || netif_msg_timer(bp)) + DP(BNX2X_MSG_STATS, "state %d -> event %d -> state %d\n", + state, event, bp->stats_state); +} + +static void bnx2x_port_stats_base_init(struct bnx2x *bp) +{ + struct dmae_command *dmae; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!bp->port.pmf || !bp->port.port_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + + dmae = bnx2x_sp(bp, dmae[bp->executer_idx++]); + dmae->opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_PCI, DMAE_DST_GRC, + true, DMAE_COMP_PCI); + dmae->src_addr_lo = U64_LO(bnx2x_sp_mapping(bp, port_stats)); + dmae->src_addr_hi = U64_HI(bnx2x_sp_mapping(bp, port_stats)); + dmae->dst_addr_lo = bp->port.port_stx >> 2; + dmae->dst_addr_hi = 0; + dmae->len = sizeof(struct host_port_stats) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); +} + +static void bnx2x_func_stats_base_init(struct bnx2x *bp) +{ + int vn, vn_max = IS_MF(bp) ? E1HVN_MAX : E1VN_MAX; + u32 func_stx; + + /* sanity */ + if (!bp->port.pmf || !bp->func_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + /* save our func_stx */ + func_stx = bp->func_stx; + + for (vn = VN_0; vn < vn_max; vn++) { + int mb_idx = CHIP_IS_E1x(bp) ? 2*vn + BP_PORT(bp) : vn; + + bp->func_stx = SHMEM_RD(bp, func_mb[mb_idx].fw_mb_param); + bnx2x_func_stats_init(bp); + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); + } + + /* restore our func_stx */ + bp->func_stx = func_stx; +} + +static void bnx2x_func_stats_base_update(struct bnx2x *bp) +{ + struct dmae_command *dmae = &bp->stats_dmae; + u32 *stats_comp = bnx2x_sp(bp, stats_comp); + + /* sanity */ + if (!bp->func_stx) { + BNX2X_ERR("BUG!\n"); + return; + } + + bp->executer_idx = 0; + memset(dmae, 0, sizeof(struct dmae_command)); + + dmae->opcode = bnx2x_dmae_opcode(bp, DMAE_SRC_GRC, DMAE_DST_PCI, + true, DMAE_COMP_PCI); + dmae->src_addr_lo = bp->func_stx >> 2; + dmae->src_addr_hi = 0; + dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, func_stats_base)); + dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, func_stats_base)); + dmae->len = sizeof(struct host_func_stats) >> 2; + dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, stats_comp)); + dmae->comp_val = DMAE_COMP_VAL; + + *stats_comp = 0; + bnx2x_hw_stats_post(bp); + bnx2x_stats_comp(bp); +} + +/** + * This function will prepare the statistics ramrod data the way + * we will only have to increment the statistics counter and + * send the ramrod each time we have to. + * + * @param bp + */ +static inline void bnx2x_prep_fw_stats_req(struct bnx2x *bp) +{ + int i; + struct stats_query_header *stats_hdr = &bp->fw_stats_req->hdr; + + dma_addr_t cur_data_offset; + struct stats_query_entry *cur_query_entry; + + stats_hdr->cmd_num = bp->fw_stats_num; + stats_hdr->drv_stats_counter = 0; + + /* storm_counters struct contains the counters of completed + * statistics requests per storm which are incremented by FW + * each time it completes hadning a statistics ramrod. We will + * check these counters in the timer handler and discard a + * (statistics) ramrod completion. + */ + cur_data_offset = bp->fw_stats_data_mapping + + offsetof(struct bnx2x_fw_stats_data, storm_counters); + + stats_hdr->stats_counters_addrs.hi = + cpu_to_le32(U64_HI(cur_data_offset)); + stats_hdr->stats_counters_addrs.lo = + cpu_to_le32(U64_LO(cur_data_offset)); + + /* prepare to the first stats ramrod (will be completed with + * the counters equal to zero) - init counters to somethig different. + */ + memset(&bp->fw_stats_data->storm_counters, 0xff, + sizeof(struct stats_counter)); + + /**** Port FW statistics data ****/ + cur_data_offset = bp->fw_stats_data_mapping + + offsetof(struct bnx2x_fw_stats_data, port); + + cur_query_entry = &bp->fw_stats_req->query[BNX2X_PORT_QUERY_IDX]; + + cur_query_entry->kind = STATS_TYPE_PORT; + /* For port query index is a DONT CARE */ + cur_query_entry->index = BP_PORT(bp); + /* For port query funcID is a DONT CARE */ + cur_query_entry->funcID = cpu_to_le16(BP_FUNC(bp)); + cur_query_entry->address.hi = cpu_to_le32(U64_HI(cur_data_offset)); + cur_query_entry->address.lo = cpu_to_le32(U64_LO(cur_data_offset)); + + /**** PF FW statistics data ****/ + cur_data_offset = bp->fw_stats_data_mapping + + offsetof(struct bnx2x_fw_stats_data, pf); + + cur_query_entry = &bp->fw_stats_req->query[BNX2X_PF_QUERY_IDX]; + + cur_query_entry->kind = STATS_TYPE_PF; + /* For PF query index is a DONT CARE */ + cur_query_entry->index = BP_PORT(bp); + cur_query_entry->funcID = cpu_to_le16(BP_FUNC(bp)); + cur_query_entry->address.hi = cpu_to_le32(U64_HI(cur_data_offset)); + cur_query_entry->address.lo = cpu_to_le32(U64_LO(cur_data_offset)); + + /**** Clients' queries ****/ + cur_data_offset = bp->fw_stats_data_mapping + + offsetof(struct bnx2x_fw_stats_data, queue_stats); + + for_each_eth_queue(bp, i) { + cur_query_entry = + &bp->fw_stats_req-> + query[BNX2X_FIRST_QUEUE_QUERY_IDX + i]; + + cur_query_entry->kind = STATS_TYPE_QUEUE; + cur_query_entry->index = bnx2x_stats_id(&bp->fp[i]); + cur_query_entry->funcID = cpu_to_le16(BP_FUNC(bp)); + cur_query_entry->address.hi = + cpu_to_le32(U64_HI(cur_data_offset)); + cur_query_entry->address.lo = + cpu_to_le32(U64_LO(cur_data_offset)); + + cur_data_offset += sizeof(struct per_queue_stats); + } +} + +void bnx2x_stats_init(struct bnx2x *bp) +{ + int /*abs*/port = BP_PORT(bp); + int mb_idx = BP_FW_MB_IDX(bp); + int i; + + bp->stats_pending = 0; + bp->executer_idx = 0; + bp->stats_counter = 0; + + /* port and func stats for management */ + if (!BP_NOMCP(bp)) { + bp->port.port_stx = SHMEM_RD(bp, port_mb[port].port_stx); + bp->func_stx = SHMEM_RD(bp, func_mb[mb_idx].fw_mb_param); + + } else { + bp->port.port_stx = 0; + bp->func_stx = 0; + } + DP(BNX2X_MSG_STATS, "port_stx 0x%x func_stx 0x%x\n", + bp->port.port_stx, bp->func_stx); + + port = BP_PORT(bp); + /* port stats */ + memset(&(bp->port.old_nig_stats), 0, sizeof(struct nig_stats)); + bp->port.old_nig_stats.brb_discard = + REG_RD(bp, NIG_REG_STAT0_BRB_DISCARD + port*0x38); + bp->port.old_nig_stats.brb_truncate = + REG_RD(bp, NIG_REG_STAT0_BRB_TRUNCATE + port*0x38); + if (!CHIP_IS_E3(bp)) { + REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT0 + port*0x50, + &(bp->port.old_nig_stats.egress_mac_pkt0_lo), 2); + REG_RD_DMAE(bp, NIG_REG_STAT0_EGRESS_MAC_PKT1 + port*0x50, + &(bp->port.old_nig_stats.egress_mac_pkt1_lo), 2); + } + + /* function stats */ + for_each_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + memset(&fp->old_tclient, 0, sizeof(fp->old_tclient)); + memset(&fp->old_uclient, 0, sizeof(fp->old_uclient)); + memset(&fp->old_xclient, 0, sizeof(fp->old_xclient)); + memset(&fp->eth_q_stats, 0, sizeof(fp->eth_q_stats)); + } + + /* Prepare statistics ramrod data */ + bnx2x_prep_fw_stats_req(bp); + + memset(&bp->dev->stats, 0, sizeof(bp->dev->stats)); + memset(&bp->eth_stats, 0, sizeof(bp->eth_stats)); + + bp->stats_state = STATS_STATE_DISABLED; + + if (bp->port.pmf) { + if (bp->port.port_stx) + bnx2x_port_stats_base_init(bp); + + if (bp->func_stx) + bnx2x_func_stats_base_init(bp); + + } else if (bp->func_stx) + bnx2x_func_stats_base_update(bp); +} diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h new file mode 100644 index 000000000000..5d8ce2f6afef --- /dev/null +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h @@ -0,0 +1,381 @@ +/* bnx2x_stats.h: Broadcom Everest network driver. + * + * Copyright (c) 2007-2011 Broadcom Corporation + * + * 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: Eilon Greenstein + * 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 + * + */ +#ifndef BNX2X_STATS_H +#define BNX2X_STATS_H + +#include + +struct nig_stats { + u32 brb_discard; + u32 brb_packet; + u32 brb_truncate; + u32 flow_ctrl_discard; + u32 flow_ctrl_octets; + u32 flow_ctrl_packet; + u32 mng_discard; + u32 mng_octet_inp; + u32 mng_octet_out; + u32 mng_packet_inp; + u32 mng_packet_out; + u32 pbf_octets; + u32 pbf_packet; + u32 safc_inp; + u32 egress_mac_pkt0_lo; + u32 egress_mac_pkt0_hi; + u32 egress_mac_pkt1_lo; + u32 egress_mac_pkt1_hi; +}; + + +enum bnx2x_stats_event { + STATS_EVENT_PMF = 0, + STATS_EVENT_LINK_UP, + STATS_EVENT_UPDATE, + STATS_EVENT_STOP, + STATS_EVENT_MAX +}; + +enum bnx2x_stats_state { + STATS_STATE_DISABLED = 0, + STATS_STATE_ENABLED, + STATS_STATE_MAX +}; + +struct bnx2x_eth_stats { + u32 total_bytes_received_hi; + u32 total_bytes_received_lo; + u32 total_bytes_transmitted_hi; + u32 total_bytes_transmitted_lo; + u32 total_unicast_packets_received_hi; + u32 total_unicast_packets_received_lo; + u32 total_multicast_packets_received_hi; + u32 total_multicast_packets_received_lo; + u32 total_broadcast_packets_received_hi; + u32 total_broadcast_packets_received_lo; + u32 total_unicast_packets_transmitted_hi; + u32 total_unicast_packets_transmitted_lo; + u32 total_multicast_packets_transmitted_hi; + u32 total_multicast_packets_transmitted_lo; + u32 total_broadcast_packets_transmitted_hi; + u32 total_broadcast_packets_transmitted_lo; + u32 valid_bytes_received_hi; + u32 valid_bytes_received_lo; + + u32 error_bytes_received_hi; + u32 error_bytes_received_lo; + u32 etherstatsoverrsizepkts_hi; + u32 etherstatsoverrsizepkts_lo; + u32 no_buff_discard_hi; + u32 no_buff_discard_lo; + + u32 rx_stat_ifhcinbadoctets_hi; + u32 rx_stat_ifhcinbadoctets_lo; + u32 tx_stat_ifhcoutbadoctets_hi; + u32 tx_stat_ifhcoutbadoctets_lo; + u32 rx_stat_dot3statsfcserrors_hi; + u32 rx_stat_dot3statsfcserrors_lo; + u32 rx_stat_dot3statsalignmenterrors_hi; + u32 rx_stat_dot3statsalignmenterrors_lo; + u32 rx_stat_dot3statscarriersenseerrors_hi; + u32 rx_stat_dot3statscarriersenseerrors_lo; + u32 rx_stat_falsecarriererrors_hi; + u32 rx_stat_falsecarriererrors_lo; + u32 rx_stat_etherstatsundersizepkts_hi; + u32 rx_stat_etherstatsundersizepkts_lo; + u32 rx_stat_dot3statsframestoolong_hi; + u32 rx_stat_dot3statsframestoolong_lo; + u32 rx_stat_etherstatsfragments_hi; + u32 rx_stat_etherstatsfragments_lo; + u32 rx_stat_etherstatsjabbers_hi; + u32 rx_stat_etherstatsjabbers_lo; + u32 rx_stat_maccontrolframesreceived_hi; + u32 rx_stat_maccontrolframesreceived_lo; + u32 rx_stat_bmac_xpf_hi; + u32 rx_stat_bmac_xpf_lo; + u32 rx_stat_bmac_xcf_hi; + u32 rx_stat_bmac_xcf_lo; + u32 rx_stat_xoffstateentered_hi; + u32 rx_stat_xoffstateentered_lo; + u32 rx_stat_xonpauseframesreceived_hi; + u32 rx_stat_xonpauseframesreceived_lo; + u32 rx_stat_xoffpauseframesreceived_hi; + u32 rx_stat_xoffpauseframesreceived_lo; + u32 tx_stat_outxonsent_hi; + u32 tx_stat_outxonsent_lo; + u32 tx_stat_outxoffsent_hi; + u32 tx_stat_outxoffsent_lo; + u32 tx_stat_flowcontroldone_hi; + u32 tx_stat_flowcontroldone_lo; + u32 tx_stat_etherstatscollisions_hi; + u32 tx_stat_etherstatscollisions_lo; + u32 tx_stat_dot3statssinglecollisionframes_hi; + u32 tx_stat_dot3statssinglecollisionframes_lo; + u32 tx_stat_dot3statsmultiplecollisionframes_hi; + u32 tx_stat_dot3statsmultiplecollisionframes_lo; + u32 tx_stat_dot3statsdeferredtransmissions_hi; + u32 tx_stat_dot3statsdeferredtransmissions_lo; + u32 tx_stat_dot3statsexcessivecollisions_hi; + u32 tx_stat_dot3statsexcessivecollisions_lo; + u32 tx_stat_dot3statslatecollisions_hi; + u32 tx_stat_dot3statslatecollisions_lo; + u32 tx_stat_etherstatspkts64octets_hi; + u32 tx_stat_etherstatspkts64octets_lo; + u32 tx_stat_etherstatspkts65octetsto127octets_hi; + u32 tx_stat_etherstatspkts65octetsto127octets_lo; + u32 tx_stat_etherstatspkts128octetsto255octets_hi; + u32 tx_stat_etherstatspkts128octetsto255octets_lo; + u32 tx_stat_etherstatspkts256octetsto511octets_hi; + u32 tx_stat_etherstatspkts256octetsto511octets_lo; + u32 tx_stat_etherstatspkts512octetsto1023octets_hi; + u32 tx_stat_etherstatspkts512octetsto1023octets_lo; + u32 tx_stat_etherstatspkts1024octetsto1522octets_hi; + u32 tx_stat_etherstatspkts1024octetsto1522octets_lo; + u32 tx_stat_etherstatspktsover1522octets_hi; + u32 tx_stat_etherstatspktsover1522octets_lo; + u32 tx_stat_bmac_2047_hi; + u32 tx_stat_bmac_2047_lo; + u32 tx_stat_bmac_4095_hi; + u32 tx_stat_bmac_4095_lo; + u32 tx_stat_bmac_9216_hi; + u32 tx_stat_bmac_9216_lo; + u32 tx_stat_bmac_16383_hi; + u32 tx_stat_bmac_16383_lo; + u32 tx_stat_dot3statsinternalmactransmiterrors_hi; + u32 tx_stat_dot3statsinternalmactransmiterrors_lo; + u32 tx_stat_bmac_ufl_hi; + u32 tx_stat_bmac_ufl_lo; + + u32 pause_frames_received_hi; + u32 pause_frames_received_lo; + u32 pause_frames_sent_hi; + u32 pause_frames_sent_lo; + + u32 etherstatspkts1024octetsto1522octets_hi; + u32 etherstatspkts1024octetsto1522octets_lo; + u32 etherstatspktsover1522octets_hi; + u32 etherstatspktsover1522octets_lo; + + u32 brb_drop_hi; + u32 brb_drop_lo; + u32 brb_truncate_hi; + u32 brb_truncate_lo; + + u32 mac_filter_discard; + u32 mf_tag_discard; + u32 brb_truncate_discard; + u32 mac_discard; + + u32 driver_xoff; + u32 rx_err_discard_pkt; + u32 rx_skb_alloc_failed; + u32 hw_csum_err; + + u32 nig_timer_max; + + /* TPA */ + u32 total_tpa_aggregations_hi; + u32 total_tpa_aggregations_lo; + u32 total_tpa_aggregated_frames_hi; + u32 total_tpa_aggregated_frames_lo; + u32 total_tpa_bytes_hi; + u32 total_tpa_bytes_lo; +}; + + +struct bnx2x_eth_q_stats { + u32 total_unicast_bytes_received_hi; + u32 total_unicast_bytes_received_lo; + u32 total_broadcast_bytes_received_hi; + u32 total_broadcast_bytes_received_lo; + u32 total_multicast_bytes_received_hi; + u32 total_multicast_bytes_received_lo; + u32 total_bytes_received_hi; + u32 total_bytes_received_lo; + u32 total_unicast_bytes_transmitted_hi; + u32 total_unicast_bytes_transmitted_lo; + u32 total_broadcast_bytes_transmitted_hi; + u32 total_broadcast_bytes_transmitted_lo; + u32 total_multicast_bytes_transmitted_hi; + u32 total_multicast_bytes_transmitted_lo; + u32 total_bytes_transmitted_hi; + u32 total_bytes_transmitted_lo; + u32 total_unicast_packets_received_hi; + u32 total_unicast_packets_received_lo; + u32 total_multicast_packets_received_hi; + u32 total_multicast_packets_received_lo; + u32 total_broadcast_packets_received_hi; + u32 total_broadcast_packets_received_lo; + u32 total_unicast_packets_transmitted_hi; + u32 total_unicast_packets_transmitted_lo; + u32 total_multicast_packets_transmitted_hi; + u32 total_multicast_packets_transmitted_lo; + u32 total_broadcast_packets_transmitted_hi; + u32 total_broadcast_packets_transmitted_lo; + u32 valid_bytes_received_hi; + u32 valid_bytes_received_lo; + + u32 etherstatsoverrsizepkts_hi; + u32 etherstatsoverrsizepkts_lo; + u32 no_buff_discard_hi; + u32 no_buff_discard_lo; + + u32 driver_xoff; + u32 rx_err_discard_pkt; + u32 rx_skb_alloc_failed; + u32 hw_csum_err; + + u32 total_packets_received_checksum_discarded_hi; + u32 total_packets_received_checksum_discarded_lo; + u32 total_packets_received_ttl0_discarded_hi; + u32 total_packets_received_ttl0_discarded_lo; + u32 total_transmitted_dropped_packets_error_hi; + u32 total_transmitted_dropped_packets_error_lo; + + /* TPA */ + u32 total_tpa_aggregations_hi; + u32 total_tpa_aggregations_lo; + u32 total_tpa_aggregated_frames_hi; + u32 total_tpa_aggregated_frames_lo; + u32 total_tpa_bytes_hi; + u32 total_tpa_bytes_lo; +}; + +/**************************************************************************** +* Macros +****************************************************************************/ + +/* sum[hi:lo] += add[hi:lo] */ +#define ADD_64(s_hi, a_hi, s_lo, a_lo) \ + do { \ + s_lo += a_lo; \ + s_hi += a_hi + ((s_lo < a_lo) ? 1 : 0); \ + } while (0) + +/* difference = minuend - subtrahend */ +#define DIFF_64(d_hi, m_hi, s_hi, d_lo, m_lo, s_lo) \ + do { \ + if (m_lo < s_lo) { \ + /* underflow */ \ + d_hi = m_hi - s_hi; \ + if (d_hi > 0) { \ + /* we can 'loan' 1 */ \ + d_hi--; \ + d_lo = m_lo + (UINT_MAX - s_lo) + 1; \ + } else { \ + /* m_hi <= s_hi */ \ + d_hi = 0; \ + d_lo = 0; \ + } \ + } else { \ + /* m_lo >= s_lo */ \ + if (m_hi < s_hi) { \ + d_hi = 0; \ + d_lo = 0; \ + } else { \ + /* m_hi >= s_hi */ \ + d_hi = m_hi - s_hi; \ + d_lo = m_lo - s_lo; \ + } \ + } \ + } while (0) + +#define UPDATE_STAT64(s, t) \ + do { \ + DIFF_64(diff.hi, new->s##_hi, pstats->mac_stx[0].t##_hi, \ + diff.lo, new->s##_lo, pstats->mac_stx[0].t##_lo); \ + pstats->mac_stx[0].t##_hi = new->s##_hi; \ + pstats->mac_stx[0].t##_lo = new->s##_lo; \ + ADD_64(pstats->mac_stx[1].t##_hi, diff.hi, \ + pstats->mac_stx[1].t##_lo, diff.lo); \ + } while (0) + +#define UPDATE_STAT64_NIG(s, t) \ + do { \ + DIFF_64(diff.hi, new->s##_hi, old->s##_hi, \ + diff.lo, new->s##_lo, old->s##_lo); \ + ADD_64(estats->t##_hi, diff.hi, \ + estats->t##_lo, diff.lo); \ + } while (0) + +/* sum[hi:lo] += add */ +#define ADD_EXTEND_64(s_hi, s_lo, a) \ + do { \ + s_lo += a; \ + s_hi += (s_lo < a) ? 1 : 0; \ + } while (0) + +#define ADD_STAT64(diff, t) \ + do { \ + ADD_64(pstats->mac_stx[1].t##_hi, new->diff##_hi, \ + pstats->mac_stx[1].t##_lo, new->diff##_lo); \ + } while (0) + +#define UPDATE_EXTEND_STAT(s) \ + do { \ + ADD_EXTEND_64(pstats->mac_stx[1].s##_hi, \ + pstats->mac_stx[1].s##_lo, \ + new->s); \ + } while (0) + +#define UPDATE_EXTEND_TSTAT(s, t) \ + do { \ + diff = le32_to_cpu(tclient->s) - le32_to_cpu(old_tclient->s); \ + old_tclient->s = tclient->s; \ + ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \ + } while (0) + +#define UPDATE_EXTEND_USTAT(s, t) \ + do { \ + diff = le32_to_cpu(uclient->s) - le32_to_cpu(old_uclient->s); \ + old_uclient->s = uclient->s; \ + ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \ + } while (0) + +#define UPDATE_EXTEND_XSTAT(s, t) \ + do { \ + diff = le32_to_cpu(xclient->s) - le32_to_cpu(old_xclient->s); \ + old_xclient->s = xclient->s; \ + ADD_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \ + } while (0) + +/* minuend -= subtrahend */ +#define SUB_64(m_hi, s_hi, m_lo, s_lo) \ + do { \ + DIFF_64(m_hi, m_hi, s_hi, m_lo, m_lo, s_lo); \ + } while (0) + +/* minuend[hi:lo] -= subtrahend */ +#define SUB_EXTEND_64(m_hi, m_lo, s) \ + do { \ + SUB_64(m_hi, 0, m_lo, s); \ + } while (0) + +#define SUB_EXTEND_USTAT(s, t) \ + do { \ + diff = le32_to_cpu(uclient->s) - le32_to_cpu(old_uclient->s); \ + SUB_EXTEND_64(qstats->t##_hi, qstats->t##_lo, diff); \ + } while (0) + + +/* forward */ +struct bnx2x; + +void bnx2x_stats_init(struct bnx2x *bp); + +void bnx2x_stats_handle(struct bnx2x *bp, enum bnx2x_stats_event event); + +#endif /* BNX2X_STATS_H */ -- cgit v1.2.3-59-g8ed1b