aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/benet
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/benet')
-rw-r--r--drivers/net/benet/be.h31
-rw-r--r--drivers/net/benet/be_cmds.c116
-rw-r--r--drivers/net/benet/be_cmds.h23
-rw-r--r--drivers/net/benet/be_ethtool.c119
-rw-r--r--drivers/net/benet/be_hw.h4
-rw-r--r--drivers/net/benet/be_main.c207
6 files changed, 342 insertions, 158 deletions
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index 2353eca3259..41bbc32123f 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -84,15 +84,14 @@ static inline char *nic_name(struct pci_dev *pdev)
#define MCC_CQ_LEN 256
#define MAX_RSS_QS 4 /* BE limit is 4 queues/port */
-#define BE_MAX_MSIX_VECTORS (MAX_RSS_QS + 1 + 1)/* RSS qs + 1 def Rx + Tx */
+#define MAX_RX_QS (MAX_RSS_QS + 1) /* RSS qs + 1 def Rx */
+#define BE_MAX_MSIX_VECTORS (MAX_RX_QS + 1)/* RX + TX */
#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
-#define BE_MAX_VF 32
-
struct be_dma_mem {
void *va;
dma_addr_t dma;
@@ -276,7 +275,7 @@ struct be_adapter {
spinlock_t mcc_cq_lock;
struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS];
- bool msix_enabled;
+ u32 num_msix_vec;
bool isr_registered;
/* TX Rings */
@@ -287,7 +286,7 @@ struct be_adapter {
u32 cache_line_break[8];
/* Rx rings */
- struct be_rx_obj rx_obj[MAX_RSS_QS + 1]; /* one default non-rss Q */
+ struct be_rx_obj rx_obj[MAX_RX_QS];
u32 num_rx_qs;
u32 big_page_size; /* Compounded page size shared by rx wrbs */
@@ -308,10 +307,10 @@ struct be_adapter {
u16 work_counter;
/* Ethtool knobs and info */
- bool rx_csum; /* BE card must perform rx-checksumming */
char fw_ver[FW_VER_LEN];
u32 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 link_up;
@@ -334,7 +333,7 @@ struct be_adapter {
bool be3_native;
bool sriov_enabled;
- struct be_vf_cfg vf_cfg[BE_MAX_VF];
+ struct be_vf_cfg *vf_cfg;
u8 is_virtfn;
u32 sli_family;
u8 hba_port_num;
@@ -351,6 +350,7 @@ struct be_adapter {
extern const struct ethtool_ops be_ethtool_ops;
+#define msix_enabled(adapter) (adapter->num_msix_vec > 0)
#define tx_stats(adapter) (&adapter->tx_stats)
#define rx_stats(rxo) (&rxo->stats)
@@ -455,18 +455,10 @@ static inline u8 is_udp_pkt(struct sk_buff *skb)
static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
{
- u8 data;
u32 sli_intf;
- if (lancer_chip(adapter)) {
- pci_read_config_dword(adapter->pdev, SLI_INTF_REG_OFFSET,
- &sli_intf);
- adapter->is_virtfn = (sli_intf & SLI_INTF_FT_MASK) ? 1 : 0;
- } else {
- pci_write_config_byte(adapter->pdev, 0xFE, 0xAA);
- pci_read_config_byte(adapter->pdev, 0xFE, &data);
- adapter->is_virtfn = (data != 0xAA);
- }
+ 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)
@@ -482,6 +474,11 @@ static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
memcpy(mac, adapter->netdev->dev_addr, 3);
}
+static inline bool be_multi_rxq(const struct be_adapter *adapter)
+{
+ return adapter->num_rx_qs > 1;
+}
+
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, bool link_up);
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index 9dc9394fd4c..5fedc27c883 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -78,7 +78,8 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
}
if (compl_status == MCC_STATUS_SUCCESS) {
- if (compl->tag0 == OPCODE_ETH_GET_STATISTICS) {
+ if ((compl->tag0 == OPCODE_ETH_GET_STATISTICS) &&
+ (compl->tag1 == CMD_SUBSYSTEM_ETH)) {
struct be_cmd_resp_get_stats *resp =
adapter->stats_cmd.va;
be_dws_le_to_cpu(&resp->hw_stats,
@@ -1096,6 +1097,7 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
OPCODE_ETH_GET_STATISTICS, sizeof(*req));
+ wrb->tag1 = CMD_SUBSYSTEM_ETH;
sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
sge->len = cpu_to_le32(nonemb_cmd->size);
@@ -1110,7 +1112,7 @@ err:
/* Uses synchronous mcc */
int be_cmd_link_status_query(struct be_adapter *adapter,
- bool *link_up, u8 *mac_speed, u16 *link_speed)
+ bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_link_status *req;
@@ -1186,6 +1188,116 @@ err:
return status;
}
+/* Uses synchronous mcc */
+int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_fat *req;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+ req = embedded_payload(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
+ OPCODE_COMMON_MANAGE_FAT);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_MANAGE_FAT, sizeof(*req));
+ req->fat_operation = cpu_to_le32(QUERY_FAT);
+ status = be_mcc_notify_wait(adapter);
+ if (!status) {
+ struct be_cmd_resp_get_fat *resp = embedded_payload(wrb);
+ if (log_size && resp->log_size)
+ *log_size = le32_to_cpu(resp->log_size) -
+ sizeof(u32);
+ }
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
+void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf)
+{
+ struct be_dma_mem get_fat_cmd;
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_fat *req;
+ struct be_sge *sge;
+ u32 offset = 0, total_size, buf_size,
+ log_offset = sizeof(u32), payload_len;
+ int status;
+
+ if (buf_len == 0)
+ return;
+
+ total_size = buf_len;
+
+ get_fat_cmd.size = sizeof(struct be_cmd_req_get_fat) + 60*1024;
+ get_fat_cmd.va = pci_alloc_consistent(adapter->pdev,
+ get_fat_cmd.size,
+ &get_fat_cmd.dma);
+ if (!get_fat_cmd.va) {
+ status = -ENOMEM;
+ dev_err(&adapter->pdev->dev,
+ "Memory allocation failure while retrieving FAT data\n");
+ return;
+ }
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ while (total_size) {
+ buf_size = min(total_size, (u32)60*1024);
+ total_size -= buf_size;
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+ req = get_fat_cmd.va;
+ sge = nonembedded_sgl(wrb);
+
+ payload_len = sizeof(struct be_cmd_req_get_fat) + buf_size;
+ be_wrb_hdr_prepare(wrb, payload_len, false, 1,
+ OPCODE_COMMON_MANAGE_FAT);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_MANAGE_FAT, payload_len);
+
+ sge->pa_hi = cpu_to_le32(upper_32_bits(get_fat_cmd.dma));
+ sge->pa_lo = cpu_to_le32(get_fat_cmd.dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(get_fat_cmd.size);
+
+ req->fat_operation = cpu_to_le32(RETRIEVE_FAT);
+ req->read_log_offset = cpu_to_le32(log_offset);
+ req->read_log_length = cpu_to_le32(buf_size);
+ req->data_buffer_size = cpu_to_le32(buf_size);
+
+ status = be_mcc_notify_wait(adapter);
+ if (!status) {
+ struct be_cmd_resp_get_fat *resp = get_fat_cmd.va;
+ memcpy(buf + offset,
+ resp->data_buffer,
+ resp->read_log_length);
+ } else {
+ dev_err(&adapter->pdev->dev, "FAT Table Retrieve error\n");
+ goto err;
+ }
+ offset += buf_size;
+ log_offset += buf_size;
+ }
+err:
+ pci_free_consistent(adapter->pdev, get_fat_cmd.size,
+ get_fat_cmd.va,
+ get_fat_cmd.dma);
+ spin_unlock_bh(&adapter->mcc_lock);
+}
+
/* Uses Mbox */
int be_cmd_get_fw_ver(struct be_adapter *adapter, char *fw_ver)
{
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index 4f254cfaabe..af4bbff5feb 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -186,6 +186,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_NTWK_PMAC_ADD 59
#define OPCODE_COMMON_NTWK_PMAC_DEL 60
#define OPCODE_COMMON_FUNCTION_RESET 61
+#define OPCODE_COMMON_MANAGE_FAT 68
#define OPCODE_COMMON_ENABLE_DISABLE_BEACON 69
#define OPCODE_COMMON_GET_BEACON_STATE 70
#define OPCODE_COMMON_READ_TRANSRECV_DATA 73
@@ -380,6 +381,24 @@ struct be_cmd_resp_cq_create {
u16 rsvd0;
} __packed;
+struct be_cmd_req_get_fat {
+ struct be_cmd_req_hdr hdr;
+ u32 fat_operation;
+ u32 read_log_offset;
+ u32 read_log_length;
+ u32 data_buffer_size;
+ u32 data_buffer[1];
+} __packed;
+
+struct be_cmd_resp_get_fat {
+ struct be_cmd_resp_hdr hdr;
+ u32 log_size;
+ u32 read_log_length;
+ u32 rsvd[2];
+ u32 data_buffer[1];
+} __packed;
+
+
/******************** Create MCCQ ***************************/
/* Pseudo amap definition in which each bit of the actual structure is defined
* as a byte: used to calculate offset/shift/mask of each field */
@@ -1093,7 +1112,7 @@ extern int be_cmd_rxq_create(struct be_adapter *adapter,
extern int be_cmd_q_destroy(struct be_adapter *adapter, struct be_queue_info *q,
int type);
extern int be_cmd_link_status_query(struct be_adapter *adapter,
- bool *link_up, u8 *mac_speed, u16 *link_speed);
+ bool *link_up, u8 *mac_speed, u16 *link_speed, u32 dom);
extern int be_cmd_reset(struct be_adapter *adapter);
extern int be_cmd_get_stats(struct be_adapter *adapter,
struct be_dma_mem *nonemb_cmd);
@@ -1148,4 +1167,6 @@ extern void be_detect_dump_ue(struct be_adapter *adapter);
extern int be_cmd_get_die_temperature(struct be_adapter *adapter);
extern int be_cmd_get_cntl_attributes(struct be_adapter *adapter);
extern int be_cmd_check_native_mode(struct be_adapter *adapter);
+extern int be_cmd_get_reg_len(struct be_adapter *adapter, u32 *log_size);
+extern void be_cmd_get_regs(struct be_adapter *adapter, u32 buf_len, void *buf);
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index aac248fbd18..8e770e8275d 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -156,6 +156,29 @@ be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
}
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))
+ 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);
+ be_cmd_get_regs(adapter, regs->len, buf);
+ }
+}
+
+static int
be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -186,9 +209,9 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
struct be_rx_obj *rxo;
struct be_eq_obj *rx_eq;
struct be_eq_obj *tx_eq = &adapter->tx_eq;
- u32 tx_max, tx_min, tx_cur;
u32 rx_max, rx_min, rx_cur;
int status = 0, i;
+ u32 tx_cur;
if (coalesce->use_adaptive_tx_coalesce == 1)
return -EINVAL;
@@ -227,8 +250,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
}
}
- tx_max = coalesce->tx_coalesce_usecs_high;
- tx_min = coalesce->tx_coalesce_usecs_low;
tx_cur = coalesce->tx_coalesce_usecs;
if (tx_cur > BE_MAX_EQD)
@@ -242,25 +263,6 @@ be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
return 0;
}
-static u32 be_get_rx_csum(struct net_device *netdev)
-{
- struct be_adapter *adapter = netdev_priv(netdev);
-
- return adapter->rx_csum;
-}
-
-static int be_set_rx_csum(struct net_device *netdev, uint32_t data)
-{
- struct be_adapter *adapter = netdev_priv(netdev);
-
- if (data)
- adapter->rx_csum = true;
- else
- adapter->rx_csum = false;
-
- return 0;
-}
-
static void
be_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, uint64_t *data)
@@ -374,19 +376,28 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) {
status = be_cmd_link_status_query(adapter, &link_up,
- &mac_speed, &link_speed);
+ &mac_speed, &link_speed, 0);
be_link_status_update(adapter, link_up);
/* link_speed is in units of 10 Mbps */
if (link_speed) {
- ecmd->speed = link_speed*10;
+ 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:
- ecmd->speed = SPEED_1000;
+ ethtool_cmd_speed_set(ecmd, SPEED_1000);
break;
case PHY_LINK_SPEED_10GBPS:
- ecmd->speed = SPEED_10000;
+ ethtool_cmd_speed_set(ecmd, SPEED_10000);
+ break;
+ case PHY_LINK_SPEED_ZERO:
+ ethtool_cmd_speed_set(ecmd, 0);
break;
}
}
@@ -429,14 +440,14 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
}
/* Save for future use */
- adapter->link_speed = ecmd->speed;
+ adapter->link_speed = ethtool_cmd_speed(ecmd);
adapter->port_type = ecmd->port;
adapter->transceiver = ecmd->transceiver;
adapter->autoneg = ecmd->autoneg;
dma_free_coherent(&adapter->pdev->dev, phy_cmd.size, phy_cmd.va,
phy_cmd.dma);
} else {
- ecmd->speed = adapter->link_speed;
+ ethtool_cmd_speed_set(ecmd, adapter->link_speed);
ecmd->port = adapter->port_type;
ecmd->transceiver = adapter->transceiver;
ecmd->autoneg = adapter->autoneg;
@@ -507,29 +518,33 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
}
static int
-be_phys_id(struct net_device *netdev, u32 data)
+be_set_phys_id(struct net_device *netdev,
+ enum ethtool_phys_id_state state)
{
struct be_adapter *adapter = netdev_priv(netdev);
- int status;
- u32 cur;
- be_cmd_get_beacon_state(adapter, adapter->hba_port_num, &cur);
+ 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 */
- if (cur == BEACON_STATE_ENABLED)
- return 0;
-
- if (data < 2)
- data = 2;
+ case ETHTOOL_ID_ON:
+ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
+ BEACON_STATE_ENABLED);
+ break;
- status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
- BEACON_STATE_ENABLED);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(data*HZ);
+ case ETHTOOL_ID_OFF:
+ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
+ BEACON_STATE_DISABLED);
+ break;
- status = be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
- BEACON_STATE_DISABLED);
+ case ETHTOOL_ID_INACTIVE:
+ be_cmd_set_beacon_state(adapter, adapter->hba_port_num, 0, 0,
+ adapter->beacon_state);
+ }
- return status;
+ return 0;
}
static bool
@@ -646,7 +661,7 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data)
}
if (be_cmd_link_status_query(adapter, &link_up, &mac_speed,
- &qos_link_speed) != 0) {
+ &qos_link_speed, 0) != 0) {
test->flags |= ETH_TEST_FL_FAILED;
data[4] = -1;
} else if (!mac_speed) {
@@ -660,11 +675,9 @@ be_do_flash(struct net_device *netdev, struct ethtool_flash *efl)
{
struct be_adapter *adapter = netdev_priv(netdev);
char file_name[ETHTOOL_FLASH_MAX_FILENAME];
- u32 region;
file_name[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0;
strcpy(file_name, efl->data);
- region = efl->region;
return be_load_fw(adapter, file_name);
}
@@ -725,18 +738,12 @@ const struct ethtool_ops be_ethtool_ops = {
.get_ringparam = be_get_ringparam,
.get_pauseparam = be_get_pauseparam,
.set_pauseparam = be_set_pauseparam,
- .get_rx_csum = be_get_rx_csum,
- .set_rx_csum = be_set_rx_csum,
- .get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_hw_csum,
- .get_sg = ethtool_op_get_sg,
- .set_sg = ethtool_op_set_sg,
- .get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
.get_strings = be_get_stat_strings,
- .phys_id = be_phys_id,
+ .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,
};
diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h
index d4344a06090..53d658afea2 100644
--- a/drivers/net/benet/be_hw.h
+++ b/drivers/net/benet/be_hw.h
@@ -155,6 +155,10 @@
/********** 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
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 9187fb4e08f..3fb4a1f465e 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -116,11 +116,6 @@ static char *ue_status_hi_desc[] = {
"Unknown"
};
-static inline bool be_multi_rxq(struct be_adapter *adapter)
-{
- return (adapter->num_rx_qs > 1);
-}
-
static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
{
struct be_dma_mem *mem = &q->dma_mem;
@@ -993,9 +988,10 @@ static void be_rx_compl_process(struct be_adapter *adapter,
struct be_rx_obj *rxo,
struct be_rx_compl_info *rxcp)
{
+ struct net_device *netdev = adapter->netdev;
struct sk_buff *skb;
- skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN);
+ skb = netdev_alloc_skb_ip_align(netdev, BE_HDR_LEN);
if (unlikely(!skb)) {
if (net_ratelimit())
dev_warn(&adapter->pdev->dev, "skb alloc failed\n");
@@ -1005,13 +1001,16 @@ static void be_rx_compl_process(struct be_adapter *adapter,
skb_fill_rx_data(adapter, rxo, skb, rxcp);
- if (likely(adapter->rx_csum && csum_passed(rxcp)))
+ if (likely((netdev->features & NETIF_F_RXCSUM) && csum_passed(rxcp)))
skb->ip_summed = CHECKSUM_UNNECESSARY;
else
skb_checksum_none_assert(skb);
skb->truesize = skb->len + sizeof(struct sk_buff);
- skb->protocol = eth_type_trans(skb, adapter->netdev);
+ skb->protocol = eth_type_trans(skb, netdev);
+ if (adapter->netdev->features & NETIF_F_RXHASH)
+ skb->rxhash = rxcp->rss_hash;
+
if (unlikely(rxcp->vlanf)) {
if (!adapter->vlan_grp || adapter->vlans_added == 0) {
@@ -1073,6 +1072,8 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
skb->data_len = rxcp->pkt_size;
skb->truesize += rxcp->pkt_size;
skb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (adapter->netdev->features & NETIF_F_RXHASH)
+ skb->rxhash = rxcp->rss_hash;
if (likely(!rxcp->vlanf))
napi_gro_frags(&eq_obj->napi);
@@ -1103,9 +1104,14 @@ static void be_parse_rx_compl_v1(struct be_adapter *adapter,
AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl);
rxcp->pkt_type =
AMAP_GET_BITS(struct amap_eth_rx_compl_v1, cast_enc, compl);
- rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, compl);
- rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
- compl);
+ rxcp->rss_hash =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, rxcp);
+ if (rxcp->vlanf) {
+ rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm,
+ compl);
+ rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag,
+ compl);
+ }
}
static void be_parse_rx_compl_v0(struct be_adapter *adapter,
@@ -1130,9 +1136,14 @@ static void be_parse_rx_compl_v0(struct be_adapter *adapter,
AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl);
rxcp->pkt_type =
AMAP_GET_BITS(struct amap_eth_rx_compl_v0, cast_enc, compl);
- rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, compl);
- rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
- compl);
+ rxcp->rss_hash =
+ AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, rxcp);
+ if (rxcp->vlanf) {
+ rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm,
+ compl);
+ rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag,
+ compl);
+ }
}
static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
@@ -1154,17 +1165,20 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo)
else
be_parse_rx_compl_v0(adapter, compl, rxcp);
- /* vlanf could be wrongly set in some cards. ignore if vtm is not set */
- if ((adapter->function_mode & 0x400) && !rxcp->vtm)
- rxcp->vlanf = 0;
+ if (rxcp->vlanf) {
+ /* vlanf could be wrongly set in some cards.
+ * ignore if vtm is not set */
+ if ((adapter->function_mode & 0x400) && !rxcp->vtm)
+ rxcp->vlanf = 0;
- if (!lancer_chip(adapter))
- rxcp->vlan_tag = swab16(rxcp->vlan_tag);
+ if (!lancer_chip(adapter))
+ rxcp->vlan_tag = swab16(rxcp->vlan_tag);
- if (((adapter->pvid & VLAN_VID_MASK) ==
- (rxcp->vlan_tag & VLAN_VID_MASK)) &&
- !adapter->vlan_tag[rxcp->vlan_tag])
- rxcp->vlanf = 0;
+ if (((adapter->pvid & VLAN_VID_MASK) ==
+ (rxcp->vlan_tag & VLAN_VID_MASK)) &&
+ !adapter->vlan_tag[rxcp->vlan_tag])
+ rxcp->vlanf = 0;
+ }
/* As the compl has been parsed, reset it; we wont touch it again */
compl->dw[offsetof(struct amap_eth_rx_compl_v1, valid) / 32] = 0;
@@ -1573,12 +1587,31 @@ static void be_rx_queues_destroy(struct be_adapter *adapter)
}
}
+static u32 be_num_rxqs_want(struct be_adapter *adapter)
+{
+ if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
+ !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) {
+ return 1 + MAX_RSS_QS; /* one default non-RSS queue */
+ } else {
+ dev_warn(&adapter->pdev->dev,
+ "No support for multiple RX queues\n");
+ return 1;
+ }
+}
+
static int be_rx_queues_create(struct be_adapter *adapter)
{
struct be_queue_info *eq, *q, *cq;
struct be_rx_obj *rxo;
int rc, i;
+ adapter->num_rx_qs = min(be_num_rxqs_want(adapter),
+ msix_enabled(adapter) ?
+ adapter->num_msix_vec - 1 : 1);
+ if (adapter->num_rx_qs != MAX_RX_QS)
+ dev_warn(&adapter->pdev->dev,
+ "Can create only %d RX queues", adapter->num_rx_qs);
+
adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
for_all_rx_queues(adapter, rxo, i) {
rxo->adapter = adapter;
@@ -1843,6 +1876,9 @@ static void be_worker(struct work_struct *work)
struct be_rx_obj *rxo;
int i;
+ if (!adapter->ue_detected && !lancer_chip(adapter))
+ be_detect_dump_ue(adapter);
+
/* when interrupts are not yet enabled, just reap any pending
* mcc completions */
if (!netif_running(adapter->netdev)) {
@@ -1855,9 +1891,6 @@ static void be_worker(struct work_struct *work)
be_cq_notify(adapter, mcc_obj->cq.id, false, mcc_compl);
}
- if (!adapter->ue_detected && !lancer_chip(adapter))
- be_detect_dump_ue(adapter);
-
goto reschedule;
}
@@ -1875,8 +1908,6 @@ static void be_worker(struct work_struct *work)
be_post_rx_frags(rxo, GFP_KERNEL);
}
}
- if (!adapter->ue_detected && !lancer_chip(adapter))
- be_detect_dump_ue(adapter);
reschedule:
adapter->work_counter++;
@@ -1885,51 +1916,35 @@ reschedule:
static void be_msix_disable(struct be_adapter *adapter)
{
- if (adapter->msix_enabled) {
+ if (msix_enabled(adapter)) {
pci_disable_msix(adapter->pdev);
- adapter->msix_enabled = false;
- }
-}
-
-static int be_num_rxqs_get(struct be_adapter *adapter)
-{
- if (multi_rxq && (adapter->function_caps & BE_FUNCTION_CAPS_RSS) &&
- !adapter->sriov_enabled && !(adapter->function_mode & 0x400)) {
- return 1 + MAX_RSS_QS; /* one default non-RSS queue */
- } else {
- dev_warn(&adapter->pdev->dev,
- "No support for multiple RX queues\n");
- return 1;
+ adapter->num_msix_vec = 0;
}
}
static void be_msix_enable(struct be_adapter *adapter)
{
#define BE_MIN_MSIX_VECTORS (1 + 1) /* Rx + Tx */
- int i, status;
+ int i, status, num_vec;
- adapter->num_rx_qs = be_num_rxqs_get(adapter);
+ num_vec = be_num_rxqs_want(adapter) + 1;
- for (i = 0; i < (adapter->num_rx_qs + 1); i++)
+ for (i = 0; i < num_vec; i++)
adapter->msix_entries[i].entry = i;
- status = pci_enable_msix(adapter->pdev, adapter->msix_entries,
- adapter->num_rx_qs + 1);
+ status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec);
if (status == 0) {
goto done;
} else if (status >= BE_MIN_MSIX_VECTORS) {
+ num_vec = status;
if (pci_enable_msix(adapter->pdev, adapter->msix_entries,
- status) == 0) {
- adapter->num_rx_qs = status - 1;
- dev_warn(&adapter->pdev->dev,
- "Could alloc only %d MSIx vectors. "
- "Using %d RX Qs\n", status, adapter->num_rx_qs);
+ num_vec) == 0)
goto done;
- }
}
return;
done:
- adapter->msix_enabled = true;
+ adapter->num_msix_vec = num_vec;
+ return;
}
static void be_sriov_enable(struct be_adapter *adapter)
@@ -1937,7 +1952,20 @@ static void be_sriov_enable(struct be_adapter *adapter)
be_check_sriov_fn_type(adapter);
#ifdef CONFIG_PCI_IOV
if (be_physfn(adapter) && num_vfs) {
- int status;
+ int status, pos;
+ u16 nvfs;
+
+ pos = pci_find_ext_capability(adapter->pdev,
+ PCI_EXT_CAP_ID_SRIOV);
+ pci_read_config_word(adapter->pdev,
+ pos + PCI_SRIOV_TOTAL_VF, &nvfs);
+
+ if (num_vfs > nvfs) {
+ dev_info(&adapter->pdev->dev,
+ "Device supports %d VFs and not %d\n",
+ nvfs, num_vfs);
+ num_vfs = nvfs;
+ }
status = pci_enable_sriov(adapter->pdev, num_vfs);
adapter->sriov_enabled = status ? false : true;
@@ -2010,8 +2038,7 @@ err_msix:
err:
dev_warn(&adapter->pdev->dev,
"MSIX Request IRQ failed - err %d\n", status);
- pci_disable_msix(adapter->pdev);
- adapter->msix_enabled = false;
+ be_msix_disable(adapter);
return status;
}
@@ -2020,7 +2047,7 @@ static int be_irq_register(struct be_adapter *adapter)
struct net_device *netdev = adapter->netdev;
int status;
- if (adapter->msix_enabled) {
+ if (msix_enabled(adapter)) {
status = be_msix_register(adapter);
if (status == 0)
goto done;
@@ -2053,7 +2080,7 @@ static void be_irq_unregister(struct be_adapter *adapter)
return;
/* INTx */
- if (!adapter->msix_enabled) {
+ if (!msix_enabled(adapter)) {
free_irq(netdev->irq, adapter);
goto done;
}
@@ -2095,7 +2122,7 @@ static int be_close(struct net_device *netdev)
be_cq_notify(adapter, rxo->cq.id, false, 0);
}
- if (adapter->msix_enabled) {
+ if (msix_enabled(adapter)) {
vec = be_msix_vec_get(adapter, tx_eq);
synchronize_irq(vec);
@@ -2148,7 +2175,7 @@ static int be_open(struct net_device *netdev)
be_async_mcc_enable(adapter);
status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
- &link_speed);
+ &link_speed, 0);
if (status)
goto err;
be_link_status_update(adapter, link_up);
@@ -2268,7 +2295,7 @@ static int be_setup(struct be_adapter *adapter)
BE_IF_FLAGS_PASS_L3L4_ERRORS;
en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS;
- if (be_multi_rxq(adapter)) {
+ if (adapter->function_caps & BE_FUNCTION_CAPS_RSS) {
cap_flags |= BE_IF_FLAGS_RSS;
en_flags |= BE_IF_FLAGS_RSS;
}
@@ -2325,7 +2352,6 @@ static int be_setup(struct be_adapter *adapter)
return 0;
- be_mcc_queues_destroy(adapter);
rx_qs_destroy:
be_rx_queues_destroy(adapter);
tx_qs_destroy:
@@ -2606,10 +2632,14 @@ static void be_netdev_init(struct net_device *netdev)
struct be_rx_obj *rxo;
int i;
- netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
- NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
- NETIF_F_GRO | NETIF_F_TSO6;
+ netdev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
+ NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM |
+ NETIF_F_HW_VLAN_TX;
+ if (be_multi_rxq(adapter))
+ netdev->hw_features |= NETIF_F_RXHASH;
+
+ netdev->features |= netdev->hw_features |
+ NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER;
netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
@@ -2619,8 +2649,6 @@ static void be_netdev_init(struct net_device *netdev)
netdev->flags |= IFF_MULTICAST;
- adapter->rx_csum = true;
-
/* Default settings for Rx and Tx flow control */
adapter->rx_fc = true;
adapter->tx_fc = true;
@@ -2814,6 +2842,7 @@ static void __devexit be_remove(struct pci_dev *pdev)
be_ctrl_cleanup(adapter);
+ kfree(adapter->vf_cfg);
be_sriov_disable(adapter);
be_msix_disable(adapter);
@@ -2998,16 +3027,23 @@ static int __devinit be_probe(struct pci_dev *pdev,
}
be_sriov_enable(adapter);
+ if (adapter->sriov_enabled) {
+ adapter->vf_cfg = kcalloc(num_vfs,
+ sizeof(struct be_vf_cfg), GFP_KERNEL);
+
+ if (!adapter->vf_cfg)
+ goto free_netdev;
+ }
status = be_ctrl_init(adapter);
if (status)
- goto free_netdev;
+ goto free_vf_cfg;
if (lancer_chip(adapter)) {
status = lancer_test_and_set_rdy_state(adapter);
if (status) {
dev_err(&pdev->dev, "Adapter in non recoverable error\n");
- goto free_netdev;
+ goto ctrl_clean;
}
}
@@ -3050,9 +3086,22 @@ static int __devinit be_probe(struct pci_dev *pdev,
netif_carrier_off(netdev);
if (be_physfn(adapter) && adapter->sriov_enabled) {
+ u8 mac_speed;
+ bool link_up;
+ u16 vf, lnk_speed;
+
status = be_vf_eth_addr_config(adapter);
if (status)
goto unreg_netdev;
+
+ for (vf = 0; vf < num_vfs; vf++) {
+ status = be_cmd_link_status_query(adapter, &link_up,
+ &mac_speed, &lnk_speed, vf + 1);
+ if (!status)
+ adapter->vf_cfg[vf].vf_tx_rate = lnk_speed * 10;
+ else
+ goto unreg_netdev;
+ }
}
dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num);
@@ -3069,6 +3118,8 @@ stats_clean:
be_stats_cleanup(adapter);
ctrl_clean:
be_ctrl_cleanup(adapter);
+free_vf_cfg:
+ kfree(adapter->vf_cfg);
free_netdev:
be_sriov_disable(adapter);
free_netdev(netdev);
@@ -3153,16 +3204,15 @@ static void be_shutdown(struct pci_dev *pdev)
if (!adapter)
return;
- if (netif_running(adapter->netdev))
- cancel_delayed_work_sync(&adapter->work);
+ cancel_delayed_work_sync(&adapter->work);
netif_device_detach(adapter->netdev);
- be_cmd_reset_function(adapter);
-
if (adapter->wol)
be_setup_wol(adapter, true);
+ be_cmd_reset_function(adapter);
+
pci_disable_device(pdev);
}
@@ -3274,13 +3324,6 @@ static int __init be_init_module(void)
rx_frag_size = 2048;
}
- if (num_vfs > 32) {
- printk(KERN_WARNING DRV_NAME
- " : Module param num_vfs must not be greater than 32."
- "Using 32\n");
- num_vfs = 32;
- }
-
return pci_register_driver(&be_driver);
}
module_init(be_init_module);