#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:
- case OC_DEVICE_ID6:
- 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 */
ASSIGNED = 1
};
-#define BE_FLAGS_LINK_STATUS_INIT 1
-#define BE_FLAGS_SRIOV_ENABLED (1 << 2)
-#define BE_FLAGS_WORKER_SCHEDULED (1 << 3)
-#define BE_FLAGS_VLAN_PROMISC (1 << 4)
-#define BE_FLAGS_MCAST_PROMISC (1 << 5)
-#define BE_FLAGS_NAPI_ENABLED (1 << 9)
-#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD (1 << 11)
-#define BE_FLAGS_VXLAN_OFFLOADS (1 << 12)
-#define BE_FLAGS_SETUP_DONE (1 << 13)
+#define BE_FLAGS_LINK_STATUS_INIT BIT(1)
+#define BE_FLAGS_SRIOV_ENABLED BIT(2)
+#define BE_FLAGS_WORKER_SCHEDULED BIT(3)
+#define BE_FLAGS_NAPI_ENABLED BIT(6)
+#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD BIT(7)
+#define BE_FLAGS_VXLAN_OFFLOADS BIT(8)
+#define BE_FLAGS_SETUP_DONE BIT(9)
+#define BE_FLAGS_EVT_INCOMPATIBLE_SFP BIT(10)
#define BE_UC_PMAC_COUNT 30
#define BE_VF_UC_PMAC_COUNT 2
#define LANCER_DELETE_FW_DUMP 0x2
struct phy_info {
+/* From SFF-8472 spec */
+#define SFP_VENDOR_NAME_LEN 17
u8 transceiver;
u8 autoneg;
u8 fc_autoneg;
u32 advertising;
u32 supported;
u8 cable_type;
+ u8 vendor_name[SFP_VENDOR_NAME_LEN];
+ u8 vendor_pn[SFP_VENDOR_NAME_LEN];
};
struct be_resources {
struct be_drv_stats drv_stats;
struct be_aic_obj aic_obj[MAX_EVT_QS];
- u16 vlans_added;
- unsigned long vids[BITS_TO_LONGS(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 */
/* Ethtool knobs and info */
char fw_ver[FW_VER_LEN];
char fw_on_flash[FW_VER_LEN];
+
+ /* IFACE filtering fields */
int if_handle; /* Used to configure filtering */
+ u32 if_flags; /* Interface filtering flags */
u32 *pmac_id; /* MAC addr handle used by BE card */
+ u32 uc_macs; /* Count of secondary UC MAC programmed */
+ unsigned long vids[BITS_TO_LONGS(VLAN_N_VID)];
+ u16 vlans_added;
+
u32 beacon_state; /* for set_phys_id */
bool eeh_error;
bool hw_error;
u32 port_num;
- bool promiscuous;
+ char port_name;
u8 mc_type;
u32 function_mode;
u32 function_caps;
struct phy_info phy;
u8 wol_cap;
bool wol_en;
- u32 uc_macs; /* Count of secondary UC MAC programmed */
u16 asic_rev;
u16 qnq_vid;
u32 msg_enable;
return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4;
}
-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;
adapter->fw_timeout = false;
}
-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;
- }
-}
-
-static inline int qnq_async_evt_rcvd(struct be_adapter *adapter)
-{
- return adapter->flags & BE_FLAGS_QNQ_ASYNC_EVT_RCVD;
-}
-
-#ifdef CONFIG_NET_RX_BUSY_POLL
-static inline bool be_lock_napi(struct be_eq_obj *eqo)
-{
- bool status = true;
-
- spin_lock(&eqo->lock); /* BH is already disabled */
- if (eqo->state & BE_EQ_LOCKED) {
- WARN_ON(eqo->state & BE_EQ_NAPI);
- eqo->state |= BE_EQ_NAPI_YIELD;
- status = false;
- } else {
- eqo->state = BE_EQ_NAPI;
- }
- spin_unlock(&eqo->lock);
- return status;
-}
-
-static inline void be_unlock_napi(struct be_eq_obj *eqo)
-{
- spin_lock(&eqo->lock); /* BH is already disabled */
-
- WARN_ON(eqo->state & (BE_EQ_POLL | BE_EQ_NAPI_YIELD));
- eqo->state = BE_EQ_IDLE;
-
- spin_unlock(&eqo->lock);
-}
-
-static inline bool be_lock_busy_poll(struct be_eq_obj *eqo)
-{
- bool status = true;
-
- spin_lock_bh(&eqo->lock);
- if (eqo->state & BE_EQ_LOCKED) {
- eqo->state |= BE_EQ_POLL_YIELD;
- status = false;
- } else {
- eqo->state |= BE_EQ_POLL;
- }
- spin_unlock_bh(&eqo->lock);
- return status;
-}
-
-static inline void be_unlock_busy_poll(struct be_eq_obj *eqo)
-{
- spin_lock_bh(&eqo->lock);
-
- WARN_ON(eqo->state & (BE_EQ_NAPI));
- eqo->state = BE_EQ_IDLE;
-
- spin_unlock_bh(&eqo->lock);
-}
-
-static inline void be_enable_busy_poll(struct be_eq_obj *eqo)
-{
- spin_lock_init(&eqo->lock);
- eqo->state = BE_EQ_IDLE;
-}
-
-static inline void be_disable_busy_poll(struct be_eq_obj *eqo)
-{
- local_bh_disable();
-
- /* It's enough to just acquire napi lock on the eqo to stop
- * be_busy_poll() from processing any queueus.
- */
- while (!be_lock_napi(eqo))
- mdelay(1);
-
- local_bh_enable();
-}
-
-#else /* CONFIG_NET_RX_BUSY_POLL */
-
-static inline bool be_lock_napi(struct be_eq_obj *eqo)
-{
- return true;
-}
-
-static inline void be_unlock_napi(struct be_eq_obj *eqo)
-{
-}
-
-static inline bool be_lock_busy_poll(struct be_eq_obj *eqo)
-{
- return false;
-}
-
-static inline void be_unlock_busy_poll(struct be_eq_obj *eqo)
-{
-}
-
-static inline void be_enable_busy_poll(struct be_eq_obj *eqo)
-{
-}
-
-static inline void be_disable_busy_poll(struct be_eq_obj *eqo)
-{
-}
-#endif /* CONFIG_NET_RX_BUSY_POLL */
-
void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped);
void be_link_status_update(struct be_adapter *adapter, u8 link_status);
bool be_is_wol_supported(struct be_adapter *adapter);
bool be_pause_supported(struct be_adapter *adapter);
u32 be_get_fw_log_level(struct be_adapter *adapter);
-
-static inline int fw_major_num(const char *fw_ver)
-{
- int fw_major = 0;
-
- sscanf(fw_ver, "%d.", &fw_major);
-
- return fw_major;
-}
-
int be_update_queues(struct be_adapter *adapter);
int be_poll(struct napi_struct *napi, int budget);
#include "be.h"
#include "be_cmds.h"
+static char *be_port_misconfig_evt_desc[] = {
+ "A valid SFP module detected",
+ "Optics faulted/ incorrectly installed/ not installed.",
+ "Optics of two types installed.",
+ "Incompatible optics.",
+ "Unknown port SFP status"
+};
+
+static char *be_port_misconfig_remedy_desc[] = {
+ "",
+ "Reseat optics. If issue not resolved, replace",
+ "Remove one optic or install matching pair of optics",
+ "Replace with compatible optics for card to function",
+ ""
+};
+
static struct be_cmd_priv_map cmd_priv_map[] = {
{
OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG,
evt->port_link_status & LINK_STATUS_MASK);
}
+static void be_async_port_misconfig_event_process(struct be_adapter *adapter,
+ struct be_mcc_compl *compl)
+{
+ struct be_async_event_misconfig_port *evt =
+ (struct be_async_event_misconfig_port *)compl;
+ u32 sfp_mismatch_evt = le32_to_cpu(evt->event_data_word1);
+ struct device *dev = &adapter->pdev->dev;
+ u8 port_misconfig_evt;
+
+ port_misconfig_evt =
+ ((sfp_mismatch_evt >> (adapter->hba_port_num * 8)) & 0xff);
+
+ /* Log an error message that would allow a user to determine
+ * whether the SFPs have an issue
+ */
+ dev_info(dev, "Port %c: %s %s", adapter->port_name,
+ be_port_misconfig_evt_desc[port_misconfig_evt],
+ be_port_misconfig_remedy_desc[port_misconfig_evt]);
+
+ if (port_misconfig_evt == INCOMPATIBLE_SFP)
+ adapter->flags |= BE_FLAGS_EVT_INCOMPATIBLE_SFP;
+}
+
/* Grp5 CoS Priority evt */
static void be_async_grp5_cos_priority_process(struct be_adapter *adapter,
struct be_mcc_compl *compl)
}
}
+static void be_async_sliport_evt_process(struct be_adapter *adapter,
+ struct be_mcc_compl *cmp)
+{
+ u8 event_type = (cmp->flags >> ASYNC_EVENT_TYPE_SHIFT) &
+ ASYNC_EVENT_TYPE_MASK;
+
+ if (event_type == ASYNC_EVENT_PORT_MISCONFIG)
+ be_async_port_misconfig_event_process(adapter, cmp);
+}
+
static inline bool is_link_state_evt(u32 flags)
{
return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) ==
ASYNC_EVENT_CODE_QNQ;
}
+static inline bool is_sliport_evt(u32 flags)
+{
+ return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) ==
+ ASYNC_EVENT_CODE_SLIPORT;
+}
+
static void be_mcc_event_process(struct be_adapter *adapter,
struct be_mcc_compl *compl)
{
be_async_grp5_evt_process(adapter, compl);
else if (is_dbg_evt(compl->flags))
be_async_dbg_evt_process(adapter, compl);
+ else if (is_sliport_evt(compl->flags))
+ be_async_sliport_evt_process(adapter, compl);
}
static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter)
ctxt, 1);
}
- /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */
- req->async_event_bitmap[0] = cpu_to_le32(0x00000022);
- req->async_event_bitmap[0] |= cpu_to_le32(1 << ASYNC_EVENT_CODE_QNQ);
+ /* Subscribe to Link State, Sliport Event and Group 5 Events
+ * (bits 1, 5 and 17 set)
+ */
+ req->async_event_bitmap[0] =
+ cpu_to_le32(BIT(ASYNC_EVENT_CODE_LINK_STATE) |
+ BIT(ASYNC_EVENT_CODE_GRP_5) |
+ BIT(ASYNC_EVENT_CODE_QNQ) |
+ BIT(ASYNC_EVENT_CODE_SLIPORT));
+
be_dws_cpu_to_le(ctxt, sizeof(req->context));
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
return status;
}
-int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
+static int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
{
struct be_mcc_wrb *wrb;
struct be_dma_mem *mem = &adapter->rx_filter;
wrb, mem);
req->if_id = cpu_to_le32(adapter->if_handle);
- if (flags & IFF_PROMISC) {
- req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS |
- BE_IF_FLAGS_VLAN_PROMISCUOUS |
- BE_IF_FLAGS_MCAST_PROMISCUOUS);
- if (value == ON)
- req->if_flags =
- cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS |
- BE_IF_FLAGS_VLAN_PROMISCUOUS |
- BE_IF_FLAGS_MCAST_PROMISCUOUS);
- } else if (flags & IFF_ALLMULTI) {
- req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS);
- req->if_flags = cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS);
- } else if (flags & BE_FLAGS_VLAN_PROMISC) {
- req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
-
- if (value == ON)
- req->if_flags =
- cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
- } else {
+ req->if_flags_mask = cpu_to_le32(flags);
+ req->if_flags = (value == ON) ? req->if_flags_mask : 0;
+
+ if (flags & BE_IF_FLAGS_MULTICAST) {
struct netdev_hw_addr *ha;
int i = 0;
- req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_MULTICAST);
- req->if_flags = cpu_to_le32(BE_IF_FLAGS_MULTICAST);
-
/* Reset mcast promisc mode if already set by setting mask
* and not setting flags field
*/
memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN);
}
- if ((req->if_flags_mask & cpu_to_le32(be_if_cap_flags(adapter))) !=
- req->if_flags_mask) {
- dev_warn(&adapter->pdev->dev,
- "Cannot set rx filter flags 0x%x\n",
- req->if_flags_mask);
- dev_warn(&adapter->pdev->dev,
- "Interface is capable of 0x%x flags only\n",
- be_if_cap_flags(adapter));
- }
- req->if_flags_mask &= cpu_to_le32(be_if_cap_flags(adapter));
-
status = be_mcc_notify_wait(adapter);
-
err:
spin_unlock_bh(&adapter->mcc_lock);
return status;
}
+int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
+{
+ struct device *dev = &adapter->pdev->dev;
+
+ if ((flags & be_if_cap_flags(adapter)) != flags) {
+ dev_warn(dev, "Cannot set rx filter flags 0x%x\n", flags);
+ dev_warn(dev, "Interface is capable of 0x%x flags only\n",
+ be_if_cap_flags(adapter));
+ }
+ flags &= be_if_cap_flags(adapter);
+
+ return __be_cmd_rx_filter(adapter, flags, value);
+}
+
/* Uses synchrounous mcc */
int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc)
{
return status;
}
+int be_cmd_query_sfp_info(struct be_adapter *adapter)
+{
+ u8 page_data[PAGE_DATA_LEN];
+ int status;
+
+ status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
+ page_data);
+ if (!status) {
+ strlcpy(adapter->phy.vendor_name, page_data +
+ SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1);
+ strlcpy(adapter->phy.vendor_pn,
+ page_data + SFP_VENDOR_PN_OFFSET,
+ SFP_VENDOR_NAME_LEN - 1);
+ }
+
+ return status;
+}
+
int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name)
{
struct lancer_cmd_req_delete_object *req;
}
int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
- u32 flash_type, u32 flash_opcode, u32 buf_size)
+ u32 flash_type, u32 flash_opcode, u32 img_offset,
+ u32 buf_size)
{
struct be_mcc_wrb *wrb;
struct be_cmd_write_flashrom *req;
cmd);
req->params.op_type = cpu_to_le32(flash_type);
+ if (flash_type == OPTYPE_OFFSET_SPECIFIED)
+ req->params.offset = cpu_to_le32(img_offset);
+
req->params.op_code = cpu_to_le32(flash_opcode);
req->params.data_buf_size = cpu_to_le32(buf_size);
}
int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
- u16 optype, int offset)
+ u16 img_optype, u32 img_offset, u32 crc_offset)
{
- struct be_mcc_wrb *wrb;
struct be_cmd_read_flash_crc *req;
+ struct be_mcc_wrb *wrb;
int status;
spin_lock_bh(&adapter->mcc_lock);
OPCODE_COMMON_READ_FLASHROM, sizeof(*req),
wrb, NULL);
- req->params.op_type = cpu_to_le32(optype);
+ req->params.op_type = cpu_to_le32(img_optype);
+ if (img_optype == OPTYPE_OFFSET_SPECIFIED)
+ req->params.offset = cpu_to_le32(img_offset + crc_offset);
+ else
+ req->params.offset = cpu_to_le32(crc_offset);
+
req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT);
- req->params.offset = cpu_to_le32(offset);
req->params.data_buf_size = cpu_to_le32(0x4);
status = be_mcc_notify_wait(adapter);
return status;
}
+static 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;
+ }
+}
+
int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
{
struct be_mcc_wrb *wrb;
return status;
}
-int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name)
+int be_cmd_query_port_name(struct be_adapter *adapter)
{
- struct be_mcc_wrb *wrb;
struct be_cmd_req_get_port_name *req;
+ struct be_mcc_wrb *wrb;
int status;
- if (!lancer_chip(adapter)) {
- *port_name = adapter->hba_port_num + '0';
- return 0;
- }
-
- spin_lock_bh(&adapter->mcc_lock);
-
- wrb = wrb_from_mccq(adapter);
- if (!wrb) {
- status = -EBUSY;
- goto err;
- }
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
+ wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_GET_PORT_NAME, sizeof(*req), wrb,
NULL);
- req->hdr.version = 1;
+ if (!BEx_chip(adapter))
+ req->hdr.version = 1;
- status = be_mcc_notify_wait(adapter);
+ status = be_mbox_notify_wait(adapter);
if (!status) {
struct be_cmd_resp_get_port_name *resp = embedded_payload(wrb);
- *port_name = resp->port_name[adapter->hba_port_num];
+ adapter->port_name = resp->port_name[adapter->hba_port_num];
} else {
- *port_name = adapter->hba_port_num + '0';
+ adapter->port_name = adapter->hba_port_num + '0';
}
-err:
- spin_unlock_bh(&adapter->mcc_lock);
+
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
{
- wrb->frag_pa_hi = upper_32_bits(addr);
- wrb->frag_pa_lo = addr & 0xFFFFFFFF;
- wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
+ wrb->frag_pa_hi = cpu_to_le32(upper_32_bits(addr));
+ wrb->frag_pa_lo = cpu_to_le32(lower_32_bits(addr));
+ wrb->frag_len = cpu_to_le32(len & ETH_WRB_FRAG_LEN_MASK);
+ wrb->rsvd0 = 0;
+}
+
+/* A dummy wrb is just all zeros. Using a separate routine for dummy-wrb
+ * to avoid the swap and shift/mask operations in wrb_fill().
+ */
+static inline void wrb_fill_dummy(struct be_eth_wrb *wrb)
+{
+ wrb->frag_pa_hi = 0;
+ wrb->frag_pa_lo = 0;
+ wrb->frag_len = 0;
wrb->rsvd0 = 0;
}
bool unmap_single)
{
dma_addr_t dma;
+ u32 frag_len = le32_to_cpu(wrb->frag_len);
- be_dws_le_to_cpu(wrb, sizeof(*wrb));
- dma = (u64)wrb->frag_pa_hi << 32 | (u64)wrb->frag_pa_lo;
- if (wrb->frag_len) {
+ dma = (u64)le32_to_cpu(wrb->frag_pa_hi) << 32 |
+ (u64)le32_to_cpu(wrb->frag_pa_lo);
+ if (frag_len) {
if (unmap_single)
- dma_unmap_single(dev, dma, wrb->frag_len,
- DMA_TO_DEVICE);
+ dma_unmap_single(dev, dma, frag_len, DMA_TO_DEVICE);
else
- dma_unmap_page(dev, dma, wrb->frag_len, DMA_TO_DEVICE);
+ dma_unmap_page(dev, dma, frag_len, DMA_TO_DEVICE);
}
}
map_single = true;
wrb = queue_head_node(txq);
wrb_fill(wrb, busaddr, len);
- be_dws_cpu_to_le(wrb, sizeof(*wrb));
queue_head_inc(txq);
copied += len;
}
goto dma_err;
wrb = queue_head_node(txq);
wrb_fill(wrb, busaddr, skb_frag_size(frag));
- be_dws_cpu_to_le(wrb, sizeof(*wrb));
queue_head_inc(txq);
copied += skb_frag_size(frag);
}
wrb = queue_head_node(txq);
unmap_tx_frag(dev, wrb, map_single);
map_single = false;
- copied -= wrb->frag_len;
+ copied -= le32_to_cpu(wrb->frag_len);
adapter->drv_stats.dma_map_errors++;
queue_head_inc(txq);
}
return 0;
}
+static inline int qnq_async_evt_rcvd(struct be_adapter *adapter)
+{
+ return adapter->flags & BE_FLAGS_QNQ_ASYNC_EVT_RCVD;
+}
+
static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
struct sk_buff *skb,
bool *skip_hw_vlan)
/* compose a dummy wrb if there are odd set of wrbs to notify */
if (!lancer_chip(adapter) && (txo->pend_wrb_cnt & 1)) {
- wrb_fill(queue_head_node(txq), 0, 0);
+ wrb_fill_dummy(queue_head_node(txq));
queue_head_inc(txq);
atomic_inc(&txq->used);
txo->pend_wrb_cnt++;
return 0;
}
+static inline bool be_in_all_promisc(struct be_adapter *adapter)
+{
+ return (adapter->if_flags & BE_IF_FLAGS_ALL_PROMISCUOUS) ==
+ BE_IF_FLAGS_ALL_PROMISCUOUS;
+}
+
+static int be_set_vlan_promisc(struct be_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+ int status;
+
+ if (adapter->if_flags & BE_IF_FLAGS_VLAN_PROMISCUOUS)
+ return 0;
+
+ status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, ON);
+ if (!status) {
+ dev_info(dev, "Enabled VLAN promiscuous mode\n");
+ adapter->if_flags |= BE_IF_FLAGS_VLAN_PROMISCUOUS;
+ } else {
+ dev_err(dev, "Failed to enable VLAN promiscuous mode\n");
+ }
+ return status;
+}
+
+static int be_clear_vlan_promisc(struct be_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+ int status;
+
+ status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, OFF);
+ if (!status) {
+ dev_info(dev, "Disabling VLAN promiscuous mode\n");
+ adapter->if_flags &= ~BE_IF_FLAGS_VLAN_PROMISCUOUS;
+ }
+ return status;
+}
+
/*
* 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.
int status = 0;
/* No need to further configure vids if in promiscuous mode */
- if (adapter->promiscuous)
+ if (be_in_all_promisc(adapter))
return 0;
if (adapter->vlans_added > be_max_vlans(adapter))
- goto set_vlan_promisc;
+ return be_set_vlan_promisc(adapter);
/* Construct VLAN Table to give to HW */
for_each_set_bit(i, adapter->vids, VLAN_N_VID)
status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num);
if (status) {
+ dev_err(dev, "Setting HW VLAN filtering failed\n");
/* Set to VLAN promisc mode as setting VLAN filter failed */
if (addl_status(status) ==
MCC_ADDL_STATUS_INSUFFICIENT_RESOURCES)
- goto set_vlan_promisc;
- dev_err(dev, "Setting HW VLAN filtering failed\n");
- } else {
- if (adapter->flags & BE_FLAGS_VLAN_PROMISC) {
- /* hw VLAN filtering re-enabled. */
- status = be_cmd_rx_filter(adapter,
- BE_FLAGS_VLAN_PROMISC, OFF);
- if (!status) {
- dev_info(dev,
- "Disabling VLAN Promiscuous mode\n");
- adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
- }
- }
+ return be_set_vlan_promisc(adapter);
+ } else if (adapter->if_flags & BE_IF_FLAGS_VLAN_PROMISCUOUS) {
+ status = be_clear_vlan_promisc(adapter);
}
-
- return status;
-
-set_vlan_promisc:
- if (adapter->flags & BE_FLAGS_VLAN_PROMISC)
- return 0;
-
- status = be_cmd_rx_filter(adapter, BE_FLAGS_VLAN_PROMISC, ON);
- if (!status) {
- dev_info(dev, "Enable VLAN Promiscuous mode\n");
- adapter->flags |= BE_FLAGS_VLAN_PROMISC;
- } else
- dev_err(dev, "Failed to enable VLAN Promiscuous mode\n");
return status;
}
return be_vid_config(adapter);
}
-static void be_clear_promisc(struct be_adapter *adapter)
+static void be_clear_all_promisc(struct be_adapter *adapter)
{
- adapter->promiscuous = false;
- adapter->flags &= ~(BE_FLAGS_VLAN_PROMISC | BE_FLAGS_MCAST_PROMISC);
+ be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, OFF);
+ adapter->if_flags &= ~BE_IF_FLAGS_ALL_PROMISCUOUS;
+}
- be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
+static void be_set_all_promisc(struct be_adapter *adapter)
+{
+ be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, ON);
+ adapter->if_flags |= BE_IF_FLAGS_ALL_PROMISCUOUS;
}
-static void be_set_rx_mode(struct net_device *netdev)
+static void be_set_mc_promisc(struct be_adapter *adapter)
{
- struct be_adapter *adapter = netdev_priv(netdev);
int status;
- if (netdev->flags & IFF_PROMISC) {
- be_cmd_rx_filter(adapter, IFF_PROMISC, ON);
- adapter->promiscuous = true;
- goto done;
- }
+ if (adapter->if_flags & BE_IF_FLAGS_MCAST_PROMISCUOUS)
+ return;
- /* BE was previously in promiscuous mode; disable it */
- if (adapter->promiscuous) {
- be_clear_promisc(adapter);
- if (adapter->vlans_added)
- be_vid_config(adapter);
+ status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MCAST_PROMISCUOUS, ON);
+ if (!status)
+ adapter->if_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS;
+}
+
+static void be_set_mc_list(struct be_adapter *adapter)
+{
+ int status;
+
+ status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MULTICAST, ON);
+ if (!status)
+ adapter->if_flags &= ~BE_IF_FLAGS_MCAST_PROMISCUOUS;
+ else
+ be_set_mc_promisc(adapter);
+}
+
+static void be_set_uc_list(struct be_adapter *adapter)
+{
+ struct netdev_hw_addr *ha;
+ int i = 1; /* First slot is claimed by the Primary MAC */
+
+ for (; adapter->uc_macs > 0; adapter->uc_macs--, i++)
+ be_cmd_pmac_del(adapter, adapter->if_handle,
+ adapter->pmac_id[i], 0);
+
+ if (netdev_uc_count(adapter->netdev) > be_max_uc(adapter)) {
+ be_set_all_promisc(adapter);
+ return;
}
- /* Enable multicast promisc if num configured exceeds what we support */
- if (netdev->flags & IFF_ALLMULTI ||
- netdev_mc_count(netdev) > be_max_mc(adapter))
- goto set_mcast_promisc;
+ netdev_for_each_uc_addr(ha, adapter->netdev) {
+ adapter->uc_macs++; /* First slot is for Primary MAC */
+ be_cmd_pmac_add(adapter, (u8 *)ha->addr, adapter->if_handle,
+ &adapter->pmac_id[adapter->uc_macs], 0);
+ }
+}
- if (netdev_uc_count(netdev) != adapter->uc_macs) {
- struct netdev_hw_addr *ha;
- int i = 1; /* First slot is claimed by the Primary MAC */
+static void be_clear_uc_list(struct be_adapter *adapter)
+{
+ int i;
- for (; adapter->uc_macs > 0; adapter->uc_macs--, i++) {
- be_cmd_pmac_del(adapter, adapter->if_handle,
- adapter->pmac_id[i], 0);
- }
+ for (i = 1; i < (adapter->uc_macs + 1); i++)
+ be_cmd_pmac_del(adapter, adapter->if_handle,
+ adapter->pmac_id[i], 0);
+ adapter->uc_macs = 0;
+}
- if (netdev_uc_count(netdev) > be_max_uc(adapter)) {
- be_cmd_rx_filter(adapter, IFF_PROMISC, ON);
- adapter->promiscuous = true;
- goto done;
- }
+static void be_set_rx_mode(struct net_device *netdev)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
- netdev_for_each_uc_addr(ha, adapter->netdev) {
- adapter->uc_macs++; /* First slot is for Primary MAC */
- be_cmd_pmac_add(adapter, (u8 *)ha->addr,
- adapter->if_handle,
- &adapter->pmac_id[adapter->uc_macs], 0);
- }
+ if (netdev->flags & IFF_PROMISC) {
+ be_set_all_promisc(adapter);
+ return;
}
- status = be_cmd_rx_filter(adapter, IFF_MULTICAST, ON);
- if (!status) {
- if (adapter->flags & BE_FLAGS_MCAST_PROMISC)
- adapter->flags &= ~BE_FLAGS_MCAST_PROMISC;
- goto done;
+ /* Interface was previously in promiscuous mode; disable it */
+ if (be_in_all_promisc(adapter)) {
+ be_clear_all_promisc(adapter);
+ if (adapter->vlans_added)
+ be_vid_config(adapter);
}
-set_mcast_promisc:
- if (adapter->flags & BE_FLAGS_MCAST_PROMISC)
+ /* Enable multicast promisc if num configured exceeds what we support */
+ if (netdev->flags & IFF_ALLMULTI ||
+ netdev_mc_count(netdev) > be_max_mc(adapter)) {
+ be_set_mc_promisc(adapter);
return;
+ }
- /* Set to MCAST promisc mode if setting MULTICAST address fails
- * or if num configured exceeds what we support
- */
- status = be_cmd_rx_filter(adapter, IFF_ALLMULTI, ON);
- if (!status)
- adapter->flags |= BE_FLAGS_MCAST_PROMISC;
-done:
- return;
+ if (netdev_uc_count(netdev) != adapter->uc_macs)
+ be_set_uc_list(adapter);
+
+ be_set_mc_list(adapter);
}
static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
}
}
+#ifdef CONFIG_NET_RX_BUSY_POLL
+static inline bool be_lock_napi(struct be_eq_obj *eqo)
+{
+ bool status = true;
+
+ spin_lock(&eqo->lock); /* BH is already disabled */
+ if (eqo->state & BE_EQ_LOCKED) {
+ WARN_ON(eqo->state & BE_EQ_NAPI);
+ eqo->state |= BE_EQ_NAPI_YIELD;
+ status = false;
+ } else {
+ eqo->state = BE_EQ_NAPI;
+ }
+ spin_unlock(&eqo->lock);
+ return status;
+}
+
+static inline void be_unlock_napi(struct be_eq_obj *eqo)
+{
+ spin_lock(&eqo->lock); /* BH is already disabled */
+
+ WARN_ON(eqo->state & (BE_EQ_POLL | BE_EQ_NAPI_YIELD));
+ eqo->state = BE_EQ_IDLE;
+
+ spin_unlock(&eqo->lock);
+}
+
+static inline bool be_lock_busy_poll(struct be_eq_obj *eqo)
+{
+ bool status = true;
+
+ spin_lock_bh(&eqo->lock);
+ if (eqo->state & BE_EQ_LOCKED) {
+ eqo->state |= BE_EQ_POLL_YIELD;
+ status = false;
+ } else {
+ eqo->state |= BE_EQ_POLL;
+ }
+ spin_unlock_bh(&eqo->lock);
+ return status;
+}
+
+static inline void be_unlock_busy_poll(struct be_eq_obj *eqo)
+{
+ spin_lock_bh(&eqo->lock);
+
+ WARN_ON(eqo->state & (BE_EQ_NAPI));
+ eqo->state = BE_EQ_IDLE;
+
+ spin_unlock_bh(&eqo->lock);
+}
+
+static inline void be_enable_busy_poll(struct be_eq_obj *eqo)
+{
+ spin_lock_init(&eqo->lock);
+ eqo->state = BE_EQ_IDLE;
+}
+
+static inline void be_disable_busy_poll(struct be_eq_obj *eqo)
+{
+ local_bh_disable();
+
+ /* It's enough to just acquire napi lock on the eqo to stop
+ * be_busy_poll() from processing any queueus.
+ */
+ while (!be_lock_napi(eqo))
+ mdelay(1);
+
+ local_bh_enable();
+}
+
+#else /* CONFIG_NET_RX_BUSY_POLL */
+
+static inline bool be_lock_napi(struct be_eq_obj *eqo)
+{
+ return true;
+}
+
+static inline void be_unlock_napi(struct be_eq_obj *eqo)
+{
+}
+
+static inline bool be_lock_busy_poll(struct be_eq_obj *eqo)
+{
+ return false;
+}
+
+static inline void be_unlock_busy_poll(struct be_eq_obj *eqo)
+{
+}
+
+static inline void be_enable_busy_poll(struct be_eq_obj *eqo)
+{
+}
+
+static inline void be_disable_busy_poll(struct be_eq_obj *eqo)
+{
+}
+#endif /* CONFIG_NET_RX_BUSY_POLL */
+
int be_poll(struct napi_struct *napi, int budget)
{
struct be_eq_obj *eqo = container_of(napi, struct be_eq_obj, napi);
be_tx_compl_clean(adapter);
be_rx_qs_destroy(adapter);
-
- for (i = 1; i < (adapter->uc_macs + 1); i++)
- be_cmd_pmac_del(adapter, adapter->if_handle,
- adapter->pmac_id[i], 0);
- adapter->uc_macs = 0;
+ be_clear_uc_list(adapter);
for_all_evt_queues(adapter, eqo, i) {
if (msix_enabled(adapter))
return status;
}
+static 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);
+}
+
/*
* Generate a seed MAC address from the PF MAC Address using jhash.
* MAC Address for VFs are assigned incrementally starting from the seed.
static void be_mac_clear(struct be_adapter *adapter)
{
- int i;
-
if (adapter->pmac_id) {
- for (i = 0; i < (adapter->uc_macs + 1); i++)
- be_cmd_pmac_del(adapter, adapter->if_handle,
- adapter->pmac_id[i], 0);
- adapter->uc_macs = 0;
-
+ be_cmd_pmac_del(adapter, adapter->if_handle,
+ adapter->pmac_id[0], 0);
kfree(adapter->pmac_id);
adapter->pmac_id = NULL;
}
adapter->phy.link_speed = -1;
adapter->if_handle = -1;
adapter->be3_native = false;
- adapter->promiscuous = false;
+ adapter->if_flags = 0;
if (be_physfn(adapter))
adapter->cmd_privileges = MAX_PRIVILEGES;
else
if (status)
return status;
- if (be_physfn(adapter)) {
+ be_cmd_query_port_name(adapter);
+
+ if (be_physfn(adapter)) {
status = be_cmd_get_active_profile(adapter, &profile_id);
if (!status)
dev_info(&adapter->pdev->dev,
return status;
}
+static inline int fw_major_num(const char *fw_ver)
+{
+ int fw_major = 0, i;
+
+ i = sscanf(fw_ver, "%d.", &fw_major);
+ if (i != 1)
+ return 0;
+
+ return fw_major;
+}
+
static int be_setup(struct be_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
int status;
u8 crc[4];
- status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_size - 4);
+ status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_offset,
+ img_size - 4);
if (status)
return status;
}
static int be_flash(struct be_adapter *adapter, const u8 *img,
- struct be_dma_mem *flash_cmd, int optype, int img_size)
+ struct be_dma_mem *flash_cmd, int optype, int img_size,
+ u32 img_offset)
{
+ u32 flash_op, num_bytes, total_bytes = img_size, bytes_sent = 0;
struct be_cmd_write_flashrom *req = flash_cmd->va;
- u32 total_bytes, flash_op, num_bytes;
int status;
- total_bytes = img_size;
while (total_bytes) {
num_bytes = min_t(u32, 32*1024, total_bytes);
memcpy(req->data_buf, img, num_bytes);
img += num_bytes;
status = be_cmd_write_flashrom(adapter, flash_cmd, optype,
- flash_op, num_bytes);
+ flash_op, img_offset +
+ bytes_sent, num_bytes);
if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST &&
optype == OPTYPE_PHY_FW)
break;
else if (status)
return status;
+
+ bytes_sent += num_bytes;
}
return 0;
}
pflashcomp = gen2_flash_types;
filehdr_size = sizeof(struct flash_file_hdr_g2);
num_comp = ARRAY_SIZE(gen2_flash_types);
+ img_hdrs_size = 0;
}
/* Get flash section info*/
return -1;
status = be_flash(adapter, p, flash_cmd, pflashcomp[i].optype,
- pflashcomp[i].size);
+ pflashcomp[i].size, 0);
if (status) {
dev_err(dev, "Flashing section type 0x%x failed\n",
pflashcomp[i].img_type);
struct be_dma_mem *flash_cmd, int num_of_images)
{
int img_hdrs_size = num_of_images * sizeof(struct image_hdr);
+ bool crc_match, old_fw_img, flash_offset_support = true;
struct device *dev = &adapter->pdev->dev;
struct flash_section_info *fsec = NULL;
u32 img_offset, img_size, img_type;
+ u16 img_optype, flash_optype;
int status, i, filehdr_size;
- bool crc_match, old_fw_img;
- u16 img_optype;
const u8 *p;
filehdr_size = sizeof(struct flash_file_hdr_g3);
return -EINVAL;
}
+retry_flash:
for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) {
img_offset = le32_to_cpu(fsec->fsec_entry[i].offset);
img_size = le32_to_cpu(fsec->fsec_entry[i].pad_size);
if (img_optype == 0xFFFF)
continue;
+
+ if (flash_offset_support)
+ flash_optype = OPTYPE_OFFSET_SPECIFIED;
+ else
+ flash_optype = img_optype;
+
/* Don't bother verifying CRC if an old FW image is being
* flashed
*/
status = be_check_flash_crc(adapter, fw->data, img_offset,
img_size, filehdr_size +
- img_hdrs_size, img_optype,
+ img_hdrs_size, flash_optype,
&crc_match);
- /* The current FW image on the card does not recognize the new
- * FLASH op_type. The FW download is partially complete.
- * Reboot the server now to enable FW image to recognize the
- * new FLASH op_type. To complete the remaining process,
- * download the same FW again after the reboot.
- */
if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST ||
base_status(status) == MCC_STATUS_ILLEGAL_FIELD) {
+ /* The current FW image on the card does not support
+ * OFFSET based flashing. Retry using older mechanism
+ * of OPTYPE based flashing
+ */
+ if (flash_optype == OPTYPE_OFFSET_SPECIFIED) {
+ flash_offset_support = false;
+ goto retry_flash;
+ }
+
+ /* The current FW image on the card does not recognize
+ * the new FLASH op_type. The FW download is partially
+ * complete. Reboot the server now to enable FW image
+ * to recognize the new FLASH op_type. To complete the
+ * remaining process, download the same FW again after
+ * the reboot.
+ */
dev_err(dev, "Flash incomplete. Reset the server\n");
dev_err(dev, "Download FW image again after reset\n");
return -EAGAIN;
if (p + img_size > fw->data + fw->size)
return -1;
- status = be_flash(adapter, p, flash_cmd, img_optype, img_size);
+ status = be_flash(adapter, p, flash_cmd, flash_optype, img_size,
+ img_offset);
+
+ /* The current FW image on the card does not support OFFSET
+ * based flashing. Retry using older mechanism of OPTYPE based
+ * flashing
+ */
+ if (base_status(status) == MCC_STATUS_ILLEGAL_FIELD &&
+ flash_optype == OPTYPE_OFFSET_SPECIFIED) {
+ flash_offset_support = false;
+ goto retry_flash;
+ }
+
/* For old FW images ignore ILLEGAL_FIELD error or errors on
* UFI_DIR region
*/
return 0;
}
-#define UFI_TYPE2 2
-#define UFI_TYPE3 3
-#define UFI_TYPE3R 10
-#define UFI_TYPE4 4
+#define BE2_UFI 2
+#define BE3_UFI 3
+#define BE3R_UFI 10
+#define SH_UFI 4
+#define SH_P2_UFI 11
+
static int be_get_ufi_type(struct be_adapter *adapter,
struct flash_file_hdr_g3 *fhdr)
{
- if (!fhdr)
- goto be_get_ufi_exit;
+ if (!fhdr) {
+ dev_err(&adapter->pdev->dev, "Invalid FW UFI file");
+ return -1;
+ }
- if (skyhawk_chip(adapter) && fhdr->build[0] == '4')
- return UFI_TYPE4;
- else if (BE3_chip(adapter) && fhdr->build[0] == '3') {
- if (fhdr->asic_type_rev == 0x10)
- return UFI_TYPE3R;
- else
- return UFI_TYPE3;
- } else if (BE2_chip(adapter) && fhdr->build[0] == '2')
- return UFI_TYPE2;
+ /* First letter of the build version is used to identify
+ * which chip this image file is meant for.
+ */
+ switch (fhdr->build[0]) {
+ case BLD_STR_UFI_TYPE_SH:
+ return (fhdr->asic_type_rev == ASIC_REV_P2) ? SH_P2_UFI :
+ SH_UFI;
+ case BLD_STR_UFI_TYPE_BE3:
+ return (fhdr->asic_type_rev == ASIC_REV_B0) ? BE3R_UFI :
+ BE3_UFI;
+ case BLD_STR_UFI_TYPE_BE2:
+ return BE2_UFI;
+ default:
+ return -1;
+ }
+}
-be_get_ufi_exit:
- dev_err(&adapter->pdev->dev,
- "UFI and Interface are not compatible for flashing\n");
- return -1;
+/* Check if the flash image file is compatible with the adapter that
+ * is being flashed.
+ * BE3 chips with asic-rev B0 must be flashed only with BE3R_UFI type.
+ * Skyhawk chips with asic-rev P2 must be flashed only with SH_P2_UFI type.
+ */
+static bool be_check_ufi_compatibility(struct be_adapter *adapter,
+ struct flash_file_hdr_g3 *fhdr)
+{
+ int ufi_type = be_get_ufi_type(adapter, fhdr);
+
+ switch (ufi_type) {
+ case SH_P2_UFI:
+ return skyhawk_chip(adapter);
+ case SH_UFI:
+ return (skyhawk_chip(adapter) &&
+ adapter->asic_rev < ASIC_REV_P2);
+ case BE3R_UFI:
+ return BE3_chip(adapter);
+ case BE3_UFI:
+ return (BE3_chip(adapter) && adapter->asic_rev < ASIC_REV_B0);
+ case BE2_UFI:
+ return BE2_chip(adapter);
+ default:
+ return false;
+ }
}
static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw)
{
+ struct device *dev = &adapter->pdev->dev;
struct flash_file_hdr_g3 *fhdr3;
- struct image_hdr *img_hdr_ptr = NULL;
+ struct image_hdr *img_hdr_ptr;
+ int status = 0, i, num_imgs;
struct be_dma_mem flash_cmd;
- const u8 *p;
- int status = 0, i = 0, num_imgs = 0, ufi_type = 0;
- flash_cmd.size = sizeof(struct be_cmd_write_flashrom);
- flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
- &flash_cmd.dma, GFP_KERNEL);
- if (!flash_cmd.va) {
- status = -ENOMEM;
- goto be_fw_exit;
+ fhdr3 = (struct flash_file_hdr_g3 *)fw->data;
+ if (!be_check_ufi_compatibility(adapter, fhdr3)) {
+ dev_err(dev, "Flash image is not compatible with adapter\n");
+ return -EINVAL;
}
- p = fw->data;
- fhdr3 = (struct flash_file_hdr_g3 *)p;
-
- ufi_type = be_get_ufi_type(adapter, fhdr3);
+ flash_cmd.size = sizeof(struct be_cmd_write_flashrom);
+ flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size, &flash_cmd.dma,
+ GFP_KERNEL);
+ if (!flash_cmd.va)
+ return -ENOMEM;
num_imgs = le32_to_cpu(fhdr3->num_imgs);
for (i = 0; i < num_imgs; i++) {
img_hdr_ptr = (struct image_hdr *)(fw->data +
(sizeof(struct flash_file_hdr_g3) +
i * sizeof(struct image_hdr)));
- if (le32_to_cpu(img_hdr_ptr->imageid) == 1) {
- switch (ufi_type) {
- case UFI_TYPE4:
- status = be_flash_skyhawk(adapter, fw,
- &flash_cmd, num_imgs);
- break;
- case UFI_TYPE3R:
- status = be_flash_BEx(adapter, fw, &flash_cmd,
- num_imgs);
- break;
- case UFI_TYPE3:
- /* Do not flash this ufi on BE3-R cards */
- if (adapter->asic_rev < 0x10)
- status = be_flash_BEx(adapter, fw,
- &flash_cmd,
- num_imgs);
- else {
- status = -EINVAL;
- dev_err(&adapter->pdev->dev,
- "Can't load BE3 UFI on BE3R\n");
- }
- }
- }
- }
-
- if (ufi_type == UFI_TYPE2)
- status = be_flash_BEx(adapter, fw, &flash_cmd, 0);
- else if (ufi_type == -1)
- status = -EINVAL;
+ if (!BE2_chip(adapter) &&
+ le32_to_cpu(img_hdr_ptr->imageid) != 1)
+ continue;
- dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va,
- flash_cmd.dma);
- if (status) {
- dev_err(&adapter->pdev->dev, "Firmware load error\n");
- goto be_fw_exit;
+ if (skyhawk_chip(adapter))
+ status = be_flash_skyhawk(adapter, fw, &flash_cmd,
+ num_imgs);
+ else
+ status = be_flash_BEx(adapter, fw, &flash_cmd,
+ num_imgs);
}
- dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
+ dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma);
+ if (!status)
+ dev_info(dev, "Firmware flashed successfully\n");
-be_fw_exit:
return status;
}
msecs_to_jiffies(1000));
}
+static void be_log_sfp_info(struct be_adapter *adapter)
+{
+ int status;
+
+ status = be_cmd_query_sfp_info(adapter);
+ if (!status) {
+ dev_err(&adapter->pdev->dev,
+ "Unqualified SFP+ detected on %c from %s part no: %s",
+ adapter->port_name, adapter->phy.vendor_name,
+ adapter->phy.vendor_pn);
+ }
+ adapter->flags &= ~BE_FLAGS_EVT_INCOMPATIBLE_SFP;
+}
+
static void be_worker(struct work_struct *work)
{
struct be_adapter *adapter =
be_eqd_update(adapter);
+ if (adapter->flags & BE_FLAGS_EVT_INCOMPATIBLE_SFP)
+ be_log_sfp_info(adapter);
+
reschedule:
adapter->work_counter++;
schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
return be_physfn(adapter) ? "PF" : "VF";
}
+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:
+ case OC_DEVICE_ID6:
+ return OC_NAME_SH;
+ default:
+ return BE_NAME;
+ }
+}
+
static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
{
- int status = 0;
struct be_adapter *adapter;
struct net_device *netdev;
- char port_name;
+ int status = 0;
dev_info(&pdev->dev, "%s version is %s\n", DRV_NAME, DRV_VER);
schedule_delayed_work(&adapter->func_recovery_work,
msecs_to_jiffies(1000));
- be_cmd_query_port_name(adapter, &port_name);
-
dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev),
- func_name(adapter), mc_name(adapter), port_name);
+ func_name(adapter), mc_name(adapter), adapter->port_name);
return 0;