net-next/hinic: Add api cmd commands
Add the api cmd commands for sending management messages to the nic. Signed-off-by: Aviad Krawczyk <aviad.krawczyk@huawei.com> Signed-off-by: Zhao Chen <zhaochen6@huawei.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
6dd8b68214
commit
0ac599c790
|
@ -25,7 +25,9 @@
|
|||
#include <linux/jiffies.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/barrier.h>
|
||||
|
||||
#include "hinic_hw_csr.h"
|
||||
#include "hinic_hw_if.h"
|
||||
|
@ -45,14 +47,313 @@
|
|||
|
||||
#define API_CMD_BUF_SIZE 2048
|
||||
|
||||
/* Sizes of the members in hinic_api_cmd_cell */
|
||||
#define API_CMD_CELL_DESC_SIZE 8
|
||||
#define API_CMD_CELL_DATA_ADDR_SIZE 8
|
||||
|
||||
#define API_CMD_CELL_ALIGNMENT 8
|
||||
|
||||
#define API_CMD_TIMEOUT 1000
|
||||
|
||||
#define MASKED_IDX(chain, idx) ((idx) & ((chain)->num_cells - 1))
|
||||
|
||||
#define SIZE_8BYTES(size) (ALIGN((size), 8) >> 3)
|
||||
#define SIZE_4BYTES(size) (ALIGN((size), 4) >> 2)
|
||||
|
||||
#define RD_DMA_ATTR_DEFAULT 0
|
||||
#define WR_DMA_ATTR_DEFAULT 0
|
||||
|
||||
enum api_cmd_data_format {
|
||||
SGE_DATA = 1, /* cell data is passed by hw address */
|
||||
};
|
||||
|
||||
enum api_cmd_type {
|
||||
API_CMD_WRITE = 0,
|
||||
};
|
||||
|
||||
enum api_cmd_bypass {
|
||||
NO_BYPASS = 0,
|
||||
BYPASS = 1,
|
||||
};
|
||||
|
||||
enum api_cmd_xor_chk_level {
|
||||
XOR_CHK_DIS = 0,
|
||||
|
||||
XOR_CHK_ALL = 3,
|
||||
};
|
||||
|
||||
static u8 xor_chksum_set(void *data)
|
||||
{
|
||||
int idx;
|
||||
u8 *val, checksum = 0;
|
||||
|
||||
val = data;
|
||||
|
||||
for (idx = 0; idx < 7; idx++)
|
||||
checksum ^= val[idx];
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
static void set_prod_idx(struct hinic_api_cmd_chain *chain)
|
||||
{
|
||||
enum hinic_api_cmd_chain_type chain_type = chain->chain_type;
|
||||
struct hinic_hwif *hwif = chain->hwif;
|
||||
u32 addr, prod_idx;
|
||||
|
||||
addr = HINIC_CSR_API_CMD_CHAIN_PI_ADDR(chain_type);
|
||||
prod_idx = hinic_hwif_read_reg(hwif, addr);
|
||||
|
||||
prod_idx = HINIC_API_CMD_PI_CLEAR(prod_idx, IDX);
|
||||
|
||||
prod_idx |= HINIC_API_CMD_PI_SET(chain->prod_idx, IDX);
|
||||
|
||||
hinic_hwif_write_reg(hwif, addr, prod_idx);
|
||||
}
|
||||
|
||||
static u32 get_hw_cons_idx(struct hinic_api_cmd_chain *chain)
|
||||
{
|
||||
u32 addr, val;
|
||||
|
||||
addr = HINIC_CSR_API_CMD_STATUS_ADDR(chain->chain_type);
|
||||
val = hinic_hwif_read_reg(chain->hwif, addr);
|
||||
|
||||
return HINIC_API_CMD_STATUS_GET(val, CONS_IDX);
|
||||
}
|
||||
|
||||
/**
|
||||
* chain_busy - check if the chain is still processing last requests
|
||||
* @chain: chain to check
|
||||
*
|
||||
* Return 0 - Success, negative - Failure
|
||||
**/
|
||||
static int chain_busy(struct hinic_api_cmd_chain *chain)
|
||||
{
|
||||
struct hinic_hwif *hwif = chain->hwif;
|
||||
struct pci_dev *pdev = hwif->pdev;
|
||||
u32 prod_idx;
|
||||
|
||||
switch (chain->chain_type) {
|
||||
case HINIC_API_CMD_WRITE_TO_MGMT_CPU:
|
||||
chain->cons_idx = get_hw_cons_idx(chain);
|
||||
prod_idx = chain->prod_idx;
|
||||
|
||||
/* check for a space for a new command */
|
||||
if (chain->cons_idx == MASKED_IDX(chain, prod_idx + 1)) {
|
||||
dev_err(&pdev->dev, "API CMD chain %d is busy\n",
|
||||
chain->chain_type);
|
||||
return -EBUSY;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&pdev->dev, "Unknown API CMD Chain type\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_cell_data_size - get the data size of a specific cell type
|
||||
* @type: chain type
|
||||
*
|
||||
* Return the data(Desc + Address) size in the cell
|
||||
**/
|
||||
static u8 get_cell_data_size(enum hinic_api_cmd_chain_type type)
|
||||
{
|
||||
u8 cell_data_size = 0;
|
||||
|
||||
switch (type) {
|
||||
case HINIC_API_CMD_WRITE_TO_MGMT_CPU:
|
||||
cell_data_size = ALIGN(API_CMD_CELL_DESC_SIZE +
|
||||
API_CMD_CELL_DATA_ADDR_SIZE,
|
||||
API_CMD_CELL_ALIGNMENT);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cell_data_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare_cell_ctrl - prepare the ctrl of the cell for the command
|
||||
* @cell_ctrl: the control of the cell to set the control value into it
|
||||
* @data_size: the size of the data in the cell
|
||||
**/
|
||||
static void prepare_cell_ctrl(u64 *cell_ctrl, u16 data_size)
|
||||
{
|
||||
u8 chksum;
|
||||
u64 ctrl;
|
||||
|
||||
ctrl = HINIC_API_CMD_CELL_CTRL_SET(SIZE_8BYTES(data_size), DATA_SZ) |
|
||||
HINIC_API_CMD_CELL_CTRL_SET(RD_DMA_ATTR_DEFAULT, RD_DMA_ATTR) |
|
||||
HINIC_API_CMD_CELL_CTRL_SET(WR_DMA_ATTR_DEFAULT, WR_DMA_ATTR);
|
||||
|
||||
chksum = xor_chksum_set(&ctrl);
|
||||
|
||||
ctrl |= HINIC_API_CMD_CELL_CTRL_SET(chksum, XOR_CHKSUM);
|
||||
|
||||
/* The data in the HW should be in Big Endian Format */
|
||||
*cell_ctrl = cpu_to_be64(ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare_api_cmd - prepare API CMD command
|
||||
* @chain: chain for the command
|
||||
* @dest: destination node on the card that will receive the command
|
||||
* @cmd: command data
|
||||
* @cmd_size: the command size
|
||||
**/
|
||||
static void prepare_api_cmd(struct hinic_api_cmd_chain *chain,
|
||||
enum hinic_node_id dest,
|
||||
void *cmd, u16 cmd_size)
|
||||
{
|
||||
struct hinic_api_cmd_cell *cell = chain->curr_node;
|
||||
struct hinic_api_cmd_cell_ctxt *cell_ctxt;
|
||||
struct hinic_hwif *hwif = chain->hwif;
|
||||
struct pci_dev *pdev = hwif->pdev;
|
||||
|
||||
cell_ctxt = &chain->cell_ctxt[chain->prod_idx];
|
||||
|
||||
switch (chain->chain_type) {
|
||||
case HINIC_API_CMD_WRITE_TO_MGMT_CPU:
|
||||
cell->desc = HINIC_API_CMD_DESC_SET(SGE_DATA, API_TYPE) |
|
||||
HINIC_API_CMD_DESC_SET(API_CMD_WRITE, RD_WR) |
|
||||
HINIC_API_CMD_DESC_SET(NO_BYPASS, MGMT_BYPASS);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&pdev->dev, "unknown Chain type\n");
|
||||
return;
|
||||
}
|
||||
|
||||
cell->desc |= HINIC_API_CMD_DESC_SET(dest, DEST) |
|
||||
HINIC_API_CMD_DESC_SET(SIZE_4BYTES(cmd_size), SIZE);
|
||||
|
||||
cell->desc |= HINIC_API_CMD_DESC_SET(xor_chksum_set(&cell->desc),
|
||||
XOR_CHKSUM);
|
||||
|
||||
/* The data in the HW should be in Big Endian Format */
|
||||
cell->desc = cpu_to_be64(cell->desc);
|
||||
|
||||
memcpy(cell_ctxt->api_cmd_vaddr, cmd, cmd_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare_cell - prepare cell ctrl and cmd in the current cell
|
||||
* @chain: chain for the command
|
||||
* @dest: destination node on the card that will receive the command
|
||||
* @cmd: command data
|
||||
* @cmd_size: the command size
|
||||
*
|
||||
* Return 0 - Success, negative - Failure
|
||||
**/
|
||||
static void prepare_cell(struct hinic_api_cmd_chain *chain,
|
||||
enum hinic_node_id dest,
|
||||
void *cmd, u16 cmd_size)
|
||||
{
|
||||
struct hinic_api_cmd_cell *curr_node = chain->curr_node;
|
||||
u16 data_size = get_cell_data_size(chain->chain_type);
|
||||
|
||||
prepare_cell_ctrl(&curr_node->ctrl, data_size);
|
||||
prepare_api_cmd(chain, dest, cmd, cmd_size);
|
||||
}
|
||||
|
||||
static inline void cmd_chain_prod_idx_inc(struct hinic_api_cmd_chain *chain)
|
||||
{
|
||||
chain->prod_idx = MASKED_IDX(chain, chain->prod_idx + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* api_cmd_status_update - update the status in the chain struct
|
||||
* @chain: chain to update
|
||||
**/
|
||||
static void api_cmd_status_update(struct hinic_api_cmd_chain *chain)
|
||||
{
|
||||
enum hinic_api_cmd_chain_type chain_type;
|
||||
struct hinic_api_cmd_status *wb_status;
|
||||
struct hinic_hwif *hwif = chain->hwif;
|
||||
struct pci_dev *pdev = hwif->pdev;
|
||||
u64 status_header;
|
||||
u32 status;
|
||||
|
||||
wb_status = chain->wb_status;
|
||||
status_header = be64_to_cpu(wb_status->header);
|
||||
|
||||
status = be32_to_cpu(wb_status->status);
|
||||
if (HINIC_API_CMD_STATUS_GET(status, CHKSUM_ERR)) {
|
||||
dev_err(&pdev->dev, "API CMD status: Xor check error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
chain_type = HINIC_API_CMD_STATUS_HEADER_GET(status_header, CHAIN_ID);
|
||||
if (chain_type >= HINIC_API_CMD_MAX) {
|
||||
dev_err(&pdev->dev, "unknown API CMD Chain %d\n", chain_type);
|
||||
return;
|
||||
}
|
||||
|
||||
chain->cons_idx = HINIC_API_CMD_STATUS_GET(status, CONS_IDX);
|
||||
}
|
||||
|
||||
/**
|
||||
* wait_for_status_poll - wait for write to api cmd command to complete
|
||||
* @chain: the chain of the command
|
||||
*
|
||||
* Return 0 - Success, negative - Failure
|
||||
**/
|
||||
static int wait_for_status_poll(struct hinic_api_cmd_chain *chain)
|
||||
{
|
||||
int err = -ETIMEDOUT;
|
||||
unsigned long end;
|
||||
|
||||
end = jiffies + msecs_to_jiffies(API_CMD_TIMEOUT);
|
||||
do {
|
||||
api_cmd_status_update(chain);
|
||||
|
||||
/* wait for CI to be updated - sign for completion */
|
||||
if (chain->cons_idx == chain->prod_idx) {
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
msleep(20);
|
||||
} while (time_before(jiffies, end));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* wait_for_api_cmd_completion - wait for command to complete
|
||||
* @chain: chain for the command
|
||||
*
|
||||
* Return 0 - Success, negative - Failure
|
||||
**/
|
||||
static int wait_for_api_cmd_completion(struct hinic_api_cmd_chain *chain)
|
||||
{
|
||||
struct hinic_hwif *hwif = chain->hwif;
|
||||
struct pci_dev *pdev = hwif->pdev;
|
||||
int err;
|
||||
|
||||
switch (chain->chain_type) {
|
||||
case HINIC_API_CMD_WRITE_TO_MGMT_CPU:
|
||||
err = wait_for_status_poll(chain);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "API CMD Poll status timeout\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&pdev->dev, "unknown API CMD Chain type\n");
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* api_cmd - API CMD command
|
||||
* @chain: chain for the command
|
||||
|
@ -65,8 +366,30 @@ enum api_cmd_xor_chk_level {
|
|||
static int api_cmd(struct hinic_api_cmd_chain *chain,
|
||||
enum hinic_node_id dest, u8 *cmd, u16 cmd_size)
|
||||
{
|
||||
/* should be implemented */
|
||||
return -EINVAL;
|
||||
struct hinic_api_cmd_cell_ctxt *ctxt;
|
||||
int err;
|
||||
|
||||
down(&chain->sem);
|
||||
if (chain_busy(chain)) {
|
||||
up(&chain->sem);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
prepare_cell(chain, dest, cmd, cmd_size);
|
||||
cmd_chain_prod_idx_inc(chain);
|
||||
|
||||
wmb(); /* inc pi before issue the command */
|
||||
|
||||
set_prod_idx(chain); /* issue the command */
|
||||
|
||||
ctxt = &chain->cell_ctxt[chain->prod_idx];
|
||||
|
||||
chain->curr_node = ctxt->cell_vaddr;
|
||||
|
||||
err = wait_for_api_cmd_completion(chain);
|
||||
|
||||
up(&chain->sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -491,6 +814,8 @@ static int api_chain_init(struct hinic_api_cmd_chain *chain,
|
|||
chain->prod_idx = 0;
|
||||
chain->cons_idx = 0;
|
||||
|
||||
sema_init(&chain->sem, 1);
|
||||
|
||||
cell_ctxt_size = chain->num_cells * sizeof(*chain->cell_ctxt);
|
||||
chain->cell_ctxt = devm_kzalloc(&pdev->dev, cell_ctxt_size, GFP_KERNEL);
|
||||
if (!chain->cell_ctxt)
|
||||
|
|
|
@ -17,9 +17,22 @@
|
|||
#define HINIC_HW_API_CMD_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/semaphore.h>
|
||||
|
||||
#include "hinic_hw_if.h"
|
||||
|
||||
#define HINIC_API_CMD_PI_IDX_SHIFT 0
|
||||
|
||||
#define HINIC_API_CMD_PI_IDX_MASK 0xFFFFFF
|
||||
|
||||
#define HINIC_API_CMD_PI_SET(val, member) \
|
||||
(((u32)(val) & HINIC_API_CMD_PI_##member##_MASK) << \
|
||||
HINIC_API_CMD_PI_##member##_SHIFT)
|
||||
|
||||
#define HINIC_API_CMD_PI_CLEAR(val, member) \
|
||||
((val) & (~(HINIC_API_CMD_PI_##member##_MASK \
|
||||
<< HINIC_API_CMD_PI_##member##_SHIFT)))
|
||||
|
||||
#define HINIC_API_CMD_CHAIN_REQ_RESTART_SHIFT 1
|
||||
|
||||
#define HINIC_API_CMD_CHAIN_REQ_RESTART_MASK 0x1
|
||||
|
@ -58,6 +71,56 @@
|
|||
((val) & (~(HINIC_API_CMD_CHAIN_CTRL_##member##_MASK \
|
||||
<< HINIC_API_CMD_CHAIN_CTRL_##member##_SHIFT)))
|
||||
|
||||
#define HINIC_API_CMD_CELL_CTRL_DATA_SZ_SHIFT 0
|
||||
#define HINIC_API_CMD_CELL_CTRL_RD_DMA_ATTR_SHIFT 16
|
||||
#define HINIC_API_CMD_CELL_CTRL_WR_DMA_ATTR_SHIFT 24
|
||||
#define HINIC_API_CMD_CELL_CTRL_XOR_CHKSUM_SHIFT 56
|
||||
|
||||
#define HINIC_API_CMD_CELL_CTRL_DATA_SZ_MASK 0x3F
|
||||
#define HINIC_API_CMD_CELL_CTRL_RD_DMA_ATTR_MASK 0x3F
|
||||
#define HINIC_API_CMD_CELL_CTRL_WR_DMA_ATTR_MASK 0x3F
|
||||
#define HINIC_API_CMD_CELL_CTRL_XOR_CHKSUM_MASK 0xFF
|
||||
|
||||
#define HINIC_API_CMD_CELL_CTRL_SET(val, member) \
|
||||
((((u64)val) & HINIC_API_CMD_CELL_CTRL_##member##_MASK) << \
|
||||
HINIC_API_CMD_CELL_CTRL_##member##_SHIFT)
|
||||
|
||||
#define HINIC_API_CMD_DESC_API_TYPE_SHIFT 0
|
||||
#define HINIC_API_CMD_DESC_RD_WR_SHIFT 1
|
||||
#define HINIC_API_CMD_DESC_MGMT_BYPASS_SHIFT 2
|
||||
#define HINIC_API_CMD_DESC_DEST_SHIFT 32
|
||||
#define HINIC_API_CMD_DESC_SIZE_SHIFT 40
|
||||
#define HINIC_API_CMD_DESC_XOR_CHKSUM_SHIFT 56
|
||||
|
||||
#define HINIC_API_CMD_DESC_API_TYPE_MASK 0x1
|
||||
#define HINIC_API_CMD_DESC_RD_WR_MASK 0x1
|
||||
#define HINIC_API_CMD_DESC_MGMT_BYPASS_MASK 0x1
|
||||
#define HINIC_API_CMD_DESC_DEST_MASK 0x1F
|
||||
#define HINIC_API_CMD_DESC_SIZE_MASK 0x7FF
|
||||
#define HINIC_API_CMD_DESC_XOR_CHKSUM_MASK 0xFF
|
||||
|
||||
#define HINIC_API_CMD_DESC_SET(val, member) \
|
||||
((((u64)val) & HINIC_API_CMD_DESC_##member##_MASK) << \
|
||||
HINIC_API_CMD_DESC_##member##_SHIFT)
|
||||
|
||||
#define HINIC_API_CMD_STATUS_HEADER_CHAIN_ID_SHIFT 16
|
||||
|
||||
#define HINIC_API_CMD_STATUS_HEADER_CHAIN_ID_MASK 0xFF
|
||||
|
||||
#define HINIC_API_CMD_STATUS_HEADER_GET(val, member) \
|
||||
(((val) >> HINIC_API_CMD_STATUS_HEADER_##member##_SHIFT) & \
|
||||
HINIC_API_CMD_STATUS_HEADER_##member##_MASK)
|
||||
|
||||
#define HINIC_API_CMD_STATUS_CONS_IDX_SHIFT 0
|
||||
#define HINIC_API_CMD_STATUS_CHKSUM_ERR_SHIFT 28
|
||||
|
||||
#define HINIC_API_CMD_STATUS_CONS_IDX_MASK 0xFFFFFF
|
||||
#define HINIC_API_CMD_STATUS_CHKSUM_ERR_MASK 0x3
|
||||
|
||||
#define HINIC_API_CMD_STATUS_GET(val, member) \
|
||||
(((val) >> HINIC_API_CMD_STATUS_##member##_SHIFT) & \
|
||||
HINIC_API_CMD_STATUS_##member##_MASK)
|
||||
|
||||
enum hinic_api_cmd_chain_type {
|
||||
HINIC_API_CMD_WRITE_TO_MGMT_CPU = 2,
|
||||
|
||||
|
@ -122,6 +185,8 @@ struct hinic_api_cmd_chain {
|
|||
u32 prod_idx;
|
||||
u32 cons_idx;
|
||||
|
||||
struct semaphore sem;
|
||||
|
||||
struct hinic_api_cmd_cell_ctxt *cell_ctxt;
|
||||
|
||||
dma_addr_t wb_status_paddr;
|
||||
|
|
|
@ -56,7 +56,13 @@
|
|||
#define HINIC_CSR_API_CMD_CHAIN_CTRL_ADDR(idx) \
|
||||
(HINIC_CSR_API_CMD_BASE + 0x14 + (idx) * HINIC_CSR_API_CMD_STRIDE)
|
||||
|
||||
#define HINIC_CSR_API_CMD_CHAIN_PI_ADDR(idx) \
|
||||
(HINIC_CSR_API_CMD_BASE + 0x1C + (idx) * HINIC_CSR_API_CMD_STRIDE)
|
||||
|
||||
#define HINIC_CSR_API_CMD_CHAIN_REQ_ADDR(idx) \
|
||||
(HINIC_CSR_API_CMD_BASE + 0x20 + (idx) * HINIC_CSR_API_CMD_STRIDE)
|
||||
|
||||
#define HINIC_CSR_API_CMD_STATUS_ADDR(idx) \
|
||||
(HINIC_CSR_API_CMD_BASE + 0x30 + (idx) * HINIC_CSR_API_CMD_STRIDE)
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue