Commit f9ff5782 authored by Edwin Peer's avatar Edwin Peer Committed by David S. Miller

bnxt_en: introduce new firmware message API based on DMA pools

This change constitutes a major step towards supporting multiple
firmware commands in flight by maintaining a separate response buffer
for the duration of each request. These firmware commands are also
known as Hardware Resource Manager (HWRM) commands.  Using separate
response buffers requires an API change in order for callers to be
able to free the buffer when done.

It is impossible to keep the existing APIs unchanged.  The existing
usage for a simple HWRM message request such as the following:

        struct input req = {0};
        bnxt_hwrm_cmd_hdr_init(bp, &req, REQ_TYPE, -1, -1);
        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
        if (rc)
                /* error */

changes to:

         struct input *req;
         rc = hwrm_req_init(bp, req, REQ_TYPE);
         if (rc)
                 /* error */
         rc = hwrm_req_send(bp, req); /* consumes req */
         if (rc)
                 /* error */

The key changes are:

1. The req is no longer allocated on the stack.
2. The caller must call hwrm_req_init() to allocate a req buffer and
   check for a valid buffer.
3. The req buffer is automatically released when hwrm_req_send() returns.
4. If the caller wants to check the firmware response, the caller must
   call hwrm_req_hold() to take ownership of the response buffer and
   release it afterwards using hwrm_req_drop().  The caller is no longer
   required to explicitly hold the hwrm_cmd_lock mutex to read the
   response.
5. Because the firmware commands and responses all have different sizes,
   some safeguards are added to the code.

This patch maintains legacy API compatibiltiy, implementing the old
API in terms of the new.  The follow-on patches will convert all
callers to use the new APIs.

v2: Fix redefined writeq with parisc .config
    Fix "cast from pointer to integer of different size" warning in
hwrm_calc_sentinel()
Signed-off-by: default avatarEdwin Peer <edwin.peer@broadcom.com>
Signed-off-by: default avatarMichael Chan <michael.chan@broadcom.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 3c8c20db
......@@ -3963,6 +3963,9 @@ static void bnxt_free_hwrm_resources(struct bnxt *bp)
bp->hwrm_cmd_resp_dma_addr);
bp->hwrm_cmd_resp_addr = NULL;
}
dma_pool_destroy(bp->hwrm_dma_pool);
bp->hwrm_dma_pool = NULL;
}
static int bnxt_alloc_hwrm_resources(struct bnxt *bp)
......@@ -3975,33 +3978,10 @@ static int bnxt_alloc_hwrm_resources(struct bnxt *bp)
if (!bp->hwrm_cmd_resp_addr)
return -ENOMEM;
return 0;
}
static void bnxt_free_hwrm_short_cmd_req(struct bnxt *bp)
{
if (bp->hwrm_short_cmd_req_addr) {
struct pci_dev *pdev = bp->pdev;
dma_free_coherent(&pdev->dev, bp->hwrm_max_ext_req_len,
bp->hwrm_short_cmd_req_addr,
bp->hwrm_short_cmd_req_dma_addr);
bp->hwrm_short_cmd_req_addr = NULL;
}
}
static int bnxt_alloc_hwrm_short_cmd_req(struct bnxt *bp)
{
struct pci_dev *pdev = bp->pdev;
if (bp->hwrm_short_cmd_req_addr)
return 0;
bp->hwrm_short_cmd_req_addr =
dma_alloc_coherent(&pdev->dev, bp->hwrm_max_ext_req_len,
&bp->hwrm_short_cmd_req_dma_addr,
GFP_KERNEL);
if (!bp->hwrm_short_cmd_req_addr)
bp->hwrm_dma_pool = dma_pool_create("bnxt_hwrm", &pdev->dev,
BNXT_HWRM_DMA_SIZE,
BNXT_HWRM_DMA_ALIGN, 0);
if (!bp->hwrm_dma_pool)
return -ENOMEM;
return 0;
......@@ -11654,12 +11634,6 @@ static int bnxt_fw_init_one_p1(struct bnxt *bp)
return rc;
}
if ((bp->fw_cap & BNXT_FW_CAP_SHORT_CMD) ||
bp->hwrm_max_ext_req_len > BNXT_HWRM_MAX_REQ_LEN) {
rc = bnxt_alloc_hwrm_short_cmd_req(bp);
if (rc)
return rc;
}
bnxt_nvm_cfg_ver_get(bp);
rc = bnxt_hwrm_func_reset(bp);
......@@ -12588,7 +12562,6 @@ static void bnxt_remove_one(struct pci_dev *pdev)
bnxt_clear_int_mode(bp);
bnxt_hwrm_func_drv_unrgtr(bp);
bnxt_free_hwrm_resources(bp);
bnxt_free_hwrm_short_cmd_req(bp);
bnxt_ethtool_free(bp);
bnxt_dcb_free(bp);
kfree(bp->edev);
......@@ -13188,7 +13161,6 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
init_err_pci_clean:
bnxt_hwrm_func_drv_unrgtr(bp);
bnxt_free_hwrm_short_cmd_req(bp);
bnxt_free_hwrm_resources(bp);
bnxt_ethtool_free(bp);
bnxt_ptp_clear(bp);
......
......@@ -1881,10 +1881,9 @@ struct bnxt {
u16 hwrm_cmd_seq;
u16 hwrm_cmd_kong_seq;
u16 hwrm_intr_seq_id;
void *hwrm_short_cmd_req_addr;
dma_addr_t hwrm_short_cmd_req_dma_addr;
void *hwrm_cmd_resp_addr;
dma_addr_t hwrm_cmd_resp_dma_addr;
struct dma_pool *hwrm_dma_pool;
struct rtnl_link_stats64 net_stats_prev;
struct bnxt_stats_mem port_stats;
......@@ -1984,7 +1983,7 @@ struct bnxt {
struct mutex sriov_lock;
#endif
#if BITS_PER_LONG == 32
#ifndef writeq
/* ensure atomic 64-bit doorbell writes on 32-bit systems. */
spinlock_t db_lock;
#endif
......@@ -2113,7 +2112,7 @@ static inline u32 bnxt_tx_avail(struct bnxt *bp, struct bnxt_tx_ring_info *txr)
((txr->tx_prod - txr->tx_cons) & bp->tx_ring_mask);
}
#if BITS_PER_LONG == 32
#ifndef writeq
#define writeq(val64, db) \
do { \
spin_lock(&bp->db_lock); \
......
......@@ -12,6 +12,26 @@
#include "bnxt_hsi.h"
enum bnxt_hwrm_ctx_flags {
/* Update the HWRM_API_FLAGS right below for any new non-internal bit added here */
BNXT_HWRM_INTERNAL_CTX_OWNED = BIT(0), /* caller owns the context */
BNXT_HWRM_INTERNAL_RESP_DIRTY = BIT(1), /* response contains data */
BNXT_HWRM_CTX_SILENT = BIT(2), /* squelch firmware errors */
BNXT_HWRM_FULL_WAIT = BIT(3), /* wait for full timeout of HWRM command */
};
#define HWRM_API_FLAGS (BNXT_HWRM_CTX_SILENT | BNXT_HWRM_FULL_WAIT)
struct bnxt_hwrm_ctx {
u64 sentinel;
dma_addr_t dma_handle;
struct output *resp;
struct input *req;
u32 req_len;
enum bnxt_hwrm_ctx_flags flags;
unsigned int timeout;
};
#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
......@@ -19,7 +39,17 @@
#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_TARGET 0xffff
#define BNXT_HWRM_NO_CMPL_RING -1
#define BNXT_HWRM_REQ_MAX_SIZE 128
#define BNXT_HWRM_DMA_SIZE (2 * PAGE_SIZE) /* space for req+resp */
#define BNXT_HWRM_RESP_RESERVED PAGE_SIZE
#define BNXT_HWRM_RESP_OFFSET (BNXT_HWRM_DMA_SIZE - \
BNXT_HWRM_RESP_RESERVED)
#define BNXT_HWRM_CTX_OFFSET (BNXT_HWRM_RESP_OFFSET - \
sizeof(struct bnxt_hwrm_ctx))
#define BNXT_HWRM_DMA_ALIGN 16
#define BNXT_HWRM_SENTINEL 0xb6e1f68a12e9a7eb /* arbitrary value */
#define BNXT_HWRM_REQS_PER_PAGE (BNXT_PAGE_SIZE / \
BNXT_HWRM_REQ_MAX_SIZE)
#define HWRM_SHORT_MIN_TIMEOUT 3
......@@ -29,14 +59,17 @@
#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 && \
#define HWRM_WAIT_MUST_ABORT(bp, ctx) \
(le16_to_cpu((ctx)->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))
static inline unsigned int hwrm_total_timeout(unsigned int n)
{
return 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
......@@ -97,4 +130,13 @@ 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);
int __hwrm_req_init(struct bnxt *bp, void **req, u16 req_type, u32 req_len);
#define hwrm_req_init(bp, req, req_type) \
__hwrm_req_init((bp), (void **)&(req), (req_type), sizeof(*(req)))
void *hwrm_req_hold(struct bnxt *bp, void *req);
void hwrm_req_drop(struct bnxt *bp, void *req);
void hwrm_req_flags(struct bnxt *bp, void *req, enum bnxt_hwrm_ctx_flags flags);
void hwrm_req_timeout(struct bnxt *bp, void *req, unsigned int timeout);
int hwrm_req_send(struct bnxt *bp, void *req);
int hwrm_req_send_silent(struct bnxt *bp, void *req);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment