diff options
Diffstat (limited to 'drivers/net/ethernet/marvell/prestera/prestera_pci.c')
-rw-r--r-- | drivers/net/ethernet/marvell/prestera/prestera_pci.c | 114 |
1 files changed, 85 insertions, 29 deletions
diff --git a/drivers/net/ethernet/marvell/prestera/prestera_pci.c b/drivers/net/ethernet/marvell/prestera/prestera_pci.c index a250d394da38..5d4d410b07c8 100644 --- a/drivers/net/ethernet/marvell/prestera/prestera_pci.c +++ b/drivers/net/ethernet/marvell/prestera/prestera_pci.c @@ -14,10 +14,10 @@ #define PRESTERA_MSG_MAX_SIZE 1500 -#define PRESTERA_SUPP_FW_MAJ_VER 3 +#define PRESTERA_SUPP_FW_MAJ_VER 4 #define PRESTERA_SUPP_FW_MIN_VER 0 -#define PRESTERA_PREV_FW_MAJ_VER 2 +#define PRESTERA_PREV_FW_MAJ_VER 4 #define PRESTERA_PREV_FW_MIN_VER 0 #define PRESTERA_FW_PATH_FMT "mrvl/prestera/mvsw_prestera_fw-v%u.%u.img" @@ -102,23 +102,30 @@ struct prestera_fw_evtq_regs { u32 len; }; +#define PRESTERA_CMD_QNUM_MAX 4 + +struct prestera_fw_cmdq_regs { + u32 req_ctl; + u32 req_len; + u32 rcv_ctl; + u32 rcv_len; + u32 offs; + u32 len; +}; + struct prestera_fw_regs { u32 fw_ready; - u32 pad; u32 cmd_offs; u32 cmd_len; + u32 cmd_qnum; u32 evt_offs; u32 evt_qnum; - u32 cmd_req_ctl; - u32 cmd_req_len; - u32 cmd_rcv_ctl; - u32 cmd_rcv_len; - u32 fw_status; u32 rx_status; - struct prestera_fw_evtq_regs evtq_list[PRESTERA_EVT_QNUM_MAX]; + struct prestera_fw_cmdq_regs cmdq_list[PRESTERA_EVT_QNUM_MAX]; + struct prestera_fw_evtq_regs evtq_list[PRESTERA_CMD_QNUM_MAX]; }; #define PRESTERA_FW_REG_OFFSET(f) offsetof(struct prestera_fw_regs, f) @@ -130,14 +137,22 @@ struct prestera_fw_regs { #define PRESTERA_CMD_BUF_OFFS_REG PRESTERA_FW_REG_OFFSET(cmd_offs) #define PRESTERA_CMD_BUF_LEN_REG PRESTERA_FW_REG_OFFSET(cmd_len) +#define PRESTERA_CMD_QNUM_REG PRESTERA_FW_REG_OFFSET(cmd_qnum) #define PRESTERA_EVT_BUF_OFFS_REG PRESTERA_FW_REG_OFFSET(evt_offs) #define PRESTERA_EVT_QNUM_REG PRESTERA_FW_REG_OFFSET(evt_qnum) -#define PRESTERA_CMD_REQ_CTL_REG PRESTERA_FW_REG_OFFSET(cmd_req_ctl) -#define PRESTERA_CMD_REQ_LEN_REG PRESTERA_FW_REG_OFFSET(cmd_req_len) +#define PRESTERA_CMDQ_REG_OFFSET(q, f) \ + (PRESTERA_FW_REG_OFFSET(cmdq_list) + \ + (q) * sizeof(struct prestera_fw_cmdq_regs) + \ + offsetof(struct prestera_fw_cmdq_regs, f)) + +#define PRESTERA_CMDQ_REQ_CTL_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, req_ctl) +#define PRESTERA_CMDQ_REQ_LEN_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, req_len) +#define PRESTERA_CMDQ_RCV_CTL_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, rcv_ctl) +#define PRESTERA_CMDQ_RCV_LEN_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, rcv_len) +#define PRESTERA_CMDQ_OFFS_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, offs) +#define PRESTERA_CMDQ_LEN_REG(q) PRESTERA_CMDQ_REG_OFFSET(q, len) -#define PRESTERA_CMD_RCV_CTL_REG PRESTERA_FW_REG_OFFSET(cmd_rcv_ctl) -#define PRESTERA_CMD_RCV_LEN_REG PRESTERA_FW_REG_OFFSET(cmd_rcv_len) #define PRESTERA_FW_STATUS_REG PRESTERA_FW_REG_OFFSET(fw_status) #define PRESTERA_RX_STATUS_REG PRESTERA_FW_REG_OFFSET(rx_status) @@ -174,6 +189,13 @@ struct prestera_fw_evtq { size_t len; }; +struct prestera_fw_cmdq { + /* serialize access to dev->send_req */ + struct mutex cmd_mtx; + u8 __iomem *addr; + size_t len; +}; + struct prestera_fw { struct prestera_fw_rev rev_supp; const struct firmware *bin; @@ -183,9 +205,10 @@ struct prestera_fw { u8 __iomem *ldr_ring_buf; u32 ldr_buf_len; u32 ldr_wr_idx; - struct mutex cmd_mtx; /* serialize access to dev->send_req */ size_t cmd_mbox_len; u8 __iomem *cmd_mbox; + struct prestera_fw_cmdq cmd_queue[PRESTERA_CMD_QNUM_MAX]; + u8 cmd_qnum; struct prestera_fw_evtq evt_queue[PRESTERA_EVT_QNUM_MAX]; u8 evt_qnum; struct work_struct evt_work; @@ -324,7 +347,27 @@ static int prestera_fw_wait_reg32(struct prestera_fw *fw, u32 reg, u32 cmp, 1 * USEC_PER_MSEC, waitms * USEC_PER_MSEC); } -static int prestera_fw_cmd_send(struct prestera_fw *fw, +static void prestera_fw_cmdq_lock(struct prestera_fw *fw, u8 qid) +{ + mutex_lock(&fw->cmd_queue[qid].cmd_mtx); +} + +static void prestera_fw_cmdq_unlock(struct prestera_fw *fw, u8 qid) +{ + mutex_unlock(&fw->cmd_queue[qid].cmd_mtx); +} + +static u32 prestera_fw_cmdq_len(struct prestera_fw *fw, u8 qid) +{ + return fw->cmd_queue[qid].len; +} + +static u8 __iomem *prestera_fw_cmdq_buf(struct prestera_fw *fw, u8 qid) +{ + return fw->cmd_queue[qid].addr; +} + +static int prestera_fw_cmd_send(struct prestera_fw *fw, int qid, void *in_msg, size_t in_size, void *out_msg, size_t out_size, unsigned int waitms) @@ -335,30 +378,32 @@ static int prestera_fw_cmd_send(struct prestera_fw *fw, if (!waitms) waitms = PRESTERA_FW_CMD_DEFAULT_WAIT_MS; - if (ALIGN(in_size, 4) > fw->cmd_mbox_len) + if (ALIGN(in_size, 4) > prestera_fw_cmdq_len(fw, qid)) return -EMSGSIZE; /* wait for finish previous reply from FW */ - err = prestera_fw_wait_reg32(fw, PRESTERA_CMD_RCV_CTL_REG, 0, 30); + err = prestera_fw_wait_reg32(fw, PRESTERA_CMDQ_RCV_CTL_REG(qid), 0, 30); if (err) { dev_err(fw->dev.dev, "finish reply from FW is timed out\n"); return err; } - prestera_fw_write(fw, PRESTERA_CMD_REQ_LEN_REG, in_size); - memcpy_toio(fw->cmd_mbox, in_msg, in_size); + prestera_fw_write(fw, PRESTERA_CMDQ_REQ_LEN_REG(qid), in_size); + + memcpy_toio(prestera_fw_cmdq_buf(fw, qid), in_msg, in_size); - prestera_fw_write(fw, PRESTERA_CMD_REQ_CTL_REG, PRESTERA_CMD_F_REQ_SENT); + prestera_fw_write(fw, PRESTERA_CMDQ_REQ_CTL_REG(qid), + PRESTERA_CMD_F_REQ_SENT); /* wait for reply from FW */ - err = prestera_fw_wait_reg32(fw, PRESTERA_CMD_RCV_CTL_REG, + err = prestera_fw_wait_reg32(fw, PRESTERA_CMDQ_RCV_CTL_REG(qid), PRESTERA_CMD_F_REPL_SENT, waitms); if (err) { dev_err(fw->dev.dev, "reply from FW is timed out\n"); goto cmd_exit; } - ret_size = prestera_fw_read(fw, PRESTERA_CMD_RCV_LEN_REG); + ret_size = prestera_fw_read(fw, PRESTERA_CMDQ_RCV_LEN_REG(qid)); if (ret_size > out_size) { dev_err(fw->dev.dev, "ret_size (%u) > out_len(%zu)\n", ret_size, out_size); @@ -366,14 +411,15 @@ static int prestera_fw_cmd_send(struct prestera_fw *fw, goto cmd_exit; } - memcpy_fromio(out_msg, fw->cmd_mbox + in_size, ret_size); + memcpy_fromio(out_msg, prestera_fw_cmdq_buf(fw, qid) + in_size, ret_size); cmd_exit: - prestera_fw_write(fw, PRESTERA_CMD_REQ_CTL_REG, PRESTERA_CMD_F_REPL_RCVD); + prestera_fw_write(fw, PRESTERA_CMDQ_REQ_CTL_REG(qid), + PRESTERA_CMD_F_REPL_RCVD); return err; } -static int prestera_fw_send_req(struct prestera_device *dev, +static int prestera_fw_send_req(struct prestera_device *dev, int qid, void *in_msg, size_t in_size, void *out_msg, size_t out_size, unsigned int waitms) { @@ -382,9 +428,10 @@ static int prestera_fw_send_req(struct prestera_device *dev, fw = container_of(dev, struct prestera_fw, dev); - mutex_lock(&fw->cmd_mtx); - ret = prestera_fw_cmd_send(fw, in_msg, in_size, out_msg, out_size, waitms); - mutex_unlock(&fw->cmd_mtx); + prestera_fw_cmdq_lock(fw, qid); + ret = prestera_fw_cmd_send(fw, qid, in_msg, in_size, out_msg, out_size, + waitms); + prestera_fw_cmdq_unlock(fw, qid); return ret; } @@ -414,7 +461,16 @@ static int prestera_fw_init(struct prestera_fw *fw) fw->cmd_mbox = base + prestera_fw_read(fw, PRESTERA_CMD_BUF_OFFS_REG); fw->cmd_mbox_len = prestera_fw_read(fw, PRESTERA_CMD_BUF_LEN_REG); - mutex_init(&fw->cmd_mtx); + fw->cmd_qnum = prestera_fw_read(fw, PRESTERA_CMD_QNUM_REG); + + for (qid = 0; qid < fw->cmd_qnum; qid++) { + u32 offs = prestera_fw_read(fw, PRESTERA_CMDQ_OFFS_REG(qid)); + struct prestera_fw_cmdq *cmdq = &fw->cmd_queue[qid]; + + cmdq->len = prestera_fw_read(fw, PRESTERA_CMDQ_LEN_REG(qid)); + cmdq->addr = fw->cmd_mbox + offs; + mutex_init(&cmdq->cmd_mtx); + } fw->evt_buf = base + prestera_fw_read(fw, PRESTERA_EVT_BUF_OFFS_REG); fw->evt_qnum = prestera_fw_read(fw, PRESTERA_EVT_QNUM_REG); |