aboutsummaryrefslogtreecommitdiffstats
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.c91
-rw-r--r--drivers/net/benet/be_cmds.h48
-rw-r--r--drivers/net/benet/be_ethtool.c58
-rw-r--r--drivers/net/benet/be_hw.h12
-rw-r--r--drivers/net/benet/be_main.c376
6 files changed, 515 insertions, 101 deletions
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index b46be490cd2a..99197bd54da5 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -33,7 +33,7 @@
#include "be_hw.h"
-#define DRV_VER "2.102.147u"
+#define DRV_VER "2.103.175u"
#define DRV_NAME "be2net"
#define BE_NAME "ServerEngines BladeEngine2 10Gbps NIC"
#define BE3_NAME "ServerEngines BladeEngine3 10Gbps NIC"
@@ -220,7 +220,16 @@ struct be_rx_obj {
struct be_rx_page_info page_info_tbl[RX_Q_LEN];
};
+struct be_vf_cfg {
+ unsigned char vf_mac_addr[ETH_ALEN];
+ u32 vf_if_handle;
+ u32 vf_pmac_id;
+ u16 vf_vlan_tag;
+ u32 vf_tx_rate;
+};
+
#define BE_NUM_MSIX_VECTORS 2 /* 1 each for Tx and Rx */
+#define BE_INVALID_PMAC_ID 0xffffffff
struct be_adapter {
struct pci_dev *pdev;
struct net_device *netdev;
@@ -276,23 +285,26 @@ struct be_adapter {
u32 port_num;
bool promiscuous;
bool wol;
- u32 cap;
+ u32 function_mode;
u32 rx_fc; /* Rx flow control */
u32 tx_fc; /* Tx flow control */
+ bool ue_detected;
+ bool stats_ioctl_sent;
int link_speed;
u8 port_type;
u8 transceiver;
+ u8 autoneg;
u8 generation; /* BladeEngine ASIC generation */
u32 flash_status;
struct completion flash_compl;
bool sriov_enabled;
- u32 vf_if_handle[BE_MAX_VF];
- u32 vf_pmac_id[BE_MAX_VF];
+ struct be_vf_cfg vf_cfg[BE_MAX_VF];
u8 base_eq_id;
+ u8 is_virtfn;
};
-#define be_physfn(adapter) (!adapter->pdev->is_virtfn)
+#define be_physfn(adapter) (!adapter->is_virtfn)
/* BladeEngine Generation numbers */
#define BE_GEN2 2
@@ -392,6 +404,15 @@ static inline u8 is_udp_pkt(struct sk_buff *skb)
return val;
}
+static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
+{
+ u8 data;
+
+ pci_write_config_byte(adapter->pdev, 0xFE, 0xAA);
+ pci_read_config_byte(adapter->pdev, 0xFE, &data);
+ adapter->is_virtfn = (data != 0xAA);
+}
+
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 b9ad799c719f..3d305494a606 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -25,6 +25,8 @@ static void be_mcc_notify(struct be_adapter *adapter)
val |= mccq->id & DB_MCCQ_RING_ID_MASK;
val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT;
+
+ wmb();
iowrite32(val, adapter->db + DB_MCCQ_OFFSET);
}
@@ -73,8 +75,10 @@ static int be_mcc_compl_process(struct be_adapter *adapter,
be_dws_le_to_cpu(&resp->hw_stats,
sizeof(resp->hw_stats));
netdev_stats_update(adapter);
+ adapter->stats_ioctl_sent = false;
}
- } else if (compl_status != MCC_STATUS_NOT_SUPPORTED) {
+ } else if ((compl_status != MCC_STATUS_NOT_SUPPORTED) &&
+ (compl->tag0 != OPCODE_COMMON_NTWK_MAC_QUERY)) {
extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
CQE_STATUS_EXTD_MASK;
dev_warn(&adapter->pdev->dev,
@@ -186,7 +190,7 @@ static int be_mcc_notify_wait(struct be_adapter *adapter)
static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
{
- int cnt = 0, wait = 5;
+ int msecs = 0;
u32 ready;
do {
@@ -201,15 +205,15 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db)
if (ready)
break;
- if (cnt > 4000000) {
+ if (msecs > 4000) {
dev_err(&adapter->pdev->dev, "mbox poll timed out\n");
+ be_dump_ue(adapter);
return -1;
}
- if (cnt > 50)
- wait = 200;
- cnt += wait;
- udelay(wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(msecs_to_jiffies(1));
+ msecs++;
} while (true);
return 0;
@@ -948,6 +952,7 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd)
sge->len = cpu_to_le32(nonemb_cmd->size);
be_mcc_notify(adapter);
+ adapter->stats_ioctl_sent = true;
err:
spin_unlock_bh(&adapter->mcc_lock);
@@ -1256,7 +1261,7 @@ err:
}
/* Uses mbox */
-int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *cap)
+int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *mode)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_query_fw_cfg *req;
@@ -1277,7 +1282,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, u32 *cap)
if (!status) {
struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb);
*port_num = le32_to_cpu(resp->phys_port);
- *cap = le32_to_cpu(resp->function_cap);
+ *mode = le32_to_cpu(resp->function_mode);
}
spin_unlock(&adapter->mbox_lock);
@@ -1694,3 +1699,71 @@ int be_cmd_get_seeprom_data(struct be_adapter *adapter,
spin_unlock_bh(&adapter->mcc_lock);
return status;
}
+
+int be_cmd_get_phy_info(struct be_adapter *adapter, struct be_dma_mem *cmd)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_get_phy_info *req;
+ struct be_sge *sge;
+ int status;
+
+ spin_lock_bh(&adapter->mcc_lock);
+
+ wrb = wrb_from_mccq(adapter);
+ if (!wrb) {
+ status = -EBUSY;
+ goto err;
+ }
+
+ req = cmd->va;
+ sge = nonembedded_sgl(wrb);
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1,
+ OPCODE_COMMON_GET_PHY_DETAILS);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_PHY_DETAILS,
+ sizeof(*req));
+
+ sge->pa_hi = cpu_to_le32(upper_32_bits(cmd->dma));
+ sge->pa_lo = cpu_to_le32(cmd->dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(cmd->size);
+
+ status = be_mcc_notify_wait(adapter);
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
+
+int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain)
+{
+ struct be_mcc_wrb *wrb;
+ struct be_cmd_req_set_qos *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_SET_QOS);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_SET_QOS, sizeof(*req));
+
+ req->hdr.domain = domain;
+ req->valid_bits = BE_QOS_BITS_NIC;
+ req->max_bps_nic = bps;
+
+ status = be_mcc_notify_wait(adapter);
+
+err:
+ spin_unlock_bh(&adapter->mcc_lock);
+ return status;
+}
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index 763dc199e337..bdc10a28cfda 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -124,6 +124,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_CQ_CREATE 12
#define OPCODE_COMMON_EQ_CREATE 13
#define OPCODE_COMMON_MCC_CREATE 21
+#define OPCODE_COMMON_SET_QOS 28
#define OPCODE_COMMON_SEEPROM_READ 30
#define OPCODE_COMMON_NTWK_RX_FILTER 34
#define OPCODE_COMMON_GET_FW_VERSION 35
@@ -144,6 +145,7 @@ struct be_mcc_mailbox {
#define OPCODE_COMMON_ENABLE_DISABLE_BEACON 69
#define OPCODE_COMMON_GET_BEACON_STATE 70
#define OPCODE_COMMON_READ_TRANSRECV_DATA 73
+#define OPCODE_COMMON_GET_PHY_DETAILS 102
#define OPCODE_ETH_ACPI_CONFIG 2
#define OPCODE_ETH_PROMISCUOUS 3
@@ -747,7 +749,7 @@ struct be_cmd_resp_query_fw_cfg {
u32 be_config_number;
u32 asic_revision;
u32 phys_port;
- u32 function_cap;
+ u32 function_mode;
u32 rsvd[26];
};
@@ -869,6 +871,46 @@ struct be_cmd_resp_seeprom_read {
u8 seeprom_data[BE_READ_SEEPROM_LEN];
};
+enum {
+ PHY_TYPE_CX4_10GB = 0,
+ PHY_TYPE_XFP_10GB,
+ PHY_TYPE_SFP_1GB,
+ PHY_TYPE_SFP_PLUS_10GB,
+ PHY_TYPE_KR_10GB,
+ PHY_TYPE_KX4_10GB,
+ PHY_TYPE_BASET_10GB,
+ PHY_TYPE_BASET_1GB,
+ PHY_TYPE_DISABLED = 255
+};
+
+struct be_cmd_req_get_phy_info {
+ struct be_cmd_req_hdr hdr;
+ u8 rsvd0[24];
+};
+struct be_cmd_resp_get_phy_info {
+ struct be_cmd_req_hdr hdr;
+ u16 phy_type;
+ u16 interface_type;
+ u32 misc_params;
+ u32 future_use[4];
+};
+
+/*********************** Set QOS ***********************/
+
+#define BE_QOS_BITS_NIC 1
+
+struct be_cmd_req_set_qos {
+ struct be_cmd_req_hdr hdr;
+ u32 valid_bits;
+ u32 max_bps_nic;
+ u32 rsvd[7];
+};
+
+struct be_cmd_resp_set_qos {
+ struct be_cmd_resp_hdr hdr;
+ u32 rsvd;
+};
+
extern int be_pci_fnum_get(struct be_adapter *adapter);
extern int be_cmd_POST(struct be_adapter *adapter);
extern int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr,
@@ -947,4 +989,8 @@ extern int be_cmd_get_seeprom_data(struct be_adapter *adapter,
struct be_dma_mem *nonemb_cmd);
extern int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num,
u8 loopback_type, u8 enable);
+extern int be_cmd_get_phy_info(struct be_adapter *adapter,
+ struct be_dma_mem *cmd);
+extern int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain);
+extern void be_dump_ue(struct be_adapter *adapter);
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index 200e98515909..cd16243c7c36 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -314,15 +314,19 @@ static int be_get_sset_count(struct net_device *netdev, int stringset)
static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
struct be_adapter *adapter = netdev_priv(netdev);
- u8 mac_speed = 0, connector = 0;
+ struct be_dma_mem phy_cmd;
+ struct be_cmd_resp_get_phy_info *resp;
+ u8 mac_speed = 0;
u16 link_speed = 0;
bool link_up = false;
int status;
+ u16 intf_type;
- if (adapter->link_speed < 0) {
+ if ((adapter->link_speed < 0) || (!(netdev->flags & IFF_UP))) {
status = be_cmd_link_status_query(adapter, &link_up,
&mac_speed, &link_speed);
+ be_link_status_update(adapter, link_up);
/* link_speed is in units of 10 Mbps */
if (link_speed) {
ecmd->speed = link_speed*10;
@@ -337,40 +341,57 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
}
}
- status = be_cmd_read_port_type(adapter, adapter->port_num,
- &connector);
+ phy_cmd.size = sizeof(struct be_cmd_req_get_phy_info);
+ phy_cmd.va = pci_alloc_consistent(adapter->pdev, phy_cmd.size,
+ &phy_cmd.dma);
+ if (!phy_cmd.va) {
+ dev_err(&adapter->pdev->dev, "Memory alloc failure\n");
+ return -ENOMEM;
+ }
+ status = be_cmd_get_phy_info(adapter, &phy_cmd);
if (!status) {
- switch (connector) {
- case 7:
+ resp = (struct be_cmd_resp_get_phy_info *) phy_cmd.va;
+ intf_type = le16_to_cpu(resp->interface_type);
+
+ switch (intf_type) {
+ case PHY_TYPE_XFP_10GB:
+ case PHY_TYPE_SFP_1GB:
+ case PHY_TYPE_SFP_PLUS_10GB:
ecmd->port = PORT_FIBRE;
- ecmd->transceiver = XCVR_EXTERNAL;
- break;
- case 0:
- ecmd->port = PORT_TP;
- ecmd->transceiver = XCVR_EXTERNAL;
break;
default:
ecmd->port = PORT_TP;
- ecmd->transceiver = XCVR_INTERNAL;
break;
}
- } else {
- ecmd->port = PORT_AUI;
+
+ switch (intf_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 = ecmd->speed;
adapter->port_type = ecmd->port;
adapter->transceiver = ecmd->transceiver;
+ adapter->autoneg = ecmd->autoneg;
+ pci_free_consistent(adapter->pdev, phy_cmd.size,
+ phy_cmd.va, phy_cmd.dma);
} else {
ecmd->speed = adapter->link_speed;
ecmd->port = adapter->port_type;
ecmd->transceiver = adapter->transceiver;
+ ecmd->autoneg = adapter->autoneg;
}
ecmd->duplex = DUPLEX_FULL;
- ecmd->autoneg = AUTONEG_DISABLE;
ecmd->phy_address = adapter->port_num;
switch (ecmd->port) {
case PORT_FIBRE:
@@ -384,6 +405,13 @@ static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
break;
}
+ if (ecmd->autoneg) {
+ ecmd->supported |= SUPPORTED_1000baseT_Full;
+ ecmd->supported |= SUPPORTED_Autoneg;
+ ecmd->advertising |= (ADVERTISED_10000baseT_Full |
+ ADVERTISED_1000baseT_Full);
+ }
+
return 0;
}
diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h
index 063026de4957..6c8f9bb8bfe6 100644
--- a/drivers/net/benet/be_hw.h
+++ b/drivers/net/benet/be_hw.h
@@ -56,6 +56,16 @@
#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
+
/********* ISR0 Register offset **********/
#define CEV_ISR0_OFFSET 0xC18
#define CEV_ISR_SIZE 4
@@ -192,7 +202,7 @@ struct amap_eth_hdr_wrb {
u8 event;
u8 crc;
u8 forward;
- u8 ipsec;
+ u8 lso6;
u8 mgmt;
u8 ipcs;
u8 udpcs;
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 54b14272f333..74e146f470c6 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -40,6 +40,76 @@ static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
{ 0 }
};
MODULE_DEVICE_TABLE(pci, be_dev_ids);
+/* UE Status Low CSR */
+static char *ue_status_low_desc[] = {
+ "CEV",
+ "CTX",
+ "DBUF",
+ "ERX",
+ "Host",
+ "MPU",
+ "NDMA",
+ "PTC ",
+ "RDMA ",
+ "RXF ",
+ "RXIPS ",
+ "RXULP0 ",
+ "RXULP1 ",
+ "RXULP2 ",
+ "TIM ",
+ "TPOST ",
+ "TPRE ",
+ "TXIPS ",
+ "TXULP0 ",
+ "TXULP1 ",
+ "UC ",
+ "WDMA ",
+ "TXULP2 ",
+ "HOST1 ",
+ "P0_OB_LINK ",
+ "P1_OB_LINK ",
+ "HOST_GPIO ",
+ "MBOX ",
+ "AXGMAC0",
+ "AXGMAC1",
+ "JTAG",
+ "MPU_INTPEND"
+};
+/* UE Status High CSR */
+static char *ue_status_hi_desc[] = {
+ "LPCMEMHOST",
+ "MGMT_MAC",
+ "PCS0ONLINE",
+ "MPU_IRAM",
+ "PCS1ONLINE",
+ "PCTL0",
+ "PCTL1",
+ "PMEM",
+ "RR",
+ "TXPB",
+ "RXPP",
+ "XAUI",
+ "TXP",
+ "ARM",
+ "IPC",
+ "HOST2",
+ "HOST3",
+ "HOST4",
+ "HOST5",
+ "HOST6",
+ "HOST7",
+ "HOST8",
+ "HOST9",
+ "NETC"
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown",
+ "Unknown"
+};
static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
{
@@ -89,6 +159,8 @@ static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
u32 val = 0;
val |= qid & DB_RQ_RING_ID_MASK;
val |= posted << DB_RQ_NUM_POSTED_SHIFT;
+
+ wmb();
iowrite32(val, adapter->db + DB_RQ_OFFSET);
}
@@ -97,6 +169,8 @@ static void be_txq_notify(struct be_adapter *adapter, u16 qid, u16 posted)
u32 val = 0;
val |= qid & DB_TXULP_RING_ID_MASK;
val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT;
+
+ wmb();
iowrite32(val, adapter->db + DB_TXULP1_OFFSET);
}
@@ -373,10 +447,12 @@ static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1);
- if (skb_shinfo(skb)->gso_segs > 1 && skb_shinfo(skb)->gso_size) {
+ if (skb_is_gso(skb)) {
AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1);
AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss,
hdr, skb_shinfo(skb)->gso_size);
+ if (skb_is_gso_v6(skb))
+ AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso6, hdr, 1);
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
if (is_tcp_pkt(skb))
AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1);
@@ -546,11 +622,18 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu)
* A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE.
* If the user configures more, place BE in vlan promiscuous mode.
*/
-static int be_vid_config(struct be_adapter *adapter)
+static int be_vid_config(struct be_adapter *adapter, bool vf, u32 vf_num)
{
u16 vtag[BE_NUM_VLANS_SUPPORTED];
u16 ntags = 0, i;
int status = 0;
+ u32 if_handle;
+
+ if (vf) {
+ if_handle = adapter->vf_cfg[vf_num].vf_if_handle;
+ vtag[0] = cpu_to_le16(adapter->vf_cfg[vf_num].vf_vlan_tag);
+ status = be_cmd_vlan_config(adapter, if_handle, vtag, 1, 1, 0);
+ }
if (adapter->vlans_added <= adapter->max_vlans) {
/* Construct VLAN Table to give to HW */
@@ -566,6 +649,7 @@ static int be_vid_config(struct be_adapter *adapter)
status = be_cmd_vlan_config(adapter, adapter->if_handle,
NULL, 0, 1, 1);
}
+
return status;
}
@@ -586,27 +670,28 @@ static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
{
struct be_adapter *adapter = netdev_priv(netdev);
+ adapter->vlans_added++;
if (!be_physfn(adapter))
return;
adapter->vlan_tag[vid] = 1;
- adapter->vlans_added++;
if (adapter->vlans_added <= (adapter->max_vlans + 1))
- be_vid_config(adapter);
+ be_vid_config(adapter, false, 0);
}
static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
{
struct be_adapter *adapter = netdev_priv(netdev);
+ adapter->vlans_added--;
+ vlan_group_set_device(adapter->vlan_grp, vid, NULL);
+
if (!be_physfn(adapter))
return;
adapter->vlan_tag[vid] = 0;
- vlan_group_set_device(adapter->vlan_grp, vid, NULL);
- adapter->vlans_added--;
if (adapter->vlans_added <= adapter->max_vlans)
- be_vid_config(adapter);
+ be_vid_config(adapter, false, 0);
}
static void be_set_multicast_list(struct net_device *netdev)
@@ -650,14 +735,93 @@ static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
if (!is_valid_ether_addr(mac) || (vf >= num_vfs))
return -EINVAL;
- status = be_cmd_pmac_del(adapter, adapter->vf_if_handle[vf],
- adapter->vf_pmac_id[vf]);
+ if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
+ status = be_cmd_pmac_del(adapter,
+ adapter->vf_cfg[vf].vf_if_handle,
+ adapter->vf_cfg[vf].vf_pmac_id);
- status = be_cmd_pmac_add(adapter, mac, adapter->vf_if_handle[vf],
- &adapter->vf_pmac_id[vf]);
- if (!status)
+ status = be_cmd_pmac_add(adapter, mac,
+ adapter->vf_cfg[vf].vf_if_handle,
+ &adapter->vf_cfg[vf].vf_pmac_id);
+
+ if (status)
dev_err(&adapter->pdev->dev, "MAC %pM set on VF %d Failed\n",
mac, vf);
+ else
+ memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
+
+ return status;
+}
+
+static int be_get_vf_config(struct net_device *netdev, int vf,
+ struct ifla_vf_info *vi)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+
+ if (!adapter->sriov_enabled)
+ return -EPERM;
+
+ if (vf >= num_vfs)
+ return -EINVAL;
+
+ vi->vf = vf;
+ vi->tx_rate = adapter->vf_cfg[vf].vf_tx_rate;
+ vi->vlan = adapter->vf_cfg[vf].vf_vlan_tag;
+ vi->qos = 0;
+ memcpy(&vi->mac, adapter->vf_cfg[vf].vf_mac_addr, ETH_ALEN);
+
+ return 0;
+}
+
+static int be_set_vf_vlan(struct net_device *netdev,
+ int vf, u16 vlan, u8 qos)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ int status = 0;
+
+ if (!adapter->sriov_enabled)
+ return -EPERM;
+
+ if ((vf >= num_vfs) || (vlan > 4095))
+ return -EINVAL;
+
+ if (vlan) {
+ adapter->vf_cfg[vf].vf_vlan_tag = vlan;
+ adapter->vlans_added++;
+ } else {
+ adapter->vf_cfg[vf].vf_vlan_tag = 0;
+ adapter->vlans_added--;
+ }
+
+ status = be_vid_config(adapter, true, vf);
+
+ if (status)
+ dev_info(&adapter->pdev->dev,
+ "VLAN %d config on VF %d failed\n", vlan, vf);
+ return status;
+}
+
+static int be_set_vf_tx_rate(struct net_device *netdev,
+ int vf, int rate)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ int status = 0;
+
+ if (!adapter->sriov_enabled)
+ return -EPERM;
+
+ if ((vf >= num_vfs) || (rate < 0))
+ return -EINVAL;
+
+ if (rate > 10000)
+ rate = 10000;
+
+ adapter->vf_cfg[vf].vf_tx_rate = rate;
+ status = be_cmd_set_qos(adapter, rate / 10, vf);
+
+ if (status)
+ dev_info(&adapter->pdev->dev,
+ "tx rate %d on VF %d failed\n", rate, vf);
return status;
}
@@ -869,7 +1033,7 @@ static void be_rx_compl_process(struct be_adapter *adapter,
/* vlanf could be wrongly set in some cards.
* ignore if vtm is not set */
- if ((adapter->cap & 0x400) && !vtm)
+ if ((adapter->function_mode & 0x400) && !vtm)
vlanf = 0;
if (unlikely(vlanf)) {
@@ -909,7 +1073,7 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
/* vlanf could be wrongly set in some cards.
* ignore if vtm is not set */
- if ((adapter->cap & 0x400) && !vtm)
+ if ((adapter->function_mode & 0x400) && !vtm)
vlanf = 0;
skb = napi_get_frags(&eq_obj->napi);
@@ -971,6 +1135,7 @@ static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter)
if (rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] == 0)
return NULL;
+ rmb();
be_dws_le_to_cpu(rxcp, sizeof(*rxcp));
queue_tail_inc(&adapter->rx_obj.cq);
@@ -1064,6 +1229,7 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0)
return NULL;
+ rmb();
be_dws_le_to_cpu(txcp, sizeof(*txcp));
txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0;
@@ -1111,6 +1277,7 @@ static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj)
if (!eqe->evt)
return NULL;
+ rmb();
eqe->evt = le32_to_cpu(eqe->evt);
queue_tail_inc(&eq_obj->q);
return eqe;
@@ -1576,12 +1743,66 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
return 1;
}
+static inline bool be_detect_ue(struct be_adapter *adapter)
+{
+ u32 online0 = 0, online1 = 0;
+
+ pci_read_config_dword(adapter->pdev, PCICFG_ONLINE0, &online0);
+
+ pci_read_config_dword(adapter->pdev, PCICFG_ONLINE1, &online1);
+
+ if (!online0 || !online1) {
+ adapter->ue_detected = true;
+ dev_err(&adapter->pdev->dev,
+ "UE Detected!! online0=%d online1=%d\n",
+ online0, online1);
+ return true;
+ }
+
+ return false;
+}
+
+void be_dump_ue(struct be_adapter *adapter)
+{
+ u32 ue_status_lo, ue_status_hi, ue_status_lo_mask, ue_status_hi_mask;
+ u32 i;
+
+ pci_read_config_dword(adapter->pdev,
+ PCICFG_UE_STATUS_LOW, &ue_status_lo);
+ pci_read_config_dword(adapter->pdev,
+ PCICFG_UE_STATUS_HIGH, &ue_status_hi);
+ pci_read_config_dword(adapter->pdev,
+ PCICFG_UE_STATUS_LOW_MASK, &ue_status_lo_mask);
+ pci_read_config_dword(adapter->pdev,
+ PCICFG_UE_STATUS_HI_MASK, &ue_status_hi_mask);
+
+ ue_status_lo = (ue_status_lo & (~ue_status_lo_mask));
+ ue_status_hi = (ue_status_hi & (~ue_status_hi_mask));
+
+ if (ue_status_lo) {
+ for (i = 0; ue_status_lo; ue_status_lo >>= 1, i++) {
+ if (ue_status_lo & 1)
+ dev_err(&adapter->pdev->dev,
+ "UE: %s bit set\n", ue_status_low_desc[i]);
+ }
+ }
+ if (ue_status_hi) {
+ for (i = 0; ue_status_hi; ue_status_hi >>= 1, i++) {
+ if (ue_status_hi & 1)
+ dev_err(&adapter->pdev->dev,
+ "UE: %s bit set\n", ue_status_hi_desc[i]);
+ }
+ }
+
+}
+
static void be_worker(struct work_struct *work)
{
struct be_adapter *adapter =
container_of(work, struct be_adapter, work.work);
- be_cmd_get_stats(adapter, &adapter->stats.cmd);
+ if (!adapter->stats_ioctl_sent)
+ be_cmd_get_stats(adapter, &adapter->stats.cmd);
/* Set EQ delay */
be_rx_eqd_update(adapter);
@@ -1593,6 +1814,10 @@ static void be_worker(struct work_struct *work)
adapter->rx_post_starved = false;
be_post_rx_frags(adapter);
}
+ if (!adapter->ue_detected) {
+ if (be_detect_ue(adapter))
+ be_dump_ue(adapter);
+ }
schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
}
@@ -1620,9 +1845,11 @@ static void be_msix_enable(struct be_adapter *adapter)
static void be_sriov_enable(struct be_adapter *adapter)
{
+ be_check_sriov_fn_type(adapter);
#ifdef CONFIG_PCI_IOV
- int status;
if (be_physfn(adapter) && num_vfs) {
+ int status;
+
status = pci_enable_sriov(adapter->pdev, num_vfs);
adapter->sriov_enabled = status ? false : true;
}
@@ -1735,6 +1962,44 @@ done:
adapter->isr_registered = false;
}
+static int be_close(struct net_device *netdev)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
+ struct be_eq_obj *rx_eq = &adapter->rx_eq;
+ struct be_eq_obj *tx_eq = &adapter->tx_eq;
+ int vec;
+
+ cancel_delayed_work_sync(&adapter->work);
+
+ be_async_mcc_disable(adapter);
+
+ netif_stop_queue(netdev);
+ netif_carrier_off(netdev);
+ adapter->link_up = false;
+
+ be_intr_set(adapter, false);
+
+ if (adapter->msix_enabled) {
+ vec = be_msix_vec_get(adapter, tx_eq->q.id);
+ synchronize_irq(vec);
+ vec = be_msix_vec_get(adapter, rx_eq->q.id);
+ synchronize_irq(vec);
+ } else {
+ synchronize_irq(netdev->irq);
+ }
+ be_irq_unregister(adapter);
+
+ napi_disable(&rx_eq->napi);
+ napi_disable(&tx_eq->napi);
+
+ /* Wait for all pending tx completions to arrive so that
+ * all tx skbs are freed.
+ */
+ be_tx_compl_clean(adapter);
+
+ return 0;
+}
+
static int be_open(struct net_device *netdev)
{
struct be_adapter *adapter = netdev_priv(netdev);
@@ -1765,27 +2030,29 @@ static int be_open(struct net_device *netdev)
/* Now that interrupts are on we can process async mcc */
be_async_mcc_enable(adapter);
+ schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
+
status = be_cmd_link_status_query(adapter, &link_up, &mac_speed,
&link_speed);
if (status)
- goto ret_sts;
+ goto err;
be_link_status_update(adapter, link_up);
- if (be_physfn(adapter))
- status = be_vid_config(adapter);
- if (status)
- goto ret_sts;
-
if (be_physfn(adapter)) {
+ status = be_vid_config(adapter, false, 0);
+ if (status)
+ goto err;
+
status = be_cmd_set_flow_control(adapter,
adapter->tx_fc, adapter->rx_fc);
if (status)
- goto ret_sts;
+ goto err;
}
- schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
-ret_sts:
- return status;
+ return 0;
+err:
+ be_close(adapter->netdev);
+ return -EIO;
}
static int be_setup_wol(struct be_adapter *adapter, bool enable)
@@ -1853,13 +2120,15 @@ static int be_setup(struct be_adapter *adapter)
cap_flags = en_flags = BE_IF_FLAGS_UNTAGGED
| BE_IF_FLAGS_BROADCAST;
status = be_cmd_if_create(adapter, cap_flags, en_flags,
- mac, true, &adapter->vf_if_handle[vf],
+ mac, true,
+ &adapter->vf_cfg[vf].vf_if_handle,
NULL, vf+1);
if (status) {
dev_err(&adapter->pdev->dev,
"Interface Create failed for VF %d\n", vf);
goto if_destroy;
}
+ adapter->vf_cfg[vf].vf_pmac_id = BE_INVALID_PMAC_ID;
vf++;
}
} else if (!be_physfn(adapter)) {
@@ -1893,8 +2162,9 @@ tx_qs_destroy:
be_tx_queues_destroy(adapter);
if_destroy:
for (vf = 0; vf < num_vfs; vf++)
- if (adapter->vf_if_handle[vf])
- be_cmd_if_destroy(adapter, adapter->vf_if_handle[vf]);
+ if (adapter->vf_cfg[vf].vf_if_handle)
+ be_cmd_if_destroy(adapter,
+ adapter->vf_cfg[vf].vf_if_handle);
be_cmd_if_destroy(adapter, adapter->if_handle);
do_none:
return status;
@@ -1913,43 +2183,6 @@ static int be_clear(struct be_adapter *adapter)
return 0;
}
-static int be_close(struct net_device *netdev)
-{
- struct be_adapter *adapter = netdev_priv(netdev);
- struct be_eq_obj *rx_eq = &adapter->rx_eq;
- struct be_eq_obj *tx_eq = &adapter->tx_eq;
- int vec;
-
- cancel_delayed_work_sync(&adapter->work);
-
- be_async_mcc_disable(adapter);
-
- netif_stop_queue(netdev);
- netif_carrier_off(netdev);
- adapter->link_up = false;
-
- be_intr_set(adapter, false);
-
- if (adapter->msix_enabled) {
- vec = be_msix_vec_get(adapter, tx_eq->q.id);
- synchronize_irq(vec);
- vec = be_msix_vec_get(adapter, rx_eq->q.id);
- synchronize_irq(vec);
- } else {
- synchronize_irq(netdev->irq);
- }
- be_irq_unregister(adapter);
-
- napi_disable(&rx_eq->napi);
- napi_disable(&tx_eq->napi);
-
- /* Wait for all pending tx completions to arrive so that
- * all tx skbs are freed.
- */
- be_tx_compl_clean(adapter);
-
- return 0;
-}
#define FW_FILE_HDR_SIGN "ServerEngines Corp. "
char flash_cookie[2][16] = {"*** SE FLAS",
@@ -2174,7 +2407,10 @@ static struct net_device_ops be_netdev_ops = {
.ndo_vlan_rx_register = be_vlan_register,
.ndo_vlan_rx_add_vid = be_vlan_add_vid,
.ndo_vlan_rx_kill_vid = be_vlan_rem_vid,
- .ndo_set_vf_mac = be_set_vf_mac
+ .ndo_set_vf_mac = be_set_vf_mac,
+ .ndo_set_vf_vlan = be_set_vf_vlan,
+ .ndo_set_vf_tx_rate = be_set_vf_tx_rate,
+ .ndo_get_vf_config = be_get_vf_config
};
static void be_netdev_init(struct net_device *netdev)
@@ -2183,7 +2419,7 @@ static void be_netdev_init(struct net_device *netdev)
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_HW_CSUM |
- NETIF_F_GRO;
+ NETIF_F_GRO | NETIF_F_TSO6;
netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_CSUM;
@@ -2393,7 +2629,7 @@ static int be_get_config(struct be_adapter *adapter)
return status;
status = be_cmd_query_fw_cfg(adapter,
- &adapter->port_num, &adapter->cap);
+ &adapter->port_num, &adapter->function_mode);
if (status)
return status;
@@ -2413,7 +2649,7 @@ static int be_get_config(struct be_adapter *adapter)
memcpy(adapter->netdev->perm_addr, mac, ETH_ALEN);
}
- if (adapter->cap & 0x400)
+ if (adapter->function_mode & 0x400)
adapter->max_vlans = BE_NUM_VLANS_SUPPORTED/4;
else
adapter->max_vlans = BE_NUM_VLANS_SUPPORTED;