Skip to content

Commit 76baca2

Browse files
Aviad Krawczykdavem330
authored andcommitted
net-next/hinic: Add cmdq commands
Add cmdq commands for setting queue pair contexts in the nic. Signed-off-by: Aviad Krawczyk <[email protected]> Signed-off-by: Zhao Chen <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent fc9319e commit 76baca2

File tree

8 files changed

+683
-2
lines changed

8 files changed

+683
-2
lines changed

drivers/net/ethernet/huawei/hinic/hinic_common.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
*
1414
*/
1515

16+
#include <linux/kernel.h>
1617
#include <linux/types.h>
1718
#include <asm/byteorder.h>
1819

@@ -53,3 +54,27 @@ void hinic_be32_to_cpu(void *data, int len)
5354
mem++;
5455
}
5556
}
57+
58+
/**
59+
* hinic_set_sge - set dma area in scatter gather entry
60+
* @sge: scatter gather entry
61+
* @addr: dma address
62+
* @len: length of relevant data in the dma address
63+
**/
64+
void hinic_set_sge(struct hinic_sge *sge, dma_addr_t addr, int len)
65+
{
66+
sge->hi_addr = upper_32_bits(addr);
67+
sge->lo_addr = lower_32_bits(addr);
68+
sge->len = len;
69+
}
70+
71+
/**
72+
* hinic_sge_to_dma - get dma address from scatter gather entry
73+
* @sge: scatter gather entry
74+
*
75+
* Return dma address of sg entry
76+
**/
77+
dma_addr_t hinic_sge_to_dma(struct hinic_sge *sge)
78+
{
79+
return (dma_addr_t)((((u64)sge->hi_addr) << 32) | sge->lo_addr);
80+
}

drivers/net/ethernet/huawei/hinic/hinic_common.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
#ifndef HINIC_COMMON_H
1717
#define HINIC_COMMON_H
1818

19+
#include <linux/types.h>
20+
21+
#define UPPER_8_BITS(data) (((data) >> 8) & 0xFF)
22+
#define LOWER_8_BITS(data) ((data) & 0xFF)
23+
1924
struct hinic_sge {
2025
u32 hi_addr;
2126
u32 lo_addr;
@@ -26,4 +31,8 @@ void hinic_cpu_to_be32(void *data, int len);
2631

2732
void hinic_be32_to_cpu(void *data, int len);
2833

34+
void hinic_set_sge(struct hinic_sge *sge, dma_addr_t addr, int len);
35+
36+
dma_addr_t hinic_sge_to_dma(struct hinic_sge *sge);
37+
2938
#endif

drivers/net/ethernet/huawei/hinic/hinic_hw_cmdq.c

Lines changed: 280 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,45 @@
2424
#include <linux/sizes.h>
2525
#include <linux/atomic.h>
2626
#include <linux/log2.h>
27+
#include <linux/io.h>
28+
#include <linux/completion.h>
29+
#include <linux/err.h>
2730
#include <asm/byteorder.h>
31+
#include <asm/barrier.h>
2832

33+
#include "hinic_common.h"
2934
#include "hinic_hw_if.h"
3035
#include "hinic_hw_eqs.h"
3136
#include "hinic_hw_mgmt.h"
37+
#include "hinic_hw_wqe.h"
3238
#include "hinic_hw_wq.h"
3339
#include "hinic_hw_cmdq.h"
3440
#include "hinic_hw_io.h"
3541
#include "hinic_hw_dev.h"
3642

43+
#define CMDQ_DB_PI_OFF(pi) (((u16)LOWER_8_BITS(pi)) << 3)
44+
45+
#define CMDQ_DB_ADDR(db_base, pi) ((db_base) + CMDQ_DB_PI_OFF(pi))
46+
47+
#define CMDQ_WQE_HEADER(wqe) ((struct hinic_cmdq_header *)(wqe))
48+
49+
#define FIRST_DATA_TO_WRITE_LAST sizeof(u64)
50+
3751
#define CMDQ_DB_OFF SZ_2K
3852

3953
#define CMDQ_WQEBB_SIZE 64
54+
#define CMDQ_WQE_SIZE 64
4055
#define CMDQ_DEPTH SZ_4K
4156

4257
#define CMDQ_WQ_PAGE_SIZE SZ_4K
4358

4459
#define WQE_LCMD_SIZE 64
4560
#define WQE_SCMD_SIZE 64
4661

62+
#define COMPLETE_LEN 3
63+
64+
#define CMDQ_TIMEOUT 1000
65+
4766
#define CMDQ_PFN(addr, page_size) ((addr) >> (ilog2(page_size)))
4867

4968
#define cmdq_to_cmdqs(cmdq) container_of((cmdq) - (cmdq)->cmdq_type, \
@@ -58,6 +77,40 @@ enum cmdq_wqe_type {
5877
WQE_SCMD_TYPE = 1,
5978
};
6079

80+
enum completion_format {
81+
COMPLETE_DIRECT = 0,
82+
COMPLETE_SGE = 1,
83+
};
84+
85+
enum data_format {
86+
DATA_SGE = 0,
87+
DATA_DIRECT = 1,
88+
};
89+
90+
enum bufdesc_len {
91+
BUFDESC_LCMD_LEN = 2, /* 16 bytes - 2(8 byte unit) */
92+
BUFDESC_SCMD_LEN = 3, /* 24 bytes - 3(8 byte unit) */
93+
};
94+
95+
enum ctrl_sect_len {
96+
CTRL_SECT_LEN = 1, /* 4 bytes (ctrl) - 1(8 byte unit) */
97+
CTRL_DIRECT_SECT_LEN = 2, /* 12 bytes (ctrl + rsvd) - 2(8 byte unit) */
98+
};
99+
100+
enum cmdq_scmd_type {
101+
CMDQ_SET_ARM_CMD = 2,
102+
};
103+
104+
enum cmdq_cmd_type {
105+
CMDQ_CMD_SYNC_DIRECT_RESP = 0,
106+
CMDQ_CMD_SYNC_SGE_RESP = 1,
107+
};
108+
109+
enum completion_request {
110+
NO_CEQ = 0,
111+
CEQ_SET = 1,
112+
};
113+
61114
/**
62115
* hinic_alloc_cmdq_buf - alloc buffer for sending command
63116
* @cmdqs: the cmdqs
@@ -92,6 +145,221 @@ void hinic_free_cmdq_buf(struct hinic_cmdqs *cmdqs,
92145
pci_pool_free(cmdqs->cmdq_buf_pool, cmdq_buf->buf, cmdq_buf->dma_addr);
93146
}
94147

148+
static void cmdq_set_sge_completion(struct hinic_cmdq_completion *completion,
149+
struct hinic_cmdq_buf *buf_out)
150+
{
151+
struct hinic_sge_resp *sge_resp = &completion->sge_resp;
152+
153+
hinic_set_sge(&sge_resp->sge, buf_out->dma_addr, buf_out->size);
154+
}
155+
156+
static void cmdq_prepare_wqe_ctrl(struct hinic_cmdq_wqe *wqe, int wrapped,
157+
enum hinic_cmd_ack_type ack_type,
158+
enum hinic_mod_type mod, u8 cmd, u16 prod_idx,
159+
enum completion_format complete_format,
160+
enum data_format data_format,
161+
enum bufdesc_len buf_len)
162+
{
163+
struct hinic_cmdq_wqe_lcmd *wqe_lcmd;
164+
struct hinic_cmdq_wqe_scmd *wqe_scmd;
165+
enum ctrl_sect_len ctrl_len;
166+
struct hinic_ctrl *ctrl;
167+
u32 saved_data;
168+
169+
if (data_format == DATA_SGE) {
170+
wqe_lcmd = &wqe->wqe_lcmd;
171+
172+
wqe_lcmd->status.status_info = 0;
173+
ctrl = &wqe_lcmd->ctrl;
174+
ctrl_len = CTRL_SECT_LEN;
175+
} else {
176+
wqe_scmd = &wqe->direct_wqe.wqe_scmd;
177+
178+
wqe_scmd->status.status_info = 0;
179+
ctrl = &wqe_scmd->ctrl;
180+
ctrl_len = CTRL_DIRECT_SECT_LEN;
181+
}
182+
183+
ctrl->ctrl_info = HINIC_CMDQ_CTRL_SET(prod_idx, PI) |
184+
HINIC_CMDQ_CTRL_SET(cmd, CMD) |
185+
HINIC_CMDQ_CTRL_SET(mod, MOD) |
186+
HINIC_CMDQ_CTRL_SET(ack_type, ACK_TYPE);
187+
188+
CMDQ_WQE_HEADER(wqe)->header_info =
189+
HINIC_CMDQ_WQE_HEADER_SET(buf_len, BUFDESC_LEN) |
190+
HINIC_CMDQ_WQE_HEADER_SET(complete_format, COMPLETE_FMT) |
191+
HINIC_CMDQ_WQE_HEADER_SET(data_format, DATA_FMT) |
192+
HINIC_CMDQ_WQE_HEADER_SET(CEQ_SET, COMPLETE_REQ) |
193+
HINIC_CMDQ_WQE_HEADER_SET(COMPLETE_LEN, COMPLETE_SECT_LEN) |
194+
HINIC_CMDQ_WQE_HEADER_SET(ctrl_len, CTRL_LEN) |
195+
HINIC_CMDQ_WQE_HEADER_SET(wrapped, TOGGLED_WRAPPED);
196+
197+
saved_data = CMDQ_WQE_HEADER(wqe)->saved_data;
198+
saved_data = HINIC_SAVED_DATA_CLEAR(saved_data, ARM);
199+
200+
if ((cmd == CMDQ_SET_ARM_CMD) && (mod == HINIC_MOD_COMM))
201+
CMDQ_WQE_HEADER(wqe)->saved_data |=
202+
HINIC_SAVED_DATA_SET(1, ARM);
203+
else
204+
CMDQ_WQE_HEADER(wqe)->saved_data = saved_data;
205+
}
206+
207+
static void cmdq_set_lcmd_bufdesc(struct hinic_cmdq_wqe_lcmd *wqe_lcmd,
208+
struct hinic_cmdq_buf *buf_in)
209+
{
210+
hinic_set_sge(&wqe_lcmd->buf_desc.sge, buf_in->dma_addr, buf_in->size);
211+
}
212+
213+
static void cmdq_set_lcmd_wqe(struct hinic_cmdq_wqe *wqe,
214+
enum cmdq_cmd_type cmd_type,
215+
struct hinic_cmdq_buf *buf_in,
216+
struct hinic_cmdq_buf *buf_out, int wrapped,
217+
enum hinic_cmd_ack_type ack_type,
218+
enum hinic_mod_type mod, u8 cmd, u16 prod_idx)
219+
{
220+
struct hinic_cmdq_wqe_lcmd *wqe_lcmd = &wqe->wqe_lcmd;
221+
enum completion_format complete_format;
222+
223+
switch (cmd_type) {
224+
case CMDQ_CMD_SYNC_SGE_RESP:
225+
complete_format = COMPLETE_SGE;
226+
cmdq_set_sge_completion(&wqe_lcmd->completion, buf_out);
227+
break;
228+
case CMDQ_CMD_SYNC_DIRECT_RESP:
229+
complete_format = COMPLETE_DIRECT;
230+
wqe_lcmd->completion.direct_resp = 0;
231+
break;
232+
}
233+
234+
cmdq_prepare_wqe_ctrl(wqe, wrapped, ack_type, mod, cmd,
235+
prod_idx, complete_format, DATA_SGE,
236+
BUFDESC_LCMD_LEN);
237+
238+
cmdq_set_lcmd_bufdesc(wqe_lcmd, buf_in);
239+
}
240+
241+
static void cmdq_wqe_fill(void *dst, void *src)
242+
{
243+
memcpy(dst + FIRST_DATA_TO_WRITE_LAST, src + FIRST_DATA_TO_WRITE_LAST,
244+
CMDQ_WQE_SIZE - FIRST_DATA_TO_WRITE_LAST);
245+
246+
wmb(); /* The first 8 bytes should be written last */
247+
248+
*(u64 *)dst = *(u64 *)src;
249+
}
250+
251+
static void cmdq_fill_db(u32 *db_info,
252+
enum hinic_cmdq_type cmdq_type, u16 prod_idx)
253+
{
254+
*db_info = HINIC_CMDQ_DB_INFO_SET(UPPER_8_BITS(prod_idx), HI_PROD_IDX) |
255+
HINIC_CMDQ_DB_INFO_SET(HINIC_CTRL_PATH, PATH) |
256+
HINIC_CMDQ_DB_INFO_SET(cmdq_type, CMDQ_TYPE) |
257+
HINIC_CMDQ_DB_INFO_SET(HINIC_DB_CMDQ_TYPE, DB_TYPE);
258+
}
259+
260+
static void cmdq_set_db(struct hinic_cmdq *cmdq,
261+
enum hinic_cmdq_type cmdq_type, u16 prod_idx)
262+
{
263+
u32 db_info;
264+
265+
cmdq_fill_db(&db_info, cmdq_type, prod_idx);
266+
267+
/* The data that is written to HW should be in Big Endian Format */
268+
db_info = cpu_to_be32(db_info);
269+
270+
wmb(); /* write all before the doorbell */
271+
272+
writel(db_info, CMDQ_DB_ADDR(cmdq->db_base, prod_idx));
273+
}
274+
275+
static int cmdq_sync_cmd_direct_resp(struct hinic_cmdq *cmdq,
276+
enum hinic_mod_type mod, u8 cmd,
277+
struct hinic_cmdq_buf *buf_in,
278+
u64 *resp)
279+
{
280+
struct hinic_cmdq_wqe *curr_cmdq_wqe, cmdq_wqe;
281+
u16 curr_prod_idx, next_prod_idx;
282+
int errcode, wrapped, num_wqebbs;
283+
struct hinic_wq *wq = cmdq->wq;
284+
struct hinic_hw_wqe *hw_wqe;
285+
struct completion done;
286+
287+
/* Keep doorbell index correct. bh - for tasklet(ceq). */
288+
spin_lock_bh(&cmdq->cmdq_lock);
289+
290+
/* WQE_SIZE = WQEBB_SIZE, we will get the wq element and not shadow*/
291+
hw_wqe = hinic_get_wqe(wq, WQE_LCMD_SIZE, &curr_prod_idx);
292+
if (IS_ERR(hw_wqe)) {
293+
spin_unlock_bh(&cmdq->cmdq_lock);
294+
return -EBUSY;
295+
}
296+
297+
curr_cmdq_wqe = &hw_wqe->cmdq_wqe;
298+
299+
wrapped = cmdq->wrapped;
300+
301+
num_wqebbs = ALIGN(WQE_LCMD_SIZE, wq->wqebb_size) / wq->wqebb_size;
302+
next_prod_idx = curr_prod_idx + num_wqebbs;
303+
if (next_prod_idx >= wq->q_depth) {
304+
cmdq->wrapped = !cmdq->wrapped;
305+
next_prod_idx -= wq->q_depth;
306+
}
307+
308+
cmdq->errcode[curr_prod_idx] = &errcode;
309+
310+
init_completion(&done);
311+
cmdq->done[curr_prod_idx] = &done;
312+
313+
cmdq_set_lcmd_wqe(&cmdq_wqe, CMDQ_CMD_SYNC_DIRECT_RESP, buf_in, NULL,
314+
wrapped, HINIC_CMD_ACK_TYPE_CMDQ, mod, cmd,
315+
curr_prod_idx);
316+
317+
/* The data that is written to HW should be in Big Endian Format */
318+
hinic_cpu_to_be32(&cmdq_wqe, WQE_LCMD_SIZE);
319+
320+
/* CMDQ WQE is not shadow, therefore wqe will be written to wq */
321+
cmdq_wqe_fill(curr_cmdq_wqe, &cmdq_wqe);
322+
323+
cmdq_set_db(cmdq, HINIC_CMDQ_SYNC, next_prod_idx);
324+
325+
spin_unlock_bh(&cmdq->cmdq_lock);
326+
327+
if (!wait_for_completion_timeout(&done, CMDQ_TIMEOUT)) {
328+
spin_lock_bh(&cmdq->cmdq_lock);
329+
330+
if (cmdq->errcode[curr_prod_idx] == &errcode)
331+
cmdq->errcode[curr_prod_idx] = NULL;
332+
333+
if (cmdq->done[curr_prod_idx] == &done)
334+
cmdq->done[curr_prod_idx] = NULL;
335+
336+
spin_unlock_bh(&cmdq->cmdq_lock);
337+
338+
return -ETIMEDOUT;
339+
}
340+
341+
smp_rmb(); /* read error code after completion */
342+
343+
if (resp) {
344+
struct hinic_cmdq_wqe_lcmd *wqe_lcmd = &curr_cmdq_wqe->wqe_lcmd;
345+
346+
*resp = cpu_to_be64(wqe_lcmd->completion.direct_resp);
347+
}
348+
349+
if (errcode != 0)
350+
return -EFAULT;
351+
352+
return 0;
353+
}
354+
355+
static int cmdq_params_valid(struct hinic_cmdq_buf *buf_in)
356+
{
357+
if (buf_in->size > HINIC_CMDQ_MAX_DATA_SIZE)
358+
return -EINVAL;
359+
360+
return 0;
361+
}
362+
95363
/**
96364
* hinic_cmdq_direct_resp - send command with direct data as resp
97365
* @cmdqs: the cmdqs
@@ -106,8 +374,18 @@ int hinic_cmdq_direct_resp(struct hinic_cmdqs *cmdqs,
106374
enum hinic_mod_type mod, u8 cmd,
107375
struct hinic_cmdq_buf *buf_in, u64 *resp)
108376
{
109-
/* should be implemented */
110-
return -EINVAL;
377+
struct hinic_hwif *hwif = cmdqs->hwif;
378+
struct pci_dev *pdev = hwif->pdev;
379+
int err;
380+
381+
err = cmdq_params_valid(buf_in);
382+
if (err) {
383+
dev_err(&pdev->dev, "Invalid CMDQ parameters\n");
384+
return err;
385+
}
386+
387+
return cmdq_sync_cmd_direct_resp(&cmdqs->cmdq[HINIC_CMDQ_SYNC],
388+
mod, cmd, buf_in, resp);
111389
}
112390

113391
/**

0 commit comments

Comments
 (0)