M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions
@@ -0,0 +1,6 @@
config BE2NET
tristate "ServerEngines' 10Gbps NIC - BladeEngine"
depends on PCI && INET
---help---
This driver implements the NIC functionality for ServerEngines'
10Gbps network adapter - BladeEngine.
@@ -0,0 +1,7 @@
#
# Makefile to build the network driver for ServerEngine's BladeEngine.
#
obj-$(CONFIG_BE2NET) += be2net.o
be2net-y := be_main.o be_cmds.o be_ethtool.o
@@ -0,0 +1,586 @@
/*
* Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
* linux-drivers@emulex.com
*
* Emulex
* 3333 Susan Street
* Costa Mesa, CA 92626
*/
#ifndef BE_H
#define BE_H
#include <linux/pci.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <net/tcp.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <linux/if_vlan.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/u64_stats_sync.h>
#include "be_hw.h"
#define DRV_VER "4.2.116u"
#define DRV_NAME "be2net"
#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC"
#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC"
#define OC_NAME "Emulex OneConnect 10Gbps NIC"
#define OC_NAME_BE OC_NAME "(be3)"
#define OC_NAME_LANCER OC_NAME "(Lancer)"
#define OC_NAME_SH OC_NAME "(Skyhawk)"
#define DRV_DESC "ServerEngines BladeEngine 10Gbps NIC Driver"
#define BE_VENDOR_ID 0x19a2
#define EMULEX_VENDOR_ID 0x10df
#define BE_DEVICE_ID1 0x211
#define BE_DEVICE_ID2 0x221
#define OC_DEVICE_ID1 0x700 /* Device Id for BE2 cards */
#define OC_DEVICE_ID2 0x710 /* Device Id for BE3 cards */
#define OC_DEVICE_ID3 0xe220 /* Device id for Lancer cards */
#define OC_DEVICE_ID4 0xe228 /* Device id for VF in Lancer */
#define OC_DEVICE_ID5 0x720 /* Device Id for Skyhawk cards */
#define OC_SUBSYS_DEVICE_ID1 0xE602
#define OC_SUBSYS_DEVICE_ID2 0xE642
#define OC_SUBSYS_DEVICE_ID3 0xE612
#define OC_SUBSYS_DEVICE_ID4 0xE652
static inline char *nic_name(struct pci_dev *pdev)
{
switch (pdev->device) {
case OC_DEVICE_ID1:
return OC_NAME;
case OC_DEVICE_ID2:
return OC_NAME_BE;
case OC_DEVICE_ID3:
case OC_DEVICE_ID4:
return OC_NAME_LANCER;
case BE_DEVICE_ID2:
return BE3_NAME;
case OC_DEVICE_ID5:
return OC_NAME_SH;
default:
return BE_NAME;
}
}
/* Number of bytes of an RX frame that are copied to skb->data */
#define BE_HDR_LEN ((u16) 64)
/* allocate extra space to allow tunneling decapsulation without head reallocation */
#define BE_RX_SKB_ALLOC_SIZE (BE_HDR_LEN + 64)
#define BE_MAX_JUMBO_FRAME_SIZE 9018
#define BE_MIN_MTU 256
#define BE_NUM_VLANS_SUPPORTED 64
#define BE_MAX_EQD 96u
#define BE_MAX_TX_FRAG_COUNT 30
#define EVNT_Q_LEN 1024
#define TX_Q_LEN 2048
#define TX_CQ_LEN 1024
#define RX_Q_LEN 1024 /* Does not support any other value */
#define RX_CQ_LEN 1024
#define MCC_Q_LEN 128 /* total size not to exceed 8 pages */
#define MCC_CQ_LEN 256
#define BE3_MAX_RSS_QS 8
#define BE2_MAX_RSS_QS 4
#define MAX_RSS_QS BE3_MAX_RSS_QS
#define MAX_RX_QS (MAX_RSS_QS + 1) /* RSS qs + 1 def Rx */
#define MAX_TX_QS 8
#define MAX_MSIX_VECTORS MAX_RSS_QS
#define BE_TX_BUDGET 256
#define BE_NAPI_WEIGHT 64
#define MAX_RX_POST BE_NAPI_WEIGHT /* Frags posted at a time */
#define RX_FRAGS_REFILL_WM (RX_Q_LEN - MAX_RX_POST)
#define FW_VER_LEN 32
struct be_dma_mem {
void *va;
dma_addr_t dma;
u32 size;
};
struct be_queue_info {
struct be_dma_mem dma_mem;
u16 len;
u16 entry_size; /* Size of an element in the queue */
u16 id;
u16 tail, head;
bool created;
atomic_t used; /* Number of valid elements in the queue */
};
static inline u32 MODULO(u16 val, u16 limit)
{
BUG_ON(limit & (limit - 1));
return val & (limit - 1);
}
static inline void index_adv(u16 *index, u16 val, u16 limit)
{
*index = MODULO((*index + val), limit);
}
static inline void index_inc(u16 *index, u16 limit)
{
*index = MODULO((*index + 1), limit);
}
static inline void *queue_head_node(struct be_queue_info *q)
{
return q->dma_mem.va + q->head * q->entry_size;
}
static inline void *queue_tail_node(struct be_queue_info *q)
{
return q->dma_mem.va + q->tail * q->entry_size;
}
static inline void *queue_index_node(struct be_queue_info *q, u16 index)
{
return q->dma_mem.va + index * q->entry_size;
}
static inline void queue_head_inc(struct be_queue_info *q)
{
index_inc(&q->head, q->len);
}
static inline void queue_tail_inc(struct be_queue_info *q)
{
index_inc(&q->tail, q->len);
}
struct be_eq_obj {
struct be_queue_info q;
char desc[32];
/* Adaptive interrupt coalescing (AIC) info */
bool enable_aic;
u32 min_eqd; /* in usecs */
u32 max_eqd; /* in usecs */
u32 eqd; /* configured val when aic is off */
u32 cur_eqd; /* in usecs */
u8 idx; /* array index */
u16 tx_budget;
struct napi_struct napi;
struct be_adapter *adapter;
} ____cacheline_aligned_in_smp;
struct be_mcc_obj {
struct be_queue_info q;
struct be_queue_info cq;
bool rearm_cq;
};
struct be_tx_stats {
u64 tx_bytes;
u64 tx_pkts;
u64 tx_reqs;
u64 tx_wrbs;
u64 tx_compl;
ulong tx_jiffies;
u32 tx_stops;
struct u64_stats_sync sync;
struct u64_stats_sync sync_compl;
};
struct be_tx_obj {
struct be_queue_info q;
struct be_queue_info cq;
/* Remember the skbs that were transmitted */
struct sk_buff *sent_skb_list[TX_Q_LEN];
struct be_tx_stats stats;
} ____cacheline_aligned_in_smp;
/* Struct to remember the pages posted for rx frags */
struct be_rx_page_info {
struct page *page;
DEFINE_DMA_UNMAP_ADDR(bus);
u16 page_offset;
bool last_page_user;
};
struct be_rx_stats {
u64 rx_bytes;
u64 rx_pkts;
u64 rx_pkts_prev;
ulong rx_jiffies;
u32 rx_drops_no_skbs; /* skb allocation errors */
u32 rx_drops_no_frags; /* HW has no fetched frags */
u32 rx_post_fail; /* page post alloc failures */
u32 rx_compl;
u32 rx_mcast_pkts;
u32 rx_compl_err; /* completions with err set */
u32 rx_pps; /* pkts per second */
struct u64_stats_sync sync;
};
struct be_rx_compl_info {
u32 rss_hash;
u16 vlan_tag;
u16 pkt_size;
u16 rxq_idx;
u16 port;
u8 vlanf;
u8 num_rcvd;
u8 err;
u8 ipf;
u8 tcpf;
u8 udpf;
u8 ip_csum;
u8 l4_csum;
u8 ipv6;
u8 vtm;
u8 pkt_type;
};
struct be_rx_obj {
struct be_adapter *adapter;
struct be_queue_info q;
struct be_queue_info cq;
struct be_rx_compl_info rxcp;
struct be_rx_page_info page_info_tbl[RX_Q_LEN];
struct be_rx_stats stats;
u8 rss_id;
bool rx_post_starved; /* Zero rx frags have been posted to BE */
} ____cacheline_aligned_in_smp;
struct be_drv_stats {
u32 be_on_die_temperature;
u32 eth_red_drops;
u32 rx_drops_no_pbuf;
u32 rx_drops_no_txpb;
u32 rx_drops_no_erx_descr;
u32 rx_drops_no_tpre_descr;
u32 rx_drops_too_many_frags;
u32 forwarded_packets;
u32 rx_drops_mtu;
u32 rx_crc_errors;
u32 rx_alignment_symbol_errors;
u32 rx_pause_frames;
u32 rx_priority_pause_frames;
u32 rx_control_frames;
u32 rx_in_range_errors;
u32 rx_out_range_errors;
u32 rx_frame_too_long;
u32 rx_address_mismatch_drops;
u32 rx_dropped_too_small;
u32 rx_dropped_too_short;
u32 rx_dropped_header_too_small;
u32 rx_dropped_tcp_length;
u32 rx_dropped_runt;
u32 rx_ip_checksum_errs;
u32 rx_tcp_checksum_errs;
u32 rx_udp_checksum_errs;
u32 tx_pauseframes;
u32 tx_priority_pauseframes;
u32 tx_controlframes;
u32 rxpp_fifo_overflow_drop;
u32 rx_input_fifo_overflow_drop;
u32 pmem_fifo_overflow_drop;
u32 jabber_events;
};
struct be_vf_cfg {
unsigned char mac_addr[ETH_ALEN];
int if_handle;
int pmac_id;
u16 def_vid;
u16 vlan_tag;
u32 tx_rate;
};
#define BE_FLAGS_LINK_STATUS_INIT 1
#define BE_FLAGS_WORKER_SCHEDULED (1 << 3)
#define BE_UC_PMAC_COUNT 30
#define BE_VF_UC_PMAC_COUNT 2
struct be_adapter {
struct pci_dev *pdev;
struct net_device *netdev;
u8 __iomem *csr;
u8 __iomem *db; /* Door Bell */
struct mutex mbox_lock; /* For serializing mbox cmds to BE card */
struct be_dma_mem mbox_mem;
/* Mbox mem is adjusted to align to 16 bytes. The allocated addr
* is stored for freeing purpose */
struct be_dma_mem mbox_mem_alloced;
struct be_mcc_obj mcc_obj;
spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */
spinlock_t mcc_cq_lock;
u32 num_msix_vec;
u32 num_evt_qs;
struct be_eq_obj eq_obj[MAX_MSIX_VECTORS];
struct msix_entry msix_entries[MAX_MSIX_VECTORS];
bool isr_registered;
/* TX Rings */
u32 num_tx_qs;
struct be_tx_obj tx_obj[MAX_TX_QS];
/* Rx rings */
u32 num_rx_qs;
struct be_rx_obj rx_obj[MAX_RX_QS];
u32 big_page_size; /* Compounded page size shared by rx wrbs */
u8 eq_next_idx;
struct be_drv_stats drv_stats;
u16 vlans_added;
u16 max_vlans; /* Number of vlans supported */
u8 vlan_tag[VLAN_N_VID];
u8 vlan_prio_bmap; /* Available Priority BitMap */
u16 recommended_prio; /* Recommended Priority */
struct be_dma_mem rx_filter; /* Cmd DMA mem for rx-filter */
struct be_dma_mem stats_cmd;
/* Work queue used to perform periodic tasks like getting statistics */
struct delayed_work work;
u16 work_counter;
u32 flags;
/* Ethtool knobs and info */
char fw_ver[FW_VER_LEN];
int if_handle; /* Used to configure filtering */
u32 *pmac_id; /* MAC addr handle used by BE card */
u32 beacon_state; /* for set_phys_id */
bool eeh_err;
bool ue_detected;
bool fw_timeout;
u32 port_num;
bool promiscuous;
u32 function_mode;
u32 function_caps;
u32 rx_fc; /* Rx flow control */
u32 tx_fc; /* Tx flow control */
bool stats_cmd_sent;
int link_speed;
u8 port_type;
u8 transceiver;
u8 autoneg;
u8 generation; /* BladeEngine ASIC generation */
u32 flash_status;
struct completion flash_compl;
u32 num_vfs;
u8 is_virtfn;
struct be_vf_cfg *vf_cfg;
bool be3_native;
u32 sli_family;
u8 hba_port_num;
u16 pvid;
u8 wol_cap;
bool wol;
u32 max_pmac_cnt; /* Max secondary UC MACs programmable */
u32 uc_macs; /* Count of secondary UC MAC programmed */
};
#define be_physfn(adapter) (!adapter->is_virtfn)
#define sriov_enabled(adapter) (adapter->num_vfs > 0)
#define for_all_vfs(adapter, vf_cfg, i) \
for (i = 0, vf_cfg = &adapter->vf_cfg[i]; i < adapter->num_vfs; \
i++, vf_cfg++)
/* BladeEngine Generation numbers */
#define BE_GEN2 2
#define BE_GEN3 3
#define ON 1
#define OFF 0
#define lancer_chip(adapter) ((adapter->pdev->device == OC_DEVICE_ID3) || \
(adapter->pdev->device == OC_DEVICE_ID4))
extern const struct ethtool_ops be_ethtool_ops;
#define msix_enabled(adapter) (adapter->num_msix_vec > 0)
#define num_irqs(adapter) (msix_enabled(adapter) ? \
adapter->num_msix_vec : 1)
#define tx_stats(txo) (&(txo)->stats)
#define rx_stats(rxo) (&(rxo)->stats)
/* The default RXQ is the last RXQ */
#define default_rxo(adpt) (&adpt->rx_obj[adpt->num_rx_qs - 1])
#define for_all_rx_queues(adapter, rxo, i) \
for (i = 0, rxo = &adapter->rx_obj[i]; i < adapter->num_rx_qs; \
i++, rxo++)
/* Skip the default non-rss queue (last one)*/
#define for_all_rss_queues(adapter, rxo, i) \
for (i = 0, rxo = &adapter->rx_obj[i]; i < (adapter->num_rx_qs - 1);\
i++, rxo++)
#define for_all_tx_queues(adapter, txo, i) \
for (i = 0, txo = &adapter->tx_obj[i]; i < adapter->num_tx_qs; \
i++, txo++)
#define for_all_evt_queues(adapter, eqo, i) \
for (i = 0, eqo = &adapter->eq_obj[i]; i < adapter->num_evt_qs; \
i++, eqo++)
#define is_mcc_eqo(eqo) (eqo->idx == 0)
#define mcc_eqo(adapter) (&adapter->eq_obj[0])
#define PAGE_SHIFT_4K 12
#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K)
/* Returns number of pages spanned by the data starting at the given addr */
#define PAGES_4K_SPANNED(_address, size) \
((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \
(size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K))
/* Returns bit offset within a DWORD of a bitfield */
#define AMAP_BIT_OFFSET(_struct, field) \
(((size_t)&(((_struct *)0)->field))%32)
/* Returns the bit mask of the field that is NOT shifted into location. */
static inline u32 amap_mask(u32 bitsize)
{
return (bitsize == 32 ? 0xFFFFFFFF : (1 << bitsize) - 1);
}
static inline void
amap_set(void *ptr, u32 dw_offset, u32 mask, u32 offset, u32 value)
{
u32 *dw = (u32 *) ptr + dw_offset;
*dw &= ~(mask << offset);
*dw |= (mask & value) << offset;
}
#define AMAP_SET_BITS(_struct, field, ptr, val) \
amap_set(ptr, \
offsetof(_struct, field)/32, \
amap_mask(sizeof(((_struct *)0)->field)), \
AMAP_BIT_OFFSET(_struct, field), \
val)
static inline u32 amap_get(void *ptr, u32 dw_offset, u32 mask, u32 offset)
{
u32 *dw = (u32 *) ptr;
return mask & (*(dw + dw_offset) >> offset);
}
#define AMAP_GET_BITS(_struct, field, ptr) \
amap_get(ptr, \
offsetof(_struct, field)/32, \
amap_mask(sizeof(((_struct *)0)->field)), \
AMAP_BIT_OFFSET(_struct, field))
#define be_dws_cpu_to_le(wrb, len) swap_dws(wrb, len)
#define be_dws_le_to_cpu(wrb, len) swap_dws(wrb, len)
static inline void swap_dws(void *wrb, int len)
{
#ifdef __BIG_ENDIAN
u32 *dw = wrb;
BUG_ON(len % 4);
do {
*dw = cpu_to_le32(*dw);
dw++;
len -= 4;
} while (len);
#endif /* __BIG_ENDIAN */
}
static inline u8 is_tcp_pkt(struct sk_buff *skb)
{
u8 val = 0;
if (ip_hdr(skb)->version == 4)
val = (ip_hdr(skb)->protocol == IPPROTO_TCP);
else if (ip_hdr(skb)->version == 6)
val = (ipv6_hdr(skb)->nexthdr == NEXTHDR_TCP);
return val;
}
static inline u8 is_udp_pkt(struct sk_buff *skb)
{
u8 val = 0;
if (ip_hdr(skb)->version == 4)
val = (ip_hdr(skb)->protocol == IPPROTO_UDP);
else if (ip_hdr(skb)->version == 6)
val = (ipv6_hdr(skb)->nexthdr == NEXTHDR_UDP);
return val;
}
static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
{
u32 sli_intf;
pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET, &sli_intf);
adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;
}
static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
{
u32 addr;
addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0);
mac[5] = (u8)(addr & 0xFF);
mac[4] = (u8)((addr >> 8) & 0xFF);
mac[3] = (u8)((addr >> 16) & 0xFF);
/* Use the OUI from the current MAC address */
memcpy(mac, adapter->netdev->dev_addr, 3);
}
static inline bool be_multi_rxq(const struct be_adapter *adapter)
{
return adapter->num_rx_qs > 1;
}
static inline bool be_error(struct be_adapter *adapter)
{
return adapter->eeh_err || adapter->ue_detected || adapter->fw_timeout;
}
static inline bool be_is_wol_excluded(struct be_adapter *adapter)
{
struct pci_dev *pdev = adapter->pdev;
if (!be_physfn(adapter))
return true;
switch (pdev->subsystem_device) {
case OC_SUBSYS_DEVICE_ID1:
case OC_SUBSYS_DEVICE_ID2:
case OC_SUBSYS_DEVICE_ID3:
case OC_SUBSYS_DEVICE_ID4:
return true;
default:
return false;
}
}
extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped);
extern void be_link_status_update(struct be_adapter *adapter, u8 link_status);
extern void be_parse_stats(struct be_adapter *adapter);
extern int be_load_fw(struct be_adapter *adapter, u8 *func);
extern bool be_is_wol_supported(struct be_adapter *adapter);
#endif /* BE_H */
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,811 @@
/*
* Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
* linux-drivers@emulex.com
*
* Emulex
* 3333 Susan Street
* Costa Mesa, CA 92626
*/
#include "be.h"
#include "be_cmds.h"
#include <linux/ethtool.h>
struct be_ethtool_stat {
char desc[ETH_GSTRING_LEN];
int type;
int size;
int offset;
};
enum {DRVSTAT_TX, DRVSTAT_RX, DRVSTAT};
#define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \
offsetof(_struct, field)
#define DRVSTAT_TX_INFO(field) #field, DRVSTAT_TX,\
FIELDINFO(struct be_tx_stats, field)
#define DRVSTAT_RX_INFO(field) #field, DRVSTAT_RX,\
FIELDINFO(struct be_rx_stats, field)
#define DRVSTAT_INFO(field) #field, DRVSTAT,\
FIELDINFO(struct be_drv_stats, field)
static const struct be_ethtool_stat et_stats[] = {
{DRVSTAT_INFO(rx_crc_errors)},
{DRVSTAT_INFO(rx_alignment_symbol_errors)},
{DRVSTAT_INFO(rx_pause_frames)},
{DRVSTAT_INFO(rx_control_frames)},
/* Received packets dropped when the Ethernet length field
* is not equal to the actual Ethernet data length.
*/
{DRVSTAT_INFO(rx_in_range_errors)},
/* Received packets dropped when their length field is >= 1501 bytes
* and <= 1535 bytes.
*/
{DRVSTAT_INFO(rx_out_range_errors)},
/* Received packets dropped when they are longer than 9216 bytes */
{DRVSTAT_INFO(rx_frame_too_long)},
/* Received packets dropped when they don't pass the unicast or
* multicast address filtering.
*/
{DRVSTAT_INFO(rx_address_mismatch_drops)},
/* Received packets dropped when IP packet length field is less than
* the IP header length field.
*/
{DRVSTAT_INFO(rx_dropped_too_small)},
/* Received packets dropped when IP length field is greater than
* the actual packet length.
*/
{DRVSTAT_INFO(rx_dropped_too_short)},
/* Received packets dropped when the IP header length field is less
* than 5.
*/
{DRVSTAT_INFO(rx_dropped_header_too_small)},
/* Received packets dropped when the TCP header length field is less
* than 5 or the TCP header length + IP header length is more
* than IP packet length.
*/
{DRVSTAT_INFO(rx_dropped_tcp_length)},
{DRVSTAT_INFO(rx_dropped_runt)},
/* Number of received packets dropped when a fifo for descriptors going
* into the packet demux block overflows. In normal operation, this
* fifo must never overflow.
*/
{DRVSTAT_INFO(rxpp_fifo_overflow_drop)},
{DRVSTAT_INFO(rx_input_fifo_overflow_drop)},
{DRVSTAT_INFO(rx_ip_checksum_errs)},
{DRVSTAT_INFO(rx_tcp_checksum_errs)},
{DRVSTAT_INFO(rx_udp_checksum_errs)},
{DRVSTAT_INFO(tx_pauseframes)},
{DRVSTAT_INFO(tx_controlframes)},
{DRVSTAT_INFO(rx_priority_pause_frames)},
/* Received packets dropped when an internal fifo going into
* main packet buffer tank (PMEM) overflows.
*/
{DRVSTAT_INFO(pmem_fifo_overflow_drop)},
{DRVSTAT_INFO(jabber_events)},
/* Received packets dropped due to lack of available HW packet buffers
* used to temporarily hold the received packets.
*/
{DRVSTAT_INFO(rx_drops_no_pbuf)},
/* Received packets dropped due to input receive buffer
* descriptor fifo overflowing.
*/
{DRVSTAT_INFO(rx_drops_no_erx_descr)},
/* Packets dropped because the internal FIFO to the offloaded TCP
* receive processing block is full. This could happen only for
* offloaded iSCSI or FCoE trarffic.
*/
{DRVSTAT_INFO(rx_drops_no_tpre_descr)},
/* Received packets dropped when they need more than 8
* receive buffers. This cannot happen as the driver configures
* 2048 byte receive buffers.
*/
{DRVSTAT_INFO(rx_drops_too_many_frags)},
{DRVSTAT_INFO(forwarded_packets)},
/* Received packets dropped when the frame length
* is more than 9018 bytes
*/
{DRVSTAT_INFO(rx_drops_mtu)},
/* Number of packets dropped due to random early drop function */
{DRVSTAT_INFO(eth_red_drops)},
{DRVSTAT_INFO(be_on_die_temperature)}
};
#define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
/* Stats related to multi RX queues: get_stats routine assumes bytes, pkts
* are first and second members respectively.
*/
static const struct be_ethtool_stat et_rx_stats[] = {
{DRVSTAT_RX_INFO(rx_bytes)},/* If moving this member see above note */
{DRVSTAT_RX_INFO(rx_pkts)}, /* If moving this member see above note */
{DRVSTAT_RX_INFO(rx_compl)},
{DRVSTAT_RX_INFO(rx_mcast_pkts)},
/* Number of page allocation failures while posting receive buffers
* to HW.
*/
{DRVSTAT_RX_INFO(rx_post_fail)},
/* Recevied packets dropped due to skb allocation failure */
{DRVSTAT_RX_INFO(rx_drops_no_skbs)},
/* Received packets dropped due to lack of available fetched buffers
* posted by the driver.
*/
{DRVSTAT_RX_INFO(rx_drops_no_frags)}
};
#define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(et_rx_stats))
/* Stats related to multi TX queues: get_stats routine assumes compl is the
* first member
*/
static const struct be_ethtool_stat et_tx_stats[] = {
{DRVSTAT_TX_INFO(tx_compl)}, /* If moving this member see above note */
{DRVSTAT_TX_INFO(tx_bytes)},
{DRVSTAT_TX_INFO(tx_pkts)},
/* Number of skbs queued for trasmission by the driver */
{DRVSTAT_TX_INFO(tx_reqs)},
/* Number of TX work request blocks DMAed to HW */
{DRVSTAT_TX_INFO(tx_wrbs)},
/* Number of times the TX queue was stopped due to lack
* of spaces in the TXQ.
*/
{DRVSTAT_TX_INFO(tx_stops)}
};
#define ETHTOOL_TXSTATS_NUM (ARRAY_SIZE(et_tx_stats))
static const char et_self_tests[][ETH_GSTRING_LEN] = {
"MAC Loopback test",
"PHY Loopback test",
"External Loopback test",
"DDR DMA test",
"Link test"
};
#define ETHTOOL_TESTS_NUM ARRAY_SIZE(et_self_tests)
#define BE_MAC_LOOPBACK 0x0
#define BE_PHY_LOOPBACK 0x1
#define BE_ONE_PORT_EXT_LOOPBACK 0x2
#define BE_NO_LOOPBACK 0xff
static void be_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
struct be_adapter *adapter = netdev_priv(netdev);
char fw_on_flash[FW_VER_LEN];
memset(fw_on_flash, 0 , sizeof(fw_on_flash));
be_cmd_get_fw_ver(adapter, adapter->fw_ver, fw_on_flash);
strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
strlcpy(drvinfo->version, DRV_VER, sizeof(drvinfo->version));
strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN);
if (memcmp(adapter->fw_ver, fw_on_flash, FW_VER_LEN) != 0) {
strcat(drvinfo->fw_version, " [");
strcat(drvinfo->fw_version, fw_on_flash);
strcat(drvinfo->fw_version, "]");
}
strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
sizeof(drvinfo->bus_info));
drvinfo->testinfo_len = 0;
drvinfo->regdump_len = 0;
drvinfo->eedump_len = 0;
}
static u32
lancer_cmd_get_file_len(struct be_adapter *adapter, u8 *file_name)
{
u32 data_read = 0, eof;
u8 addn_status;
struct be_dma_mem data_len_cmd;
int status;
memset(&data_len_cmd, 0, sizeof(data_len_cmd));
/* data_offset and data_size should be 0 to get reg len */
status = lancer_cmd_read_object(adapter, &data_len_cmd, 0, 0,
file_name, &data_read, &eof, &addn_status);
return data_read;
}
static int
lancer_cmd_read_file(struct be_adapter *adapter, u8 *file_name,
u32 buf_len, void *buf)
{
struct be_dma_mem read_cmd;
u32 read_len = 0, total_read_len = 0, chunk_size;
u32 eof = 0;
u8 addn_status;
int status = 0;
read_cmd.size = LANCER_READ_FILE_CHUNK;
read_cmd.va = pci_alloc_consistent(adapter->pdev, read_cmd.size,
&read_cmd.dma);
if (!read_cmd.va) {
dev_err(&adapter->pdev->dev,
"Memory allocation failure while reading dump\n");
return -ENOMEM;
}
while ((total_read_len < buf_len) && !eof) {
chunk_size = min_t(u32, (buf_len - total_read_len),
LANCER_READ_FILE_CHUNK);
chunk_size = ALIGN(chunk_size, 4);
status = lancer_cmd_read_object(adapter, &read_cmd, chunk_size,
total_read_len, file_name, &read_len,
&eof, &addn_status);
if (!status) {
memcpy(buf + total_read_len, read_cmd.va, read_len);
total_read_len += read_len;
eof &= LANCER_READ_FILE_EOF_MASK;
} else {
status = -EIO;
break;
}
}
pci_free_consistent(adapter->pdev, read_cmd.size, read_cmd.va,
read_cmd.dma);
return status;
}
static int
be_get_reg_len(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
u32 log_size = 0;
if (be_physfn(adapter)) {
if (lancer_chip(adapter))
log_size = lancer_cmd_get_file_len(adapter,
LANCER_FW_DUMP_FILE);
else
be_cmd_get_reg_len(adapter, &log_size);
}
return log_size;
}
static void
be_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf)
{
struct be_adapter *adapter = netdev_priv(netdev);
if (be_physfn(adapter)) {
memset(buf, 0, regs->len);
if (lancer_chip(adapter))
lancer_cmd_read_file(adapter, LANCER_FW_DUMP_FILE,
regs->len, buf);
else
be_cmd_get_regs(adapter, regs->len, buf);
}
}
static int be_get_coalesce(struct net_device *netdev,
struct ethtool_coalesce *et)
{
struct be_adapter *adapter = netdev_priv(netdev);
struct be_eq_obj *eqo = &adapter->eq_obj[0];
et->rx_coalesce_usecs = eqo->cur_eqd;
et->rx_coalesce_usecs_high = eqo->max_eqd;
et->rx_coalesce_usecs_low = eqo->min_eqd;
et->tx_coalesce_usecs = eqo->cur_eqd;
et->tx_coalesce_usecs_high = eqo->max_eqd;
et->tx_coalesce_usecs_low = eqo->min_eqd;
et->use_adaptive_rx_coalesce = eqo->enable_aic;
et->use_adaptive_tx_coalesce = eqo->enable_aic;
return 0;
}
/* TX attributes are ignored. Only RX attributes are considered
* eqd cmd is issued in the worker thread.
*/
static int be_set_coalesce(struct net_device *netdev,
struct ethtool_coalesce *et)
{
struct be_adapter *adapter = netdev_priv(netdev);
struct be_eq_obj *eqo;
int i;
for_all_evt_queues(adapter, eqo, i) {
eqo->enable_aic = et->use_adaptive_rx_coalesce;
eqo->max_eqd = min(et->rx_coalesce_usecs_high, BE_MAX_EQD);
eqo->min_eqd = min(et->rx_coalesce_usecs_low, eqo->max_eqd);
eqo->eqd = et->rx_coalesce_usecs;
}
return 0;
}
static void
be_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, uint64_t *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
struct be_rx_obj *rxo;
struct be_tx_obj *txo;
void *p;
unsigned int i, j, base = 0, start;
for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
p = (u8 *)&adapter->drv_stats + et_stats[i].offset;
data[i] = *(u32 *)p;
}
base += ETHTOOL_STATS_NUM;
for_all_rx_queues(adapter, rxo, j) {
struct be_rx_stats *stats = rx_stats(rxo);
do {
start = u64_stats_fetch_begin_bh(&stats->sync);
data[base] = stats->rx_bytes;
data[base + 1] = stats->rx_pkts;
} while (u64_stats_fetch_retry_bh(&stats->sync, start));
for (i = 2; i < ETHTOOL_RXSTATS_NUM; i++) {
p = (u8 *)stats + et_rx_stats[i].offset;
data[base + i] = *(u32 *)p;
}
base += ETHTOOL_RXSTATS_NUM;
}
for_all_tx_queues(adapter, txo, j) {
struct be_tx_stats *stats = tx_stats(txo);
do {
start = u64_stats_fetch_begin_bh(&stats->sync_compl);
data[base] = stats->tx_compl;
} while (u64_stats_fetch_retry_bh(&stats->sync_compl, start));
do {
start = u64_stats_fetch_begin_bh(&stats->sync);
for (i = 1; i < ETHTOOL_TXSTATS_NUM; i++) {
p = (u8 *)stats + et_tx_stats[i].offset;
data[base + i] =
(et_tx_stats[i].size == sizeof(u64)) ?
*(u64 *)p : *(u32 *)p;
}
} while (u64_stats_fetch_retry_bh(&stats->sync, start));
base += ETHTOOL_TXSTATS_NUM;
}
}
static void
be_get_stat_strings(struct net_device *netdev, uint32_t stringset,
uint8_t *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
int i, j;
switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
memcpy(data, et_stats[i].desc, ETH_GSTRING_LEN);
data += ETH_GSTRING_LEN;
}
for (i = 0; i < adapter->num_rx_qs; i++) {
for (j = 0; j < ETHTOOL_RXSTATS_NUM; j++) {
sprintf(data, "rxq%d: %s", i,
et_rx_stats[j].desc);
data += ETH_GSTRING_LEN;
}
}
for (i = 0; i < adapter->num_tx_qs; i++) {
for (j = 0; j < ETHTOOL_TXSTATS_NUM; j++) {
sprintf(data, "txq%d: %s", i,
et_tx_stats[j].desc);
data += ETH_GSTRING_LEN;
}
}
break;
case ETH_SS_TEST:
for (i = 0; i < ETHTOOL_TESTS_NUM; i++) {
memcpy(data, et_self_tests[i], ETH_GSTRING_LEN);
data += ETH_GSTRING_LEN;
}
break;
}
}
static int be_get_sset_count(struct net_device *netdev, int stringset)
{
struct be_adapter *adapter = netdev_priv(netdev);
switch (stringset) {
case ETH_SS_TEST:
return ETHTOOL_TESTS_NUM;
case ETH_SS_STATS:
return ETHTOOL_STATS_NUM +
adapter->num_rx_qs * ETHTOOL_RXSTATS_NUM +
adapter->num_tx_qs * ETHTOOL_TXSTATS_NUM;
default:
return -EINVAL;
}
}
static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
struct be_adapter *adapter = netdev_priv(netdev);
struct be_phy_info phy_info;
u8 mac_speed = 0;
u16 link_speed = 0;
u8 link_status;
int status;
if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) {
status = be_cmd_link_status_query(adapter, &mac_speed,
&link_speed, &link_status, 0);
if (!status)
be_link_status_update(adapter, link_status);
/* link_speed is in units of 10 Mbps */
if (link_speed) {
ethtool_cmd_speed_set(ecmd, link_speed*10);
} else {
switch (mac_speed) {
case PHY_LINK_SPEED_10MBPS:
ethtool_cmd_speed_set(ecmd, SPEED_10);
break;
case PHY_LINK_SPEED_100MBPS:
ethtool_cmd_speed_set(ecmd, SPEED_100);
break;
case PHY_LINK_SPEED_1GBPS:
ethtool_cmd_speed_set(ecmd, SPEED_1000);
break;
case PHY_LINK_SPEED_10GBPS:
ethtool_cmd_speed_set(ecmd, SPEED_10000);
break;
case PHY_LINK_SPEED_ZERO:
ethtool_cmd_speed_set(ecmd, 0);
break;
}
}
status = be_cmd_get_phy_info(adapter, &phy_info);
if (!status) {
switch (phy_info.interface_type) {
case PHY_TYPE_XFP_10GB:
case PHY_TYPE_SFP_1GB:
case PHY_TYPE_SFP_PLUS_10GB:
ecmd->port = PORT_FIBRE;
break;
default:
ecmd->port = PORT_TP;
break;
}
switch (phy_info.interface_type) {
case PHY_TYPE_KR_10GB:
case PHY_TYPE_KX4_10GB:
ecmd->autoneg = AUTONEG_ENABLE;
ecmd->transceiver = XCVR_INTERNAL;
break;
default:
ecmd->autoneg = AUTONEG_DISABLE;
ecmd->transceiver = XCVR_EXTERNAL;
break;
}
}
/* Save for future use */
adapter->link_speed = ethtool_cmd_speed(ecmd);
adapter->port_type = ecmd->port;
adapter->transceiver = ecmd->transceiver;
adapter->autoneg = ecmd->autoneg;
} else {
ethtool_cmd_speed_set(ecmd, adapter->link_speed);
ecmd->port = adapter->port_type;
ecmd->transceiver = adapter->transceiver;
ecmd->autoneg = adapter->autoneg;
}
ecmd->duplex = DUPLEX_FULL;
ecmd->phy_address = adapter->port_num;
switch (ecmd->port) {
case PORT_FIBRE:
ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
break;
case PORT_TP:
ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_TP);
break;
case PORT_AUI:
ecmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_AUI);
break;
}
if (ecmd->autoneg) {
ecmd->supported |= SUPPORTED_1000baseT_Full;
ecmd->supported |= SUPPORTED_Autoneg;
ecmd->advertising |= (ADVERTISED_10000baseT_Full |
ADVERTISED_1000baseT_Full);
}
return 0;
}
static void be_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
struct be_adapter *adapter = netdev_priv(netdev);
ring->rx_max_pending = ring->rx_pending = adapter->rx_obj[0].q.len;
ring->tx_max_pending = ring->tx_pending = adapter->tx_obj[0].q.len;
}
static void
be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
{
struct be_adapter *adapter = netdev_priv(netdev);
be_cmd_get_flow_control(adapter, &ecmd->tx_pause, &ecmd->rx_pause);
ecmd->autoneg = 0;
}
static int
be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
{
struct be_adapter *adapter = netdev_priv(netdev);
int status;
if (ecmd->autoneg != 0)
return -EINVAL;
adapter->tx_fc = ecmd->tx_pause;
adapter->rx_fc = ecmd->rx_pause;
status = be_cmd_set_flow_control(adapter,
adapter->tx_fc, adapter->rx_fc);
if (status)
dev_warn(&adapter->pdev->dev, "Pause param set failed.\n");
return status;
}
static int
be_set_phys_id(struct net_device *netdev,
enum ethtool_phys_id_state state)
{
struct be_adapter *adapter = netdev_priv(netdev);
switch (state) {
case ETHTOOL_ID_ACTIVE:
be_cmd_get_beacon_state(adapter, adapter->hba_port_num,
&adapter->beacon_state);
return 1; /* cycle on/off once per second */
case ETHTOOL_ID_ON:
be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
BEACON_STATE_ENABLED);
break;
case ETHTOOL_ID_OFF:
be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
BEACON_STATE_DISABLED);
break;
case ETHTOOL_ID_INACTIVE:
be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
adapter->beacon_state);
}
return 0;
}
static void
be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
struct be_adapter *adapter = netdev_priv(netdev);
if (be_is_wol_supported(adapter)) {
wol->supported |= WAKE_MAGIC;
wol->wolopts |= WAKE_MAGIC;
} else
wol->wolopts = 0;
memset(&wol->sopass, 0, sizeof(wol->sopass));
}
static int
be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
struct be_adapter *adapter = netdev_priv(netdev);
if (wol->wolopts & ~WAKE_MAGIC)
return -EOPNOTSUPP;
if (!be_is_wol_supported(adapter)) {
dev_warn(&adapter->pdev->dev, "WOL not supported\n");
return -EOPNOTSUPP;
}
if (wol->wolopts & WAKE_MAGIC)
adapter->wol = true;
else
adapter->wol = false;
return 0;
}
static int
be_test_ddr_dma(struct be_adapter *adapter)
{
int ret, i;
struct be_dma_mem ddrdma_cmd;
static const u64 pattern[2] = {
0x5a5a5a5a5a5a5a5aULL, 0xa5a5a5a5a5a5a5a5ULL
};
ddrdma_cmd.size = sizeof(struct be_cmd_req_ddrdma_test);
ddrdma_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, ddrdma_cmd.size,
&ddrdma_cmd.dma, GFP_KERNEL);
if (!ddrdma_cmd.va) {
dev_err(&adapter->pdev->dev, "Memory allocation failure\n");
return -ENOMEM;
}
for (i = 0; i < 2; i++) {
ret = be_cmd_ddr_dma_test(adapter, pattern[i],
4096, &ddrdma_cmd);
if (ret != 0)
goto err;
}
err:
dma_free_coherent(&adapter->pdev->dev, ddrdma_cmd.size, ddrdma_cmd.va,
ddrdma_cmd.dma);
return ret;
}
static u64 be_loopback_test(struct be_adapter *adapter, u8 loopback_type,
u64 *status)
{
be_cmd_set_loopback(adapter, adapter->hba_port_num,
loopback_type, 1);
*status = be_cmd_loopback_test(adapter, adapter->hba_port_num,
loopback_type, 1500,
2, 0xabc);
be_cmd_set_loopback(adapter, adapter->hba_port_num,
BE_NO_LOOPBACK, 1);
return *status;
}
static void
be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
u8 mac_speed = 0;
u16 qos_link_speed = 0;
memset(data, 0, sizeof(u64) * ETHTOOL_TESTS_NUM);
if (test->flags & ETH_TEST_FL_OFFLINE) {
if (be_loopback_test(adapter, BE_MAC_LOOPBACK,
&data[0]) != 0) {
test->flags |= ETH_TEST_FL_FAILED;
}
if (be_loopback_test(adapter, BE_PHY_LOOPBACK,
&data[1]) != 0) {
test->flags |= ETH_TEST_FL_FAILED;
}
if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK,
&data[2]) != 0) {
test->flags |= ETH_TEST_FL_FAILED;
}
}
if (be_test_ddr_dma(adapter) != 0) {
data[3] = 1;
test->flags |= ETH_TEST_FL_FAILED;
}
if (be_cmd_link_status_query(adapter, &mac_speed,
&qos_link_speed, NULL, 0) != 0) {
test->flags |= ETH_TEST_FL_FAILED;
data[4] = -1;
} else if (!mac_speed) {
test->flags |= ETH_TEST_FL_FAILED;
data[4] = 1;
}
}
static int
be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
{
struct be_adapter *adapter = netdev_priv(netdev);
return be_load_fw(adapter, efl->data);
}
static int
be_get_eeprom_len(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
if (lancer_chip(adapter)) {
if (be_physfn(adapter))
return lancer_cmd_get_file_len(adapter,
LANCER_VPD_PF_FILE);
else
return lancer_cmd_get_file_len(adapter,
LANCER_VPD_VF_FILE);
} else {
return BE_READ_SEEPROM_LEN;
}
}
static int
be_read_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
uint8_t *data)
{
struct be_adapter *adapter = netdev_priv(netdev);
struct be_dma_mem eeprom_cmd;
struct be_cmd_resp_seeprom_read *resp;
int status;
if (!eeprom->len)
return -EINVAL;
if (lancer_chip(adapter)) {
if (be_physfn(adapter))
return lancer_cmd_read_file(adapter, LANCER_VPD_PF_FILE,
eeprom->len, data);
else
return lancer_cmd_read_file(adapter, LANCER_VPD_VF_FILE,
eeprom->len, data);
}
eeprom->magic = BE_VENDOR_ID | (adapter->pdev->device<<16);
memset(&eeprom_cmd, 0, sizeof(struct be_dma_mem));
eeprom_cmd.size = sizeof(struct be_cmd_req_seeprom_read);
eeprom_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, eeprom_cmd.size,
&eeprom_cmd.dma, GFP_KERNEL);
if (!eeprom_cmd.va) {
dev_err(&adapter->pdev->dev,
"Memory allocation failure. Could not read eeprom\n");
return -ENOMEM;
}
status = be_cmd_get_seeprom_data(adapter, &eeprom_cmd);
if (!status) {
resp = eeprom_cmd.va;
memcpy(data, resp->seeprom_data + eeprom->offset, eeprom->len);
}
dma_free_coherent(&adapter->pdev->dev, eeprom_cmd.size, eeprom_cmd.va,
eeprom_cmd.dma);
return status;
}
const struct ethtool_ops be_ethtool_ops = {
.get_settings = be_get_settings,
.get_drvinfo = be_get_drvinfo,
.get_wol = be_get_wol,
.set_wol = be_set_wol,
.get_link = ethtool_op_get_link,
.get_eeprom_len = be_get_eeprom_len,
.get_eeprom = be_read_eeprom,
.get_coalesce = be_get_coalesce,
.set_coalesce = be_set_coalesce,
.get_ringparam = be_get_ringparam,
.get_pauseparam = be_get_pauseparam,
.set_pauseparam = be_set_pauseparam,
.get_strings = be_get_stat_strings,
.set_phys_id = be_set_phys_id,
.get_sset_count = be_get_sset_count,
.get_ethtool_stats = be_get_ethtool_stats,
.get_regs_len = be_get_reg_len,
.get_regs = be_get_regs,
.flash_device = be_do_flash,
.self_test = be_self_test,
};
@@ -0,0 +1,512 @@
/*
* Copyright (C) 2005 - 2011 Emulex
* All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation. The full GNU General
* Public License is included in this distribution in the file called COPYING.
*
* Contact Information:
* linux-drivers@emulex.com
*
* Emulex
* 3333 Susan Street
* Costa Mesa, CA 92626
*/
/********* Mailbox door bell *************/
/* Used for driver communication with the FW.
* The software must write this register twice to post any command. First,
* it writes the register with hi=1 and the upper bits of the physical address
* for the MAILBOX structure. Software must poll the ready bit until this
* is acknowledged. Then, sotware writes the register with hi=0 with the lower
* bits in the address. It must poll the ready bit until the command is
* complete. Upon completion, the MAILBOX will contain a valid completion
* queue entry.
*/
#define MPU_MAILBOX_DB_OFFSET 0x160
#define MPU_MAILBOX_DB_RDY_MASK 0x1 /* bit 0 */
#define MPU_MAILBOX_DB_HI_MASK 0x2 /* bit 1 */
#define MPU_EP_CONTROL 0
/********** MPU semphore ******************/
#define MPU_EP_SEMAPHORE_OFFSET 0xac
#define MPU_EP_SEMAPHORE_IF_TYPE2_OFFSET 0x400
#define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF
#define EP_SEMAPHORE_POST_ERR_MASK 0x1
#define EP_SEMAPHORE_POST_ERR_SHIFT 31
/* MPU semphore POST stage values */
#define POST_STAGE_AWAITING_HOST_RDY 0x1 /* FW awaiting goahead from host */
#define POST_STAGE_HOST_RDY 0x2 /* Host has given go-ahed to FW */
#define POST_STAGE_BE_RESET 0x3 /* Host wants to reset chip */
#define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */
/* Lancer SLIPORT_CONTROL SLIPORT_STATUS registers */
#define SLIPORT_STATUS_OFFSET 0x404
#define SLIPORT_CONTROL_OFFSET 0x408
#define SLIPORT_ERROR1_OFFSET 0x40C
#define SLIPORT_ERROR2_OFFSET 0x410
#define SLIPORT_STATUS_ERR_MASK 0x80000000
#define SLIPORT_STATUS_RN_MASK 0x01000000
#define SLIPORT_STATUS_RDY_MASK 0x00800000
#define SLI_PORT_CONTROL_IP_MASK 0x08000000
/********* Memory BAR register ************/
#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc
/* Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt
* Disable" may still globally block interrupts in addition to individual
* interrupt masks; a mechanism for the device driver to block all interrupts
* atomically without having to arbitrate for the PCI Interrupt Disable bit
* with the OS.
*/
#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */
/********* Power management (WOL) **********/
#define PCICFG_PM_CONTROL_OFFSET 0x44
#define PCICFG_PM_CONTROL_MASK 0x108 /* bits 3 & 8 */
/********* Online Control Registers *******/
#define PCICFG_ONLINE0 0xB0
#define PCICFG_ONLINE1 0xB4
/********* UE Status and Mask Registers ***/
#define PCICFG_UE_STATUS_LOW 0xA0
#define PCICFG_UE_STATUS_HIGH 0xA4
#define PCICFG_UE_STATUS_LOW_MASK 0xA8
#define PCICFG_UE_STATUS_HI_MASK 0xAC
/******** SLI_INTF ***********************/
#define SLI_INTF_REG_OFFSET 0x58
#define SLI_INTF_VALID_MASK 0xE0000000
#define SLI_INTF_VALID 0xC0000000
#define SLI_INTF_HINT2_MASK 0x1F000000
#define SLI_INTF_HINT2_SHIFT 24
#define SLI_INTF_HINT1_MASK 0x00FF0000
#define SLI_INTF_HINT1_SHIFT 16
#define SLI_INTF_FAMILY_MASK 0x00000F00
#define SLI_INTF_FAMILY_SHIFT 8
#define SLI_INTF_IF_TYPE_MASK 0x0000F000
#define SLI_INTF_IF_TYPE_SHIFT 12
#define SLI_INTF_REV_MASK 0x000000F0
#define SLI_INTF_REV_SHIFT 4
#define SLI_INTF_FT_MASK 0x00000001
/* SLI family */
#define BE_SLI_FAMILY 0x0
#define LANCER_A0_SLI_FAMILY 0xA
/********* ISR0 Register offset **********/
#define CEV_ISR0_OFFSET 0xC18
#define CEV_ISR_SIZE 4
/********* Event Q door bell *************/
#define DB_EQ_OFFSET DB_CQ_OFFSET
#define DB_EQ_RING_ID_MASK 0x1FF /* bits 0 - 8 */
#define DB_EQ_RING_ID_EXT_MASK 0x3e00 /* bits 9-13 */
#define DB_EQ_RING_ID_EXT_MASK_SHIFT (2) /* qid bits 9-13 placing at 11-15 */
/* Clear the interrupt for this eq */
#define DB_EQ_CLR_SHIFT (9) /* bit 9 */
/* Must be 1 */
#define DB_EQ_EVNT_SHIFT (10) /* bit 10 */
/* Number of event entries processed */
#define DB_EQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
/* Rearm bit */
#define DB_EQ_REARM_SHIFT (29) /* bit 29 */
/********* Compl Q door bell *************/
#define DB_CQ_OFFSET 0x120
#define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
#define DB_CQ_RING_ID_EXT_MASK 0x7C00 /* bits 10-14 */
#define DB_CQ_RING_ID_EXT_MASK_SHIFT (1) /* qid bits 10-14
placing at 11-15 */
/* Number of event entries processed */
#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
/* Rearm bit */
#define DB_CQ_REARM_SHIFT (29) /* bit 29 */
/********** TX ULP door bell *************/
#define DB_TXULP1_OFFSET 0x60
#define DB_TXULP_RING_ID_MASK 0x7FF /* bits 0 - 10 */
/* Number of tx entries posted */
#define DB_TXULP_NUM_POSTED_SHIFT (16) /* bits 16 - 29 */
#define DB_TXULP_NUM_POSTED_MASK 0x3FFF /* bits 16 - 29 */
/********** RQ(erx) door bell ************/
#define DB_RQ_OFFSET 0x100
#define DB_RQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
/* Number of rx frags posted */
#define DB_RQ_NUM_POSTED_SHIFT (24) /* bits 24 - 31 */
/********** MCC door bell ************/
#define DB_MCCQ_OFFSET 0x140
#define DB_MCCQ_RING_ID_MASK 0x7FF /* bits 0 - 10 */
/* Number of entries posted */
#define DB_MCCQ_NUM_POSTED_SHIFT (16) /* bits 16 - 29 */
/********** SRIOV VF PCICFG OFFSET ********/
#define SRIOV_VF_PCICFG_OFFSET (4096)
/********** FAT TABLE ********/
#define RETRIEVE_FAT 0
#define QUERY_FAT 1
/* Flashrom related descriptors */
#define IMAGE_TYPE_FIRMWARE 160
#define IMAGE_TYPE_BOOTCODE 224
#define IMAGE_TYPE_OPTIONROM 32
#define NUM_FLASHDIR_ENTRIES 32
#define IMG_TYPE_ISCSI_ACTIVE 0
#define IMG_TYPE_REDBOOT 1
#define IMG_TYPE_BIOS 2
#define IMG_TYPE_PXE_BIOS 3
#define IMG_TYPE_FCOE_BIOS 8
#define IMG_TYPE_ISCSI_BACKUP 9
#define IMG_TYPE_FCOE_FW_ACTIVE 10
#define IMG_TYPE_FCOE_FW_BACKUP 11
#define IMG_TYPE_NCSI_FW 13
#define IMG_TYPE_PHY_FW 99
#define TN_8022 13
#define ILLEGAL_IOCTL_REQ 2
#define FLASHROM_OPER_PHY_FLASH 9
#define FLASHROM_OPER_PHY_SAVE 10
#define FLASHROM_OPER_FLASH 1
#define FLASHROM_OPER_SAVE 2
#define FLASHROM_OPER_REPORT 4
#define FLASH_IMAGE_MAX_SIZE_g2 (1310720) /* Max firmware image size */
#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 (262144) /* Max OPTION ROM image sz */
#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 (262144) /* Max Redboot image sz */
#define FLASH_IMAGE_MAX_SIZE_g3 (2097152) /* Max firmware image size */
#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 (524288) /* Max OPTION ROM image sz */
#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 (1048576) /* Max Redboot image sz */
#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 (262144)
#define FLASH_PHY_FW_IMAGE_MAX_SIZE_g3 262144
#define FLASH_NCSI_MAGIC (0x16032009)
#define FLASH_NCSI_DISABLED (0)
#define FLASH_NCSI_ENABLED (1)
#define FLASH_NCSI_BITFILE_HDR_OFFSET (0x600000)
/* Offsets for components on Flash. */
#define FLASH_iSCSI_PRIMARY_IMAGE_START_g2 (1048576)
#define FLASH_iSCSI_BACKUP_IMAGE_START_g2 (2359296)
#define FLASH_FCoE_PRIMARY_IMAGE_START_g2 (3670016)
#define FLASH_FCoE_BACKUP_IMAGE_START_g2 (4980736)
#define FLASH_iSCSI_BIOS_START_g2 (7340032)
#define FLASH_PXE_BIOS_START_g2 (7864320)
#define FLASH_FCoE_BIOS_START_g2 (524288)
#define FLASH_REDBOOT_START_g2 (0)
#define FLASH_NCSI_START_g3 (15990784)
#define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 (2097152)
#define FLASH_iSCSI_BACKUP_IMAGE_START_g3 (4194304)
#define FLASH_FCoE_PRIMARY_IMAGE_START_g3 (6291456)
#define FLASH_FCoE_BACKUP_IMAGE_START_g3 (8388608)
#define FLASH_iSCSI_BIOS_START_g3 (12582912)
#define FLASH_PXE_BIOS_START_g3 (13107200)
#define FLASH_FCoE_BIOS_START_g3 (13631488)
#define FLASH_REDBOOT_START_g3 (262144)
#define FLASH_PHY_FW_START_g3 1310720
/************* Rx Packet Type Encoding **************/
#define BE_UNICAST_PACKET 0
#define BE_MULTICAST_PACKET 1
#define BE_BROADCAST_PACKET 2
#define BE_RSVD_PACKET 3
/*
* BE descriptors: host memory data structures whose formats
* are hardwired in BE silicon.
*/
/* Event Queue Descriptor */
#define EQ_ENTRY_VALID_MASK 0x1 /* bit 0 */
#define EQ_ENTRY_RES_ID_MASK 0xFFFF /* bits 16 - 31 */
#define EQ_ENTRY_RES_ID_SHIFT 16
struct be_eq_entry {
u32 evt;
};
/* TX Queue Descriptor */
#define ETH_WRB_FRAG_LEN_MASK 0xFFFF
struct be_eth_wrb {
u32 frag_pa_hi; /* dword 0 */
u32 frag_pa_lo; /* dword 1 */
u32 rsvd0; /* dword 2 */
u32 frag_len; /* dword 3: bits 0 - 15 */
} __packed;
/* Pseudo amap definition for eth_hdr_wrb in which each bit of the
* actual structure is defined as a byte : used to calculate
* offset/shift/mask of each field */
struct amap_eth_hdr_wrb {
u8 rsvd0[32]; /* dword 0 */
u8 rsvd1[32]; /* dword 1 */
u8 complete; /* dword 2 */
u8 event;
u8 crc;
u8 forward;
u8 lso6;
u8 mgmt;
u8 ipcs;
u8 udpcs;
u8 tcpcs;
u8 lso;
u8 vlan;
u8 gso[2];
u8 num_wrb[5];
u8 lso_mss[14];
u8 len[16]; /* dword 3 */
u8 vlan_tag[16];
} __packed;
struct be_eth_hdr_wrb {
u32 dw[4];
};
/* TX Compl Queue Descriptor */
/* Pseudo amap definition for eth_tx_compl in which each bit of the
* actual structure is defined as a byte: used to calculate
* offset/shift/mask of each field */
struct amap_eth_tx_compl {
u8 wrb_index[16]; /* dword 0 */
u8 ct[2]; /* dword 0 */
u8 port[2]; /* dword 0 */
u8 rsvd0[8]; /* dword 0 */
u8 status[4]; /* dword 0 */
u8 user_bytes[16]; /* dword 1 */
u8 nwh_bytes[8]; /* dword 1 */
u8 lso; /* dword 1 */
u8 cast_enc[2]; /* dword 1 */
u8 rsvd1[5]; /* dword 1 */
u8 rsvd2[32]; /* dword 2 */
u8 pkts[16]; /* dword 3 */
u8 ringid[11]; /* dword 3 */
u8 hash_val[4]; /* dword 3 */
u8 valid; /* dword 3 */
} __packed;
struct be_eth_tx_compl {
u32 dw[4];
};
/* RX Queue Descriptor */
struct be_eth_rx_d {
u32 fragpa_hi;
u32 fragpa_lo;
};
/* RX Compl Queue Descriptor */
/* Pseudo amap definition for BE2 and BE3 legacy mode eth_rx_compl in which
* each bit of the actual structure is defined as a byte: used to calculate
* offset/shift/mask of each field */
struct amap_eth_rx_compl_v0 {
u8 vlan_tag[16]; /* dword 0 */
u8 pktsize[14]; /* dword 0 */
u8 port; /* dword 0 */
u8 ip_opt; /* dword 0 */
u8 err; /* dword 1 */
u8 rsshp; /* dword 1 */
u8 ipf; /* dword 1 */
u8 tcpf; /* dword 1 */
u8 udpf; /* dword 1 */
u8 ipcksm; /* dword 1 */
u8 l4_cksm; /* dword 1 */
u8 ip_version; /* dword 1 */
u8 macdst[6]; /* dword 1 */
u8 vtp; /* dword 1 */
u8 rsvd0; /* dword 1 */
u8 fragndx[10]; /* dword 1 */
u8 ct[2]; /* dword 1 */
u8 sw; /* dword 1 */
u8 numfrags[3]; /* dword 1 */
u8 rss_flush; /* dword 2 */
u8 cast_enc[2]; /* dword 2 */
u8 vtm; /* dword 2 */
u8 rss_bank; /* dword 2 */
u8 rsvd1[23]; /* dword 2 */
u8 lro_pkt; /* dword 2 */
u8 rsvd2[2]; /* dword 2 */
u8 valid; /* dword 2 */
u8 rsshash[32]; /* dword 3 */
} __packed;
/* Pseudo amap definition for BE3 native mode eth_rx_compl in which
* each bit of the actual structure is defined as a byte: used to calculate
* offset/shift/mask of each field */
struct amap_eth_rx_compl_v1 {
u8 vlan_tag[16]; /* dword 0 */
u8 pktsize[14]; /* dword 0 */
u8 vtp; /* dword 0 */
u8 ip_opt; /* dword 0 */
u8 err; /* dword 1 */
u8 rsshp; /* dword 1 */
u8 ipf; /* dword 1 */
u8 tcpf; /* dword 1 */
u8 udpf; /* dword 1 */
u8 ipcksm; /* dword 1 */
u8 l4_cksm; /* dword 1 */
u8 ip_version; /* dword 1 */
u8 macdst[7]; /* dword 1 */
u8 rsvd0; /* dword 1 */
u8 fragndx[10]; /* dword 1 */
u8 ct[2]; /* dword 1 */
u8 sw; /* dword 1 */
u8 numfrags[3]; /* dword 1 */
u8 rss_flush; /* dword 2 */
u8 cast_enc[2]; /* dword 2 */
u8 vtm; /* dword 2 */
u8 rss_bank; /* dword 2 */
u8 port[2]; /* dword 2 */
u8 vntagp; /* dword 2 */
u8 header_len[8]; /* dword 2 */
u8 header_split[2]; /* dword 2 */
u8 rsvd1[13]; /* dword 2 */
u8 valid; /* dword 2 */
u8 rsshash[32]; /* dword 3 */
} __packed;
struct be_eth_rx_compl {
u32 dw[4];
};
struct mgmt_hba_attribs {
u8 flashrom_version_string[32];
u8 manufacturer_name[32];
u32 supported_modes;
u32 rsvd0[3];
u8 ncsi_ver_string[12];
u32 default_extended_timeout;
u8 controller_model_number[32];
u8 controller_description[64];
u8 controller_serial_number[32];
u8 ip_version_string[32];
u8 firmware_version_string[32];
u8 bios_version_string[32];
u8 redboot_version_string[32];
u8 driver_version_string[32];
u8 fw_on_flash_version_string[32];
u32 functionalities_supported;
u16 max_cdblength;
u8 asic_revision;
u8 generational_guid[16];
u8 hba_port_count;
u16 default_link_down_timeout;
u8 iscsi_ver_min_max;
u8 multifunction_device;
u8 cache_valid;
u8 hba_status;
u8 max_domains_supported;
u8 phy_port;
u32 firmware_post_status;
u32 hba_mtu[8];
u32 rsvd1[4];
};
struct mgmt_controller_attrib {
struct mgmt_hba_attribs hba_attribs;
u16 pci_vendor_id;
u16 pci_device_id;
u16 pci_sub_vendor_id;
u16 pci_sub_system_id;
u8 pci_bus_number;
u8 pci_device_number;
u8 pci_function_number;
u8 interface_type;
u64 unique_identifier;
u32 rsvd0[5];
};
struct controller_id {
u32 vendor;
u32 device;
u32 subvendor;
u32 subdevice;
};
struct flash_comp {
unsigned long offset;
int optype;
int size;
};
struct image_hdr {
u32 imageid;
u32 imageoffset;
u32 imagelength;
u32 image_checksum;
u8 image_version[32];
};
struct flash_file_hdr_g2 {
u8 sign[32];
u32 cksum;
u32 antidote;
struct controller_id cont_id;
u32 file_len;
u32 chunk_num;
u32 total_chunks;
u32 num_imgs;
u8 build[24];
};
struct flash_file_hdr_g3 {
u8 sign[52];
u8 ufi_version[4];
u32 file_len;
u32 cksum;
u32 antidote;
u32 num_imgs;
u8 build[24];
u8 rsvd[32];
};
struct flash_section_hdr {
u32 format_rev;
u32 cksum;
u32 antidote;
u32 build_no;
u8 id_string[64];
u32 active_entry_mask;
u32 valid_entry_mask;
u32 org_content_mask;
u32 rsvd0;
u32 rsvd1;
u32 rsvd2;
u32 rsvd3;
u32 rsvd4;
};
struct flash_section_entry {
u32 type;
u32 offset;
u32 pad_size;
u32 image_size;
u32 cksum;
u32 entry_point;
u32 rsvd0;
u32 rsvd1;
u8 ver_data[32];
};
struct flash_section_info {
u8 cookie[32];
struct flash_section_hdr fsec_hdr;
struct flash_section_entry fsec_entry[32];
};
File diff suppressed because it is too large Load Diff