1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
|
/* SPDX-License-Identifier: GPL-2.0-only */
/* Copyright (C) 2025 Intel Corporation */
#ifndef __LIBIE_CONTROLQ_H
#define __LIBIE_CONTROLQ_H
#include <linux/dmapool.h>
#include <net/libeth/rx.h>
#include <linux/net/intel/libie/pci.h>
#include <linux/net/intel/virtchnl2.h>
/* Default mailbox control queue */
#define LIBIE_CTLQ_MBX_ID -1
#define LIBIE_CTLQ_MAX_BUF_LEN SZ_4K
/**
* enum libie_ctlq_type - control queue type
* @LIBIE_CTLQ_TYPE_TX: basic Tx control queue
* @LIBIE_CTLQ_TYPE_RX: basic Rx control queue
*/
enum libie_ctlq_type {
LIBIE_CTLQ_TYPE_TX = 0,
LIBIE_CTLQ_TYPE_RX = 1,
};
/* Opcode used to send controlq message to the control plane */
#define LIBIE_CTLQ_SEND_MSG_TO_CP 0x801
#define LIBIE_CTLQ_SEND_MSG_TO_PEER 0x804
#define LIBIE_CP_TX_COPYBREAK 128
/**
* struct libie_ctlq_ctx - contains controlq info and MMIO region info
* @mmio_info: MMIO region info structure
* @ctlqs: list that stores all the control queues
* @ctlqs_lock: lock for control queue list
*/
struct libie_ctlq_ctx {
struct libie_mmio_info mmio_info;
struct list_head ctlqs;
spinlock_t ctlqs_lock; /* protects the ctlqs list */
};
/**
* struct libie_ctlq_reg - structure representing virtual addresses of the
* controlq registers and masks
* @head: controlq head register address
* @tail: controlq tail register address
* @len: register address to write controlq length and enable bit
* @addr_high: register address to write the upper 32b of ring physical address
* @addr_low: register address to write the lower 32b of ring physical address
* @len_mask: mask to read the controlq length
* @len_ena_mask: mask to write the controlq enable bit
* @head_mask: mask to read the head value
*/
struct libie_ctlq_reg {
void __iomem *head;
void __iomem *tail;
void __iomem *len;
void __iomem *addr_high;
void __iomem *addr_low;
u32 len_mask;
u32 len_ena_mask;
u32 head_mask;
};
/**
* struct libie_cp_dma_mem - structure for DMA memory
* @va: virtual address
* @pa: physical address
* @size: memory size
* @direction: memory to device or device to memory
*/
struct libie_cp_dma_mem {
void *va;
dma_addr_t pa;
size_t size;
int direction;
};
/**
* struct libie_ctlq_msg - control queue message data
* @flags: refer to 'Flags sub-structure' definitions
* @opcode: infrastructure message opcode
* @data_len: size of the payload
* @func_id: queue id for mailbox selection, 0 for default mailbox (Tx)
* @hw_retval: execution status from the HW (Rx)
* @chnl_opcode: virtchnl message opcode
* @chnl_retval: virtchnl return value
* @param0: indirect message raw parameter0
* @sw_cookie: used to verify the response of the sent virtchnl message
* @virt_flags: virtchnl capability flags
* @addr_param: additional parameters in place of the address, given no buffer
* @recv_mem: virtual address and size of the buffer that contains
* the indirect response
* @send_mem: physical and virtual address of the DMA buffer,
* used for sending
*/
struct libie_ctlq_msg {
u16 flags;
u16 opcode;
u16 data_len;
union {
u16 func_id;
u16 hw_retval;
};
u32 chnl_opcode;
u32 chnl_retval;
u32 param0;
u16 sw_cookie;
u16 virt_flags;
u64 addr_param;
union {
struct kvec recv_mem;
struct libie_cp_dma_mem send_mem;
};
};
/**
* struct libie_ctlq_create_info - control queue create information
* @type: control queue type (Rx or Tx)
* @id: queue offset passed as input, -1 for default mailbox
* @reg: registers accessed by control queue
* @len: controlq length
*/
struct libie_ctlq_create_info {
enum libie_ctlq_type type;
int id;
struct libie_ctlq_reg reg;
u16 len;
};
/**
* struct libie_ctlq_info - control queue information
* @list: used to add a controlq to the list of queues in libie_ctlq_ctx
* @type: control queue type
* @qid: queue identifier
* @lock: control queue lock
* @ring_mem: descriptor ring DMA memory
* @descs: array of descriptors
* @rx_fqes: array of controlq Rx buffers
* @tx_msg: Tx messages sent to hardware
* @reg: registers used by control queue
* @dev: device that owns this control queue
* @pp: page pool for controlq Rx buffers
* @truesize: size to allocate per buffer
* @next_to_clean: next descriptor to be cleaned
* @next_to_use: next available slot to send buffer (Tx queue)
* @next_to_post: next available slot to post buffers to (Rx queue)
* @ring_len: length of the descriptor ring
*/
struct libie_ctlq_info {
struct list_head list;
enum libie_ctlq_type type;
int qid;
spinlock_t lock; /* for concurrent processing */
struct libie_cp_dma_mem ring_mem;
struct libie_ctlq_desc *descs;
union {
struct libeth_fqe *rx_fqes;
struct libie_ctlq_msg **tx_msg;
};
struct libie_ctlq_reg reg;
struct device *dev;
struct page_pool *pp;
u32 truesize;
u32 next_to_clean;
union {
u32 next_to_use;
u32 next_to_post;
};
u32 ring_len;
};
#define LIBIE_CTLQ_MBX_ATQ_LEN GENMASK(9, 0)
/* libie controlq descriptor qword0 details */
/* Flags sub-structure
* |0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10 |11 |12 |13 |14 |15 |
* |DD |CMP|ERR| * RSV * |FTYPE | *RSV* |RD |VFC|BUF| HOST_ID |
*/
#define LIBIE_CTLQ_DESC_FLAG_DD BIT(0)
#define LIBIE_CTLQ_DESC_FLAG_CMP BIT(1)
#define LIBIE_CTLQ_DESC_FLAG_ERR BIT(2)
#define LIBIE_CTLQ_DESC_FLAG_FTYPE_VM BIT(6)
#define LIBIE_CTLQ_DESC_FLAG_FTYPE_PF BIT(7)
#define LIBIE_CTLQ_DESC_FLAG_FTYPE GENMASK(7, 6)
#define LIBIE_CTLQ_DESC_FLAG_RD BIT(10)
#define LIBIE_CTLQ_DESC_FLAG_VFC BIT(11)
#define LIBIE_CTLQ_DESC_FLAG_BUF BIT(12)
#define LIBIE_CTLQ_DESC_FLAG_HOST_ID GENMASK(15, 13)
#define LIBIE_CTLQ_DESC_FLAGS GENMASK(15, 0)
#define LIBIE_CTLQ_DESC_INFRA_OPCODE GENMASK_ULL(31, 16)
#define LIBIE_CTLQ_DESC_DATA_LEN GENMASK_ULL(47, 32)
#define LIBIE_CTLQ_DESC_HW_RETVAL GENMASK_ULL(63, 48)
#define LIBIE_CTLQ_DESC_PFID_VFID GENMASK_ULL(63, 48)
/* libie controlq descriptor qword1 details */
#define LIBIE_CTLQ_DESC_VIRTCHNL_OPCODE GENMASK(27, 0)
#define LIBIE_CTLQ_DESC_VIRTCHNL_DESC_TYPE GENMASK_ULL(31, 28)
#define LIBIE_CTLQ_DESC_VIRTCHNL_MSG_RET_VAL GENMASK_ULL(63, 32)
/* libie controlq descriptor qword2 details */
#define LIBIE_CTLQ_DESC_MSG_PARAM0 GENMASK_ULL(31, 0)
#define LIBIE_CTLQ_DESC_SW_COOKIE GENMASK_ULL(47, 32)
#define LIBIE_CTLQ_DESC_VIRTCHNL_FLAGS GENMASK_ULL(63, 48)
/* libie controlq descriptor qword3 details */
#define LIBIE_CTLQ_DESC_DATA_ADDR_HIGH GENMASK_ULL(31, 0)
#define LIBIE_CTLQ_DESC_DATA_ADDR_LOW GENMASK_ULL(63, 32)
/**
* struct libie_ctlq_desc - control queue descriptor format
* @qword0: flags, message opcode, data length etc
* @qword1: virtchnl opcode, descriptor type and return value
* @qword2: indirect message parameters
* @qword3: indirect message buffer address
*/
struct libie_ctlq_desc {
__le64 qword0;
__le64 qword1;
__le64 qword2;
__le64 qword3;
};
/**
* struct libie_ctlq_clean_params - cleaning parameters for Tx messages
* @rel_dma_mem: non-sleeping callback to put the DMA buffer after send
* @rel_ctx: additional context for release callback
* @ctlq: control queue information
* @num_msgs: number of messages to be cleaned
* @force: clean even if DD is not yet set, use only for final cleanup
*/
struct libie_ctlq_clean_params {
void (*rel_dma_mem)(const void *ctx, struct libie_cp_dma_mem *dma_mem);
const void *rel_ctx;
struct libie_ctlq_info *ctlq;
u16 num_msgs;
bool force;
};
/**
* libie_ctlq_release_rx_buf - Release Rx buffer for a specific control queue
* @rx_buf: Rx buffer to be freed
*
* Driver uses this function to post back the Rx buffer after the usage.
*/
static inline void libie_ctlq_release_rx_buf(struct kvec *rx_buf)
{
netmem_ref netmem;
if (!rx_buf->iov_base)
return;
netmem = virt_to_netmem(rx_buf->iov_base);
page_pool_put_full_netmem(netmem_get_pp(netmem), netmem, false);
}
int libie_ctlq_init(struct libie_ctlq_ctx *ctx,
const struct libie_ctlq_create_info *qinfo, u32 numq);
void libie_ctlq_deinit(struct libie_ctlq_ctx *ctx);
struct libie_ctlq_info *libie_find_ctlq(struct libie_ctlq_ctx *ctx,
enum libie_ctlq_type type,
int id);
u32 libie_ctlq_send_desc_avail(const struct libie_ctlq_info *ctlq);
void libie_ctlq_send(struct libie_ctlq_info *ctlq, u32 num_q_msg);
u32 libie_ctlq_send_clean(const struct libie_ctlq_clean_params *params);
u32 libie_ctlq_recv(struct libie_ctlq_info *ctlq, struct libie_ctlq_msg *msg,
u32 num_q_msg);
int libie_ctlq_post_rx_buffs(struct libie_ctlq_info *ctlq);
/* Only 8 bits are available in descriptor for Xn index */
#define LIBIE_CTLQ_MAX_XN_ENTRIES 256
#define LIBIE_CTLQ_XN_COOKIE_M GENMASK(15, 8)
#define LIBIE_CTLQ_XN_INDEX_M GENMASK(7, 0)
/**
* enum libie_ctlq_xn_state - Transaction state of a virtchnl message
* @LIBIE_CTLQ_XN_IDLE: transaction is available to use
* @LIBIE_CTLQ_XN_WAITING: waiting for transaction to complete
* @LIBIE_CTLQ_XN_COMPLETED_SUCCESS: transaction completed with success
* @LIBIE_CTLQ_XN_COMPLETED_FAILED: transaction completed with failure
* @LIBIE_CTLQ_XN_ASYNC: asynchronous virtchnl message transaction type
* @LIBIE_CTLQ_XN_SHUTDOWN: transaction cannot be used anymore
*/
enum libie_ctlq_xn_state {
LIBIE_CTLQ_XN_IDLE = 0,
LIBIE_CTLQ_XN_WAITING,
LIBIE_CTLQ_XN_COMPLETED_SUCCESS,
LIBIE_CTLQ_XN_COMPLETED_FAILED,
LIBIE_CTLQ_XN_ASYNC,
LIBIE_CTLQ_XN_SHUTDOWN,
};
/**
* struct libie_ctlq_xn - structure representing a virtchnl transaction entry
* @resp_cb: non-sleeping callback to handle the response to an async message
* @xn_lock: lock to protect the transaction entry state
* @cmd_completion_event: wait until reply is received or xn is terminated
* @small_dma_mem: DMA memory for copying small send buffers from stack,
* is recycled when response is received or on timeout
* @send_dma_mem: DMA memory of send buffer
* @recv_mem: receive buffer
* @send_ctx: context for callback function
* @timeout_ms: Xn transaction timeout in msecs
* @timestamp: timestamp to record the Xn send
* @tx_msg: control queue Tx message slot to track small DMA usage
* @virtchnl_opcode: virtchnl command opcode used for Xn transaction
* @state: transaction state of a virtchnl message
* @cookie: unique message identifier, incremented every time the slot is used
* @index: index of the transaction entry
*/
struct libie_ctlq_xn {
void (*resp_cb)(void *ctx, struct kvec *mem, int status);
spinlock_t xn_lock; /* protects state */
struct completion cmd_completion_event;
struct libie_cp_dma_mem small_dma_mem;
struct libie_cp_dma_mem send_dma_mem;
struct kvec recv_mem;
void *send_ctx;
u64 timeout_ms;
ktime_t timestamp;
struct libie_ctlq_msg *tx_msg;
u32 virtchnl_opcode;
enum libie_ctlq_xn_state state;
u8 cookie;
u8 index;
};
/**
* struct libie_ctlq_xn_manager - structure representing the array of virtchnl
* transaction entries
* @ctx: pointer to controlq context structure
* @free_xns_bm_lock: lock to protect the free Xn entries bit map
* @free_xns_bm: bitmap that represents the free Xn entries
* @ring: array of Xn entries
* @small_buff_pool: DMA pool for small send buffers
* @can_destroy: completion, triggered by the last released transaction
* @shutdown: shutdown process has been started, no new transactions allowed
*/
struct libie_ctlq_xn_manager {
struct libie_ctlq_ctx *ctx;
spinlock_t free_xns_bm_lock; /* get/check entries */
DECLARE_BITMAP(free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES);
struct libie_ctlq_xn ring[LIBIE_CTLQ_MAX_XN_ENTRIES];
struct dma_pool *small_buff_pool;
struct completion can_destroy;
bool shutdown;
};
/**
* struct libie_ctlq_xn_send_params - structure representing send Xn entry
* @resp_cb: non-sleeping callback to handle the response to an async message
* @rel_tx_buf: non-sleeping callback for freeing the send buffer
* @xnm: Xn manager to process Xn entries
* @ctlq: send control queue information
* @ctlq_msg: control queue message information
* @send_buf: buffer that carries outgoing message data, buffers larger than
* LIBIE_CP_TX_COPYBREAK bytes will always be consumed
* @recv_mem: receive buffer
* @send_ctx: context for callback function
* @timeout_ms: virtchnl transaction timeout in msecs
* @chnl_opcode: virtchnl message opcode
*/
struct libie_ctlq_xn_send_params {
void (*resp_cb)(void *ctx, struct kvec *mem, int status);
void (*rel_tx_buf)(const void *buf_va);
struct libie_ctlq_xn_manager *xnm;
struct libie_ctlq_info *ctlq;
struct libie_ctlq_msg *ctlq_msg;
struct kvec send_buf;
struct kvec recv_mem;
void *send_ctx;
u64 timeout_ms;
u32 chnl_opcode;
};
/**
* libie_cp_can_send_onstack - can a message be sent using a stack variable
* @size: ctlq data buffer size
*
* Return: %true if the message size is small enough for caller to pass
* an on-stack buffer, %false if kmalloc is needed
*/
static inline bool libie_cp_can_send_onstack(u32 size)
{
return size <= LIBIE_CP_TX_COPYBREAK;
}
/**
* struct libie_ctlq_xn_recv_params - request to receive xn responses
* @ctlq_msg_handler: handler for Rx messages with no matching xn (mandatory)
* @xnm: Xn manager to process Xn entries
* @ctlq: control queue information
* @budget: maximum number of messages to process
*/
struct libie_ctlq_xn_recv_params {
void (*ctlq_msg_handler)(struct libie_ctlq_ctx *ctx,
struct libie_ctlq_msg *msg);
struct libie_ctlq_xn_manager *xnm;
struct libie_ctlq_info *ctlq;
u32 budget;
};
/**
* struct libie_ctlq_xn_init_params - xn transaction manager parameters
* @cctlq_info: control queue information
* @ctx: pointer to controlq context structure
* @xnm: Xn manager to process Xn entries
* @num_qs: number of control queues to be initialized
*/
struct libie_ctlq_xn_init_params {
struct libie_ctlq_create_info *cctlq_info;
struct libie_ctlq_ctx *ctx;
struct libie_ctlq_xn_manager *xnm;
u32 num_qs;
};
int libie_ctlq_xn_init(struct libie_ctlq_xn_init_params *params);
void libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager *xnm,
struct libie_ctlq_ctx *ctx);
void libie_ctlq_xn_shutdown(struct libie_ctlq_xn_manager *xnm);
int libie_ctlq_xn_send(struct libie_ctlq_xn_send_params *params);
u32 libie_ctlq_xn_recv(struct libie_ctlq_xn_recv_params *params);
u32 libie_ctlq_xn_send_clean(struct libie_ctlq_info *ctlq,
void (*rel_tx_buf)(const void *buf_va),
bool force);
#endif /* __LIBIE_CONTROLQ_H */
|