@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_BNXT) += bnxt_en.o
-bnxt_en-y := bnxt.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_ptp.o bnxt_vfr.o bnxt_devlink.o bnxt_dim.o
+bnxt_en-y := bnxt.o bnxt_hwrm.o bnxt_sriov.o bnxt_ethtool.o bnxt_dcb.o bnxt_ulp.o bnxt_xdp.o bnxt_ptp.o bnxt_vfr.o bnxt_devlink.o bnxt_dim.o
bnxt_en-$(CONFIG_BNXT_FLOWER_OFFLOAD) += bnxt_tc.o
bnxt_en-$(CONFIG_DEBUG_FS) += bnxt_debugfs.o
@@ -60,6 +60,7 @@
#include "bnxt_hsi.h"
#include "bnxt.h"
+#include "bnxt_hwrm.h"
#include "bnxt_ulp.h"
#include "bnxt_sriov.h"
#include "bnxt_ethtool.h"
@@ -4549,278 +4550,6 @@ static void bnxt_enable_int(struct bnxt *bp)
}
}
-void bnxt_hwrm_cmd_hdr_init(struct bnxt *bp, void *request, u16 req_type,
- u16 cmpl_ring, u16 target_id)
-{
- struct input *req = request;
-
- req->req_type = cpu_to_le16(req_type);
- req->cmpl_ring = cpu_to_le16(cmpl_ring);
- req->target_id = cpu_to_le16(target_id);
- req->resp_addr = cpu_to_le64(bp->hwrm_cmd_resp_dma_addr);
-}
-
-static int bnxt_hwrm_to_stderr(u32 hwrm_err)
-{
- switch (hwrm_err) {
- case HWRM_ERR_CODE_SUCCESS:
- return 0;
- case HWRM_ERR_CODE_RESOURCE_LOCKED:
- return -EROFS;
- case HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED:
- return -EACCES;
- case HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR:
- return -ENOSPC;
- case HWRM_ERR_CODE_INVALID_PARAMS:
- case HWRM_ERR_CODE_INVALID_FLAGS:
- case HWRM_ERR_CODE_INVALID_ENABLES:
- case HWRM_ERR_CODE_UNSUPPORTED_TLV:
- case HWRM_ERR_CODE_UNSUPPORTED_OPTION_ERR:
- return -EINVAL;
- case HWRM_ERR_CODE_NO_BUFFER:
- return -ENOMEM;
- case HWRM_ERR_CODE_HOT_RESET_PROGRESS:
- case HWRM_ERR_CODE_BUSY:
- return -EAGAIN;
- case HWRM_ERR_CODE_CMD_NOT_SUPPORTED:
- return -EOPNOTSUPP;
- default:
- return -EIO;
- }
-}
-
-static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
- int timeout, bool silent)
-{
- int i, intr_process, rc, tmo_count;
- struct input *req = msg;
- u32 *data = msg;
- u8 *valid;
- u16 cp_ring_id, len = 0;
- struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr;
- u16 max_req_len = BNXT_HWRM_MAX_REQ_LEN;
- struct hwrm_short_input short_input = {0};
- u32 doorbell_offset = BNXT_GRCPF_REG_CHIMP_COMM_TRIGGER;
- u32 bar_offset = BNXT_GRCPF_REG_CHIMP_COMM;
- u16 dst = BNXT_HWRM_CHNL_CHIMP;
-
- if (BNXT_NO_FW_ACCESS(bp) &&
- le16_to_cpu(req->req_type) != HWRM_FUNC_RESET)
- return -EBUSY;
-
- if (msg_len > BNXT_HWRM_MAX_REQ_LEN) {
- if (msg_len > bp->hwrm_max_ext_req_len ||
- !bp->hwrm_short_cmd_req_addr)
- return -EINVAL;
- }
-
- if (bnxt_kong_hwrm_message(bp, req)) {
- dst = BNXT_HWRM_CHNL_KONG;
- bar_offset = BNXT_GRCPF_REG_KONG_COMM;
- doorbell_offset = BNXT_GRCPF_REG_KONG_COMM_TRIGGER;
- }
-
- memset(resp, 0, PAGE_SIZE);
- cp_ring_id = le16_to_cpu(req->cmpl_ring);
- intr_process = (cp_ring_id == INVALID_HW_RING_ID) ? 0 : 1;
-
- req->seq_id = cpu_to_le16(bnxt_get_hwrm_seq_id(bp, dst));
- /* currently supports only one outstanding message */
- if (intr_process)
- bp->hwrm_intr_seq_id = le16_to_cpu(req->seq_id);
-
- if ((bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) ||
- msg_len > BNXT_HWRM_MAX_REQ_LEN) {
- void *short_cmd_req = bp->hwrm_short_cmd_req_addr;
- u16 max_msg_len;
-
- /* Set boundary for maximum extended request length for short
- * cmd format. If passed up from device use the max supported
- * internal req length.
- */
- max_msg_len = bp->hwrm_max_ext_req_len;
-
- memcpy(short_cmd_req, req, msg_len);
- if (msg_len < max_msg_len)
- memset(short_cmd_req + msg_len, 0,
- max_msg_len - msg_len);
-
- short_input.req_type = req->req_type;
- short_input.signature =
- cpu_to_le16(SHORT_REQ_SIGNATURE_SHORT_CMD);
- short_input.size = cpu_to_le16(msg_len);
- short_input.req_addr =
- cpu_to_le64(bp->hwrm_short_cmd_req_dma_addr);
-
- data = (u32 *)&short_input;
- msg_len = sizeof(short_input);
-
- /* Sync memory write before updating doorbell */
- wmb();
-
- max_req_len = BNXT_HWRM_SHORT_REQ_LEN;
- }
-
- /* Write request msg to hwrm channel */
- __iowrite32_copy(bp->bar0 + bar_offset, data, msg_len / 4);
-
- for (i = msg_len; i < max_req_len; i += 4)
- writel(0, bp->bar0 + bar_offset + i);
-
- /* Ring channel doorbell */
- writel(1, bp->bar0 + doorbell_offset);
-
- if (!pci_is_enabled(bp->pdev))
- return -ENODEV;
-
- if (!timeout)
- timeout = DFLT_HWRM_CMD_TIMEOUT;
- /* Limit timeout to an upper limit */
- timeout = min(timeout, HWRM_CMD_MAX_TIMEOUT);
- /* convert timeout to usec */
- timeout *= 1000;
-
- i = 0;
- /* Short timeout for the first few iterations:
- * number of loops = number of loops for short timeout +
- * number of loops for standard timeout.
- */
- tmo_count = HWRM_SHORT_TIMEOUT_COUNTER;
- timeout = timeout - HWRM_SHORT_MIN_TIMEOUT * HWRM_SHORT_TIMEOUT_COUNTER;
- tmo_count += DIV_ROUND_UP(timeout, HWRM_MIN_TIMEOUT);
-
- if (intr_process) {
- u16 seq_id = bp->hwrm_intr_seq_id;
-
- /* Wait until hwrm response cmpl interrupt is processed */
- while (bp->hwrm_intr_seq_id != (u16)~seq_id &&
- i++ < tmo_count) {
- /* Abort the wait for completion if the FW health
- * check has failed.
- */
- if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
- return -EBUSY;
- /* on first few passes, just barely sleep */
- if (i < HWRM_SHORT_TIMEOUT_COUNTER) {
- usleep_range(HWRM_SHORT_MIN_TIMEOUT,
- HWRM_SHORT_MAX_TIMEOUT);
- } else {
- if (HWRM_WAIT_MUST_ABORT(bp, req))
- break;
- usleep_range(HWRM_MIN_TIMEOUT,
- HWRM_MAX_TIMEOUT);
- }
- }
-
- if (bp->hwrm_intr_seq_id != (u16)~seq_id) {
- if (!silent)
- netdev_err(bp->dev, "Resp cmpl intr err msg: 0x%x\n",
- le16_to_cpu(req->req_type));
- return -EBUSY;
- }
- len = le16_to_cpu(resp->resp_len);
- valid = ((u8 *)resp) + len - 1;
- } else {
- int j;
-
- /* Check if response len is updated */
- for (i = 0; i < tmo_count; i++) {
- /* Abort the wait for completion if the FW health
- * check has failed.
- */
- if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
- return -EBUSY;
- len = le16_to_cpu(resp->resp_len);
- if (len)
- break;
- /* on first few passes, just barely sleep */
- if (i < HWRM_SHORT_TIMEOUT_COUNTER) {
- usleep_range(HWRM_SHORT_MIN_TIMEOUT,
- HWRM_SHORT_MAX_TIMEOUT);
- } else {
- if (HWRM_WAIT_MUST_ABORT(bp, req))
- goto timeout_abort;
- usleep_range(HWRM_MIN_TIMEOUT,
- HWRM_MAX_TIMEOUT);
- }
- }
-
- if (i >= tmo_count) {
-timeout_abort:
- if (!silent)
- netdev_err(bp->dev, "Error (timeout: %d) msg {0x%x 0x%x} len:%d\n",
- HWRM_TOTAL_TIMEOUT(i),
- le16_to_cpu(req->req_type),
- le16_to_cpu(req->seq_id), len);
- return -EBUSY;
- }
-
- /* Last byte of resp contains valid bit */
- valid = ((u8 *)resp) + len - 1;
- for (j = 0; j < HWRM_VALID_BIT_DELAY_USEC; j++) {
- /* make sure we read from updated DMA memory */
- dma_rmb();
- if (*valid)
- break;
- usleep_range(1, 5);
- }
-
- if (j >= HWRM_VALID_BIT_DELAY_USEC) {
- if (!silent)
- netdev_err(bp->dev, "Error (timeout: %d) msg {0x%x 0x%x} len:%d v:%d\n",
- HWRM_TOTAL_TIMEOUT(i),
- le16_to_cpu(req->req_type),
- le16_to_cpu(req->seq_id), len,
- *valid);
- return -EBUSY;
- }
- }
-
- /* Zero valid bit for compatibility. Valid bit in an older spec
- * may become a new field in a newer spec. We must make sure that
- * a new field not implemented by old spec will read zero.
- */
- *valid = 0;
- rc = le16_to_cpu(resp->error_code);
- if (rc && !silent)
- netdev_err(bp->dev, "hwrm req_type 0x%x seq id 0x%x error 0x%x\n",
- le16_to_cpu(resp->req_type),
- le16_to_cpu(resp->seq_id), rc);
- return bnxt_hwrm_to_stderr(rc);
-}
-
-int _hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
-{
- return bnxt_hwrm_do_send_msg(bp, msg, msg_len, timeout, false);
-}
-
-int _hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 msg_len,
- int timeout)
-{
- return bnxt_hwrm_do_send_msg(bp, msg, msg_len, timeout, true);
-}
-
-int hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
-{
- int rc;
-
- mutex_lock(&bp->hwrm_cmd_lock);
- rc = _hwrm_send_message(bp, msg, msg_len, timeout);
- mutex_unlock(&bp->hwrm_cmd_lock);
- return rc;
-}
-
-int hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 msg_len,
- int timeout)
-{
- int rc;
-
- mutex_lock(&bp->hwrm_cmd_lock);
- rc = bnxt_hwrm_do_send_msg(bp, msg, msg_len, timeout, true);
- mutex_unlock(&bp->hwrm_cmd_lock);
- return rc;
-}
-
int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap, int bmap_size,
bool async_only)
{
@@ -669,37 +669,7 @@ struct nqe_cn {
#define RING_CMP(idx) ((idx) & bp->cp_ring_mask)
#define NEXT_CMP(idx) RING_CMP(ADV_RAW_CMP(idx, 1))
-#define BNXT_HWRM_MAX_REQ_LEN (bp->hwrm_max_req_len)
-#define BNXT_HWRM_SHORT_REQ_LEN sizeof(struct hwrm_short_input)
#define DFLT_HWRM_CMD_TIMEOUT 500
-#define HWRM_CMD_MAX_TIMEOUT 40000
-#define SHORT_HWRM_CMD_TIMEOUT 20
-#define HWRM_CMD_TIMEOUT (bp->hwrm_cmd_timeout)
-#define HWRM_RESET_TIMEOUT ((HWRM_CMD_TIMEOUT) * 4)
-#define HWRM_COREDUMP_TIMEOUT ((HWRM_CMD_TIMEOUT) * 12)
-#define BNXT_HWRM_REQ_MAX_SIZE 128
-#define BNXT_HWRM_REQS_PER_PAGE (BNXT_PAGE_SIZE / \
- BNXT_HWRM_REQ_MAX_SIZE)
-#define HWRM_SHORT_MIN_TIMEOUT 3
-#define HWRM_SHORT_MAX_TIMEOUT 10
-#define HWRM_SHORT_TIMEOUT_COUNTER 5
-
-#define HWRM_MIN_TIMEOUT 25
-#define HWRM_MAX_TIMEOUT 40
-
-#define HWRM_WAIT_MUST_ABORT(bp, req) \
- (le16_to_cpu((req)->req_type) != HWRM_VER_GET && \
- !bnxt_is_fw_healthy(bp))
-
-#define HWRM_TOTAL_TIMEOUT(n) (((n) <= HWRM_SHORT_TIMEOUT_COUNTER) ? \
- ((n) * HWRM_SHORT_MIN_TIMEOUT) : \
- (HWRM_SHORT_TIMEOUT_COUNTER * HWRM_SHORT_MIN_TIMEOUT + \
- ((n) - HWRM_SHORT_TIMEOUT_COUNTER) * HWRM_MIN_TIMEOUT))
-
-#define HWRM_VALID_BIT_DELAY_USEC 150
-
-#define BNXT_HWRM_CHNL_CHIMP 0
-#define BNXT_HWRM_CHNL_KONG 1
#define BNXT_RX_EVENT 1
#define BNXT_AGG_EVENT 2
@@ -2185,55 +2155,6 @@ static inline void bnxt_db_write(struct bnxt *bp, struct bnxt_db_info *db,
}
}
-static inline bool bnxt_cfa_hwrm_message(u16 req_type)
-{
- switch (req_type) {
- case HWRM_CFA_ENCAP_RECORD_ALLOC:
- case HWRM_CFA_ENCAP_RECORD_FREE:
- case HWRM_CFA_DECAP_FILTER_ALLOC:
- case HWRM_CFA_DECAP_FILTER_FREE:
- case HWRM_CFA_EM_FLOW_ALLOC:
- case HWRM_CFA_EM_FLOW_FREE:
- case HWRM_CFA_EM_FLOW_CFG:
- case HWRM_CFA_FLOW_ALLOC:
- case HWRM_CFA_FLOW_FREE:
- case HWRM_CFA_FLOW_INFO:
- case HWRM_CFA_FLOW_FLUSH:
- case HWRM_CFA_FLOW_STATS:
- case HWRM_CFA_METER_PROFILE_ALLOC:
- case HWRM_CFA_METER_PROFILE_FREE:
- case HWRM_CFA_METER_PROFILE_CFG:
- case HWRM_CFA_METER_INSTANCE_ALLOC:
- case HWRM_CFA_METER_INSTANCE_FREE:
- return true;
- default:
- return false;
- }
-}
-
-static inline bool bnxt_kong_hwrm_message(struct bnxt *bp, struct input *req)
-{
- return (bp->fw_cap & BNXT_FW_CAP_KONG_MB_CHNL &&
- (bnxt_cfa_hwrm_message(le16_to_cpu(req->req_type)) ||
- le16_to_cpu(req->target_id) == HWRM_TARGET_ID_KONG));
-}
-
-static inline void *bnxt_get_hwrm_resp_addr(struct bnxt *bp, void *req)
-{
- return bp->hwrm_cmd_resp_addr;
-}
-
-static inline u16 bnxt_get_hwrm_seq_id(struct bnxt *bp, u16 dst)
-{
- u16 seq_id;
-
- if (dst == BNXT_HWRM_CHNL_CHIMP)
- seq_id = bp->hwrm_cmd_seq++;
- else
- seq_id = bp->hwrm_cmd_kong_seq++;
- return seq_id;
-}
-
extern const u16 bnxt_lhint_arr[];
int bnxt_alloc_rx_data(struct bnxt *bp, struct bnxt_rx_ring_info *rxr,
@@ -2243,11 +2164,6 @@ u32 bnxt_fw_health_readl(struct bnxt *bp, int reg_idx);
void bnxt_set_tpa_flags(struct bnxt *bp);
void bnxt_set_ring_params(struct bnxt *);
int bnxt_set_rx_skb_mode(struct bnxt *bp, bool page_mode);
-void bnxt_hwrm_cmd_hdr_init(struct bnxt *, void *, u16, u16, u16);
-int _hwrm_send_message(struct bnxt *, void *, u32, int);
-int _hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 len, int timeout);
-int hwrm_send_message(struct bnxt *, void *, u32, int);
-int hwrm_send_message_silent(struct bnxt *, void *, u32, int);
int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp, unsigned long *bmap,
int bmap_size, bool async_only);
int bnxt_get_nr_rss_ctxs(struct bnxt *bp, int rx_rings);
@@ -18,6 +18,7 @@
#include <rdma/ib_verbs.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
+#include "bnxt_hwrm.h"
#include "bnxt_dcb.h"
#ifdef CONFIG_BNXT_DCB
@@ -12,6 +12,7 @@
#include <net/devlink.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
+#include "bnxt_hwrm.h"
#include "bnxt_vfr.h"
#include "bnxt_devlink.h"
#include "bnxt_ethtool.h"
@@ -24,6 +24,7 @@
#include <linux/timecounter.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
+#include "bnxt_hwrm.h"
#include "bnxt_xdp.h"
#include "bnxt_ptp.h"
#include "bnxt_ethtool.h"
new file mode 100644
@@ -0,0 +1,297 @@
+/* Broadcom NetXtreme-C/E network driver.
+ *
+ * Copyright (c) 2020 Broadcom Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/errno.h>
+#include <linux/ethtool.h>
+#include <linux/if_ether.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/skbuff.h>
+
+#include "bnxt_hsi.h"
+#include "bnxt.h"
+#include "bnxt_hwrm.h"
+
+void bnxt_hwrm_cmd_hdr_init(struct bnxt *bp, void *request, u16 req_type,
+ u16 cmpl_ring, u16 target_id)
+{
+ struct input *req = request;
+
+ req->req_type = cpu_to_le16(req_type);
+ req->cmpl_ring = cpu_to_le16(cmpl_ring);
+ req->target_id = cpu_to_le16(target_id);
+ req->resp_addr = cpu_to_le64(bp->hwrm_cmd_resp_dma_addr);
+}
+
+static int bnxt_hwrm_to_stderr(u32 hwrm_err)
+{
+ switch (hwrm_err) {
+ case HWRM_ERR_CODE_SUCCESS:
+ return 0;
+ case HWRM_ERR_CODE_RESOURCE_LOCKED:
+ return -EROFS;
+ case HWRM_ERR_CODE_RESOURCE_ACCESS_DENIED:
+ return -EACCES;
+ case HWRM_ERR_CODE_RESOURCE_ALLOC_ERROR:
+ return -ENOSPC;
+ case HWRM_ERR_CODE_INVALID_PARAMS:
+ case HWRM_ERR_CODE_INVALID_FLAGS:
+ case HWRM_ERR_CODE_INVALID_ENABLES:
+ case HWRM_ERR_CODE_UNSUPPORTED_TLV:
+ case HWRM_ERR_CODE_UNSUPPORTED_OPTION_ERR:
+ return -EINVAL;
+ case HWRM_ERR_CODE_NO_BUFFER:
+ return -ENOMEM;
+ case HWRM_ERR_CODE_HOT_RESET_PROGRESS:
+ case HWRM_ERR_CODE_BUSY:
+ return -EAGAIN;
+ case HWRM_ERR_CODE_CMD_NOT_SUPPORTED:
+ return -EOPNOTSUPP;
+ default:
+ return -EIO;
+ }
+}
+
+static int bnxt_hwrm_do_send_msg(struct bnxt *bp, void *msg, u32 msg_len,
+ int timeout, bool silent)
+{
+ int i, intr_process, rc, tmo_count;
+ struct input *req = msg;
+ u32 *data = msg;
+ u8 *valid;
+ u16 cp_ring_id, len = 0;
+ struct hwrm_err_output *resp = bp->hwrm_cmd_resp_addr;
+ u16 max_req_len = BNXT_HWRM_MAX_REQ_LEN;
+ struct hwrm_short_input short_input = {0};
+ u32 doorbell_offset = BNXT_GRCPF_REG_CHIMP_COMM_TRIGGER;
+ u32 bar_offset = BNXT_GRCPF_REG_CHIMP_COMM;
+ u16 dst = BNXT_HWRM_CHNL_CHIMP;
+
+ if (BNXT_NO_FW_ACCESS(bp) &&
+ le16_to_cpu(req->req_type) != HWRM_FUNC_RESET)
+ return -EBUSY;
+
+ if (msg_len > BNXT_HWRM_MAX_REQ_LEN) {
+ if (msg_len > bp->hwrm_max_ext_req_len ||
+ !bp->hwrm_short_cmd_req_addr)
+ return -EINVAL;
+ }
+
+ if (bnxt_kong_hwrm_message(bp, req)) {
+ dst = BNXT_HWRM_CHNL_KONG;
+ bar_offset = BNXT_GRCPF_REG_KONG_COMM;
+ doorbell_offset = BNXT_GRCPF_REG_KONG_COMM_TRIGGER;
+ }
+
+ memset(resp, 0, PAGE_SIZE);
+ cp_ring_id = le16_to_cpu(req->cmpl_ring);
+ intr_process = (cp_ring_id == INVALID_HW_RING_ID) ? 0 : 1;
+
+ req->seq_id = cpu_to_le16(bnxt_get_hwrm_seq_id(bp, dst));
+ /* currently supports only one outstanding message */
+ if (intr_process)
+ bp->hwrm_intr_seq_id = le16_to_cpu(req->seq_id);
+
+ if ((bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) ||
+ msg_len > BNXT_HWRM_MAX_REQ_LEN) {
+ void *short_cmd_req = bp->hwrm_short_cmd_req_addr;
+ u16 max_msg_len;
+
+ /* Set boundary for maximum extended request length for short
+ * cmd format. If passed up from device use the max supported
+ * internal req length.
+ */
+ max_msg_len = bp->hwrm_max_ext_req_len;
+
+ memcpy(short_cmd_req, req, msg_len);
+ if (msg_len < max_msg_len)
+ memset(short_cmd_req + msg_len, 0,
+ max_msg_len - msg_len);
+
+ short_input.req_type = req->req_type;
+ short_input.signature =
+ cpu_to_le16(SHORT_REQ_SIGNATURE_SHORT_CMD);
+ short_input.size = cpu_to_le16(msg_len);
+ short_input.req_addr =
+ cpu_to_le64(bp->hwrm_short_cmd_req_dma_addr);
+
+ data = (u32 *)&short_input;
+ msg_len = sizeof(short_input);
+
+ /* Sync memory write before updating doorbell */
+ wmb();
+
+ max_req_len = BNXT_HWRM_SHORT_REQ_LEN;
+ }
+
+ /* Write request msg to hwrm channel */
+ __iowrite32_copy(bp->bar0 + bar_offset, data, msg_len / 4);
+
+ for (i = msg_len; i < max_req_len; i += 4)
+ writel(0, bp->bar0 + bar_offset + i);
+
+ /* Ring channel doorbell */
+ writel(1, bp->bar0 + doorbell_offset);
+
+ if (!pci_is_enabled(bp->pdev))
+ return -ENODEV;
+
+ if (!timeout)
+ timeout = DFLT_HWRM_CMD_TIMEOUT;
+ /* Limit timeout to an upper limit */
+ timeout = min(timeout, HWRM_CMD_MAX_TIMEOUT);
+ /* convert timeout to usec */
+ timeout *= 1000;
+
+ i = 0;
+ /* Short timeout for the first few iterations:
+ * number of loops = number of loops for short timeout +
+ * number of loops for standard timeout.
+ */
+ tmo_count = HWRM_SHORT_TIMEOUT_COUNTER;
+ timeout = timeout - HWRM_SHORT_MIN_TIMEOUT * HWRM_SHORT_TIMEOUT_COUNTER;
+ tmo_count += DIV_ROUND_UP(timeout, HWRM_MIN_TIMEOUT);
+
+ if (intr_process) {
+ u16 seq_id = bp->hwrm_intr_seq_id;
+
+ /* Wait until hwrm response cmpl interrupt is processed */
+ while (bp->hwrm_intr_seq_id != (u16)~seq_id &&
+ i++ < tmo_count) {
+ /* Abort the wait for completion if the FW health
+ * check has failed.
+ */
+ if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
+ return -EBUSY;
+ /* on first few passes, just barely sleep */
+ if (i < HWRM_SHORT_TIMEOUT_COUNTER) {
+ usleep_range(HWRM_SHORT_MIN_TIMEOUT,
+ HWRM_SHORT_MAX_TIMEOUT);
+ } else {
+ if (HWRM_WAIT_MUST_ABORT(bp, req))
+ break;
+ usleep_range(HWRM_MIN_TIMEOUT,
+ HWRM_MAX_TIMEOUT);
+ }
+ }
+
+ if (bp->hwrm_intr_seq_id != (u16)~seq_id) {
+ if (!silent)
+ netdev_err(bp->dev, "Resp cmpl intr err msg: 0x%x\n",
+ le16_to_cpu(req->req_type));
+ return -EBUSY;
+ }
+ len = le16_to_cpu(resp->resp_len);
+ valid = ((u8 *)resp) + len - 1;
+ } else {
+ int j;
+
+ /* Check if response len is updated */
+ for (i = 0; i < tmo_count; i++) {
+ /* Abort the wait for completion if the FW health
+ * check has failed.
+ */
+ if (test_bit(BNXT_STATE_FW_FATAL_COND, &bp->state))
+ return -EBUSY;
+ len = le16_to_cpu(resp->resp_len);
+ if (len)
+ break;
+ /* on first few passes, just barely sleep */
+ if (i < HWRM_SHORT_TIMEOUT_COUNTER) {
+ usleep_range(HWRM_SHORT_MIN_TIMEOUT,
+ HWRM_SHORT_MAX_TIMEOUT);
+ } else {
+ if (HWRM_WAIT_MUST_ABORT(bp, req))
+ goto timeout_abort;
+ usleep_range(HWRM_MIN_TIMEOUT,
+ HWRM_MAX_TIMEOUT);
+ }
+ }
+
+ if (i >= tmo_count) {
+timeout_abort:
+ if (!silent)
+ netdev_err(bp->dev, "Error (timeout: %d) msg {0x%x 0x%x} len:%d\n",
+ HWRM_TOTAL_TIMEOUT(i),
+ le16_to_cpu(req->req_type),
+ le16_to_cpu(req->seq_id), len);
+ return -EBUSY;
+ }
+
+ /* Last byte of resp contains valid bit */
+ valid = ((u8 *)resp) + len - 1;
+ for (j = 0; j < HWRM_VALID_BIT_DELAY_USEC; j++) {
+ /* make sure we read from updated DMA memory */
+ dma_rmb();
+ if (*valid)
+ break;
+ usleep_range(1, 5);
+ }
+
+ if (j >= HWRM_VALID_BIT_DELAY_USEC) {
+ if (!silent)
+ netdev_err(bp->dev, "Error (timeout: %d) msg {0x%x 0x%x} len:%d v:%d\n",
+ HWRM_TOTAL_TIMEOUT(i),
+ le16_to_cpu(req->req_type),
+ le16_to_cpu(req->seq_id), len,
+ *valid);
+ return -EBUSY;
+ }
+ }
+
+ /* Zero valid bit for compatibility. Valid bit in an older spec
+ * may become a new field in a newer spec. We must make sure that
+ * a new field not implemented by old spec will read zero.
+ */
+ *valid = 0;
+ rc = le16_to_cpu(resp->error_code);
+ if (rc && !silent)
+ netdev_err(bp->dev, "hwrm req_type 0x%x seq id 0x%x error 0x%x\n",
+ le16_to_cpu(resp->req_type),
+ le16_to_cpu(resp->seq_id), rc);
+ return bnxt_hwrm_to_stderr(rc);
+}
+
+int _hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
+{
+ return bnxt_hwrm_do_send_msg(bp, msg, msg_len, timeout, false);
+}
+
+int _hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 msg_len,
+ int timeout)
+{
+ return bnxt_hwrm_do_send_msg(bp, msg, msg_len, timeout, true);
+}
+
+int hwrm_send_message(struct bnxt *bp, void *msg, u32 msg_len, int timeout)
+{
+ int rc;
+
+ mutex_lock(&bp->hwrm_cmd_lock);
+ rc = _hwrm_send_message(bp, msg, msg_len, timeout);
+ mutex_unlock(&bp->hwrm_cmd_lock);
+ return rc;
+}
+
+int hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 msg_len,
+ int timeout)
+{
+ int rc;
+
+ mutex_lock(&bp->hwrm_cmd_lock);
+ rc = bnxt_hwrm_do_send_msg(bp, msg, msg_len, timeout, true);
+ mutex_unlock(&bp->hwrm_cmd_lock);
+ return rc;
+}
new file mode 100644
@@ -0,0 +1,100 @@
+/* Broadcom NetXtreme-C/E network driver.
+ *
+ * Copyright (c) 2020 Broadcom Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef BNXT_HWRM_H
+#define BNXT_HWRM_H
+
+#include "bnxt_hsi.h"
+
+#define BNXT_HWRM_MAX_REQ_LEN (bp->hwrm_max_req_len)
+#define BNXT_HWRM_SHORT_REQ_LEN sizeof(struct hwrm_short_input)
+#define HWRM_CMD_MAX_TIMEOUT 40000
+#define SHORT_HWRM_CMD_TIMEOUT 20
+#define HWRM_CMD_TIMEOUT (bp->hwrm_cmd_timeout)
+#define HWRM_RESET_TIMEOUT ((HWRM_CMD_TIMEOUT) * 4)
+#define HWRM_COREDUMP_TIMEOUT ((HWRM_CMD_TIMEOUT) * 12)
+#define BNXT_HWRM_REQ_MAX_SIZE 128
+#define BNXT_HWRM_REQS_PER_PAGE (BNXT_PAGE_SIZE / \
+ BNXT_HWRM_REQ_MAX_SIZE)
+#define HWRM_SHORT_MIN_TIMEOUT 3
+#define HWRM_SHORT_MAX_TIMEOUT 10
+#define HWRM_SHORT_TIMEOUT_COUNTER 5
+
+#define HWRM_MIN_TIMEOUT 25
+#define HWRM_MAX_TIMEOUT 40
+
+#define HWRM_WAIT_MUST_ABORT(bp, req) \
+ (le16_to_cpu((req)->req_type) != HWRM_VER_GET && \
+ !bnxt_is_fw_healthy(bp))
+
+#define HWRM_TOTAL_TIMEOUT(n) (((n) <= HWRM_SHORT_TIMEOUT_COUNTER) ? \
+ ((n) * HWRM_SHORT_MIN_TIMEOUT) : \
+ (HWRM_SHORT_TIMEOUT_COUNTER * HWRM_SHORT_MIN_TIMEOUT + \
+ ((n) - HWRM_SHORT_TIMEOUT_COUNTER) * HWRM_MIN_TIMEOUT))
+
+#define HWRM_VALID_BIT_DELAY_USEC 150
+
+#define BNXT_HWRM_CHNL_CHIMP 0
+#define BNXT_HWRM_CHNL_KONG 1
+
+static inline bool bnxt_cfa_hwrm_message(u16 req_type)
+{
+ switch (req_type) {
+ case HWRM_CFA_ENCAP_RECORD_ALLOC:
+ case HWRM_CFA_ENCAP_RECORD_FREE:
+ case HWRM_CFA_DECAP_FILTER_ALLOC:
+ case HWRM_CFA_DECAP_FILTER_FREE:
+ case HWRM_CFA_EM_FLOW_ALLOC:
+ case HWRM_CFA_EM_FLOW_FREE:
+ case HWRM_CFA_EM_FLOW_CFG:
+ case HWRM_CFA_FLOW_ALLOC:
+ case HWRM_CFA_FLOW_FREE:
+ case HWRM_CFA_FLOW_INFO:
+ case HWRM_CFA_FLOW_FLUSH:
+ case HWRM_CFA_FLOW_STATS:
+ case HWRM_CFA_METER_PROFILE_ALLOC:
+ case HWRM_CFA_METER_PROFILE_FREE:
+ case HWRM_CFA_METER_PROFILE_CFG:
+ case HWRM_CFA_METER_INSTANCE_ALLOC:
+ case HWRM_CFA_METER_INSTANCE_FREE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static inline bool bnxt_kong_hwrm_message(struct bnxt *bp, struct input *req)
+{
+ return (bp->fw_cap & BNXT_FW_CAP_KONG_MB_CHNL &&
+ (bnxt_cfa_hwrm_message(le16_to_cpu(req->req_type)) ||
+ le16_to_cpu(req->target_id) == HWRM_TARGET_ID_KONG));
+}
+
+static inline void *bnxt_get_hwrm_resp_addr(struct bnxt *bp, void *req)
+{
+ return bp->hwrm_cmd_resp_addr;
+}
+
+static inline u16 bnxt_get_hwrm_seq_id(struct bnxt *bp, u16 dst)
+{
+ u16 seq_id;
+
+ if (dst == BNXT_HWRM_CHNL_CHIMP)
+ seq_id = bp->hwrm_cmd_seq++;
+ else
+ seq_id = bp->hwrm_cmd_kong_seq++;
+ return seq_id;
+}
+
+void bnxt_hwrm_cmd_hdr_init(struct bnxt *, void *, u16, u16, u16);
+int _hwrm_send_message(struct bnxt *bp, void *msg, u32 len, int timeout);
+int _hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 len, int timeout);
+int hwrm_send_message(struct bnxt *bp, void *msg, u32 len, int timeout);
+int hwrm_send_message_silent(struct bnxt *bp, void *msg, u32 len, int timeout);
+#endif
@@ -18,6 +18,7 @@
#include <linux/ptp_classify.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
+#include "bnxt_hwrm.h"
#include "bnxt_ptp.h"
int bnxt_ptp_parse(struct sk_buff *skb, u16 *seq_id, u16 *hdr_off)
@@ -17,6 +17,7 @@
#include <linux/etherdevice.h>
#include "bnxt_hsi.h"
#include "bnxt.h"
+#include "bnxt_hwrm.h"
#include "bnxt_ulp.h"
#include "bnxt_sriov.h"
#include "bnxt_vfr.h"
@@ -22,6 +22,7 @@
#include "bnxt_hsi.h"
#include "bnxt.h"
+#include "bnxt_hwrm.h"
#include "bnxt_sriov.h"
#include "bnxt_tc.h"
#include "bnxt_vfr.h"
@@ -22,6 +22,7 @@
#include "bnxt_hsi.h"
#include "bnxt.h"
+#include "bnxt_hwrm.h"
#include "bnxt_ulp.h"
static int bnxt_register_dev(struct bnxt_en_dev *edev, int ulp_id,
@@ -15,6 +15,7 @@
#include "bnxt_hsi.h"
#include "bnxt.h"
+#include "bnxt_hwrm.h"
#include "bnxt_vfr.h"
#include "bnxt_devlink.h"
#include "bnxt_tc.h"