24
24
#include <linux/sizes.h>
25
25
#include <linux/atomic.h>
26
26
#include <linux/log2.h>
27
+ #include <linux/io.h>
28
+ #include <linux/completion.h>
29
+ #include <linux/err.h>
27
30
#include <asm/byteorder.h>
31
+ #include <asm/barrier.h>
28
32
33
+ #include "hinic_common.h"
29
34
#include "hinic_hw_if.h"
30
35
#include "hinic_hw_eqs.h"
31
36
#include "hinic_hw_mgmt.h"
37
+ #include "hinic_hw_wqe.h"
32
38
#include "hinic_hw_wq.h"
33
39
#include "hinic_hw_cmdq.h"
34
40
#include "hinic_hw_io.h"
35
41
#include "hinic_hw_dev.h"
36
42
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
+
37
51
#define CMDQ_DB_OFF SZ_2K
38
52
39
53
#define CMDQ_WQEBB_SIZE 64
54
+ #define CMDQ_WQE_SIZE 64
40
55
#define CMDQ_DEPTH SZ_4K
41
56
42
57
#define CMDQ_WQ_PAGE_SIZE SZ_4K
43
58
44
59
#define WQE_LCMD_SIZE 64
45
60
#define WQE_SCMD_SIZE 64
46
61
62
+ #define COMPLETE_LEN 3
63
+
64
+ #define CMDQ_TIMEOUT 1000
65
+
47
66
#define CMDQ_PFN (addr , page_size ) ((addr) >> (ilog2(page_size)))
48
67
49
68
#define cmdq_to_cmdqs (cmdq ) container_of((cmdq) - (cmdq)->cmdq_type, \
@@ -58,6 +77,40 @@ enum cmdq_wqe_type {
58
77
WQE_SCMD_TYPE = 1 ,
59
78
};
60
79
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
+
61
114
/**
62
115
* hinic_alloc_cmdq_buf - alloc buffer for sending command
63
116
* @cmdqs: the cmdqs
@@ -92,6 +145,221 @@ void hinic_free_cmdq_buf(struct hinic_cmdqs *cmdqs,
92
145
pci_pool_free (cmdqs -> cmdq_buf_pool , cmdq_buf -> buf , cmdq_buf -> dma_addr );
93
146
}
94
147
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
+
95
363
/**
96
364
* hinic_cmdq_direct_resp - send command with direct data as resp
97
365
* @cmdqs: the cmdqs
@@ -106,8 +374,18 @@ int hinic_cmdq_direct_resp(struct hinic_cmdqs *cmdqs,
106
374
enum hinic_mod_type mod , u8 cmd ,
107
375
struct hinic_cmdq_buf * buf_in , u64 * resp )
108
376
{
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 );
111
389
}
112
390
113
391
/**
0 commit comments