xref: /linux/drivers/net/ethernet/intel/libie/controlq.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1caed480fSPhani R Burra // SPDX-License-Identifier: GPL-2.0-only
2caed480fSPhani R Burra /* Copyright (C) 2025 Intel Corporation */
3caed480fSPhani R Burra 
4caed480fSPhani R Burra #include <linux/bitfield.h>
5caed480fSPhani R Burra #include <net/libeth/rx.h>
6caed480fSPhani R Burra 
7caed480fSPhani R Burra #include <linux/net/intel/libie/controlq.h>
8caed480fSPhani R Burra 
9caed480fSPhani R Burra #define LIBIE_CTLQ_DESC_QWORD0(sz)			\
10caed480fSPhani R Burra 	(LIBIE_CTLQ_DESC_FLAG_BUF |			\
11caed480fSPhani R Burra 	 LIBIE_CTLQ_DESC_FLAG_RD |			\
12caed480fSPhani R Burra 	 FIELD_PREP(LIBIE_CTLQ_DESC_DATA_LEN, sz))
13caed480fSPhani R Burra 
14caed480fSPhani R Burra /**
15caed480fSPhani R Burra  * libie_ctlq_free_fq - free fill queue resources, including buffers
16caed480fSPhani R Burra  * @ctlq: Rx control queue whose resources need to be freed
17caed480fSPhani R Burra  */
libie_ctlq_free_fq(struct libie_ctlq_info * ctlq)18caed480fSPhani R Burra static void libie_ctlq_free_fq(struct libie_ctlq_info *ctlq)
19caed480fSPhani R Burra {
20caed480fSPhani R Burra 	struct libeth_fq fq = {
21caed480fSPhani R Burra 		.fqes		= ctlq->rx_fqes,
22caed480fSPhani R Burra 		.pp		= ctlq->pp,
23caed480fSPhani R Burra 	};
24caed480fSPhani R Burra 
25caed480fSPhani R Burra 	for (u32 ntc = ctlq->next_to_clean; ntc != ctlq->next_to_post; ) {
26caed480fSPhani R Burra 		page_pool_put_full_netmem(fq.pp, fq.fqes[ntc].netmem, false);
27caed480fSPhani R Burra 
28caed480fSPhani R Burra 		if (++ntc >= ctlq->ring_len)
29caed480fSPhani R Burra 			ntc = 0;
30caed480fSPhani R Burra 	}
31caed480fSPhani R Burra 
32caed480fSPhani R Burra 	libeth_rx_fq_destroy(&fq);
33caed480fSPhani R Burra }
34caed480fSPhani R Burra 
35caed480fSPhani R Burra /**
36caed480fSPhani R Burra  * libie_ctlq_init_fq - initialize fill queue for an Rx controlq
37caed480fSPhani R Burra  * @ctlq: control queue that needs Rx buffer allocation
38caed480fSPhani R Burra  *
39caed480fSPhani R Burra  * Return: %0 on success, -%errno on failure
40caed480fSPhani R Burra  */
libie_ctlq_init_fq(struct libie_ctlq_info * ctlq)41caed480fSPhani R Burra static int libie_ctlq_init_fq(struct libie_ctlq_info *ctlq)
42caed480fSPhani R Burra {
43caed480fSPhani R Burra 	struct libeth_fq fq = {
44caed480fSPhani R Burra 		.count		= ctlq->ring_len,
45caed480fSPhani R Burra 		.truesize	= LIBIE_CTLQ_MAX_BUF_LEN,
46caed480fSPhani R Burra 		.nid		= NUMA_NO_NODE,
47caed480fSPhani R Burra 		.type		= LIBETH_FQE_SHORT,
48caed480fSPhani R Burra 		.hsplit		= true,
49caed480fSPhani R Burra 		.no_napi	= true,
50caed480fSPhani R Burra 	};
51caed480fSPhani R Burra 	int err;
52caed480fSPhani R Burra 
53caed480fSPhani R Burra 	err = libeth_rx_fq_create(&fq, ctlq->dev);
54caed480fSPhani R Burra 	if (err)
55caed480fSPhani R Burra 		return err;
56caed480fSPhani R Burra 
57caed480fSPhani R Burra 	ctlq->pp = fq.pp;
58caed480fSPhani R Burra 	ctlq->rx_fqes = fq.fqes;
59caed480fSPhani R Burra 	ctlq->truesize = fq.truesize;
60caed480fSPhani R Burra 
61caed480fSPhani R Burra 	return 0;
62caed480fSPhani R Burra }
63caed480fSPhani R Burra 
64caed480fSPhani R Burra /**
65caed480fSPhani R Burra  * libie_ctlq_prep_rx_desc - prepare the descriptor with a new address
66caed480fSPhani R Burra  * @desc: descriptor to (re)initialize
67caed480fSPhani R Burra  * @addr: physical address to put into descriptor
68caed480fSPhani R Burra  * @mem_truesize: size of the accessible memory
69caed480fSPhani R Burra  */
libie_ctlq_prep_rx_desc(struct libie_ctlq_desc * desc,dma_addr_t addr,u32 mem_truesize)70caed480fSPhani R Burra static void libie_ctlq_prep_rx_desc(struct libie_ctlq_desc *desc,
71caed480fSPhani R Burra 				    dma_addr_t addr, u32 mem_truesize)
72caed480fSPhani R Burra {
73caed480fSPhani R Burra 	u64 qword;
74caed480fSPhani R Burra 
75caed480fSPhani R Burra 	qword = LIBIE_CTLQ_DESC_QWORD0(mem_truesize);
76caed480fSPhani R Burra 	desc->qword0 = cpu_to_le64(qword);
77caed480fSPhani R Burra 
78caed480fSPhani R Burra 	qword = FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_HIGH,
79caed480fSPhani R Burra 			   upper_32_bits(addr)) |
80caed480fSPhani R Burra 		FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_LOW,
81caed480fSPhani R Burra 			   lower_32_bits(addr));
82caed480fSPhani R Burra 	desc->qword3 = cpu_to_le64(qword);
83caed480fSPhani R Burra }
84caed480fSPhani R Burra 
85caed480fSPhani R Burra /**
86caed480fSPhani R Burra  * libie_ctlq_post_rx_buffs - post buffers to descriptor ring
87caed480fSPhani R Burra  * @ctlq: control queue that requires Rx descriptor ring to be initialized with
88caed480fSPhani R Burra  *	  new Rx buffers
89caed480fSPhani R Burra  *
90caed480fSPhani R Burra  * The caller must make sure that calls to libie_ctlq_post_rx_buffs()
91caed480fSPhani R Burra  * and libie_ctlq_recv() for each queue are either serialized
92caed480fSPhani R Burra  * or used under ctlq->lock.
93caed480fSPhani R Burra  *
94caed480fSPhani R Burra  * Return: %0 on success, -%ENOMEM if any buffer could not be allocated
95caed480fSPhani R Burra  */
libie_ctlq_post_rx_buffs(struct libie_ctlq_info * ctlq)96caed480fSPhani R Burra int libie_ctlq_post_rx_buffs(struct libie_ctlq_info *ctlq)
97caed480fSPhani R Burra {
98caed480fSPhani R Burra 	u32 ntp = ctlq->next_to_post, ntc = ctlq->next_to_clean, num_to_post;
99caed480fSPhani R Burra 	const struct libeth_fq_fp fq = {
100caed480fSPhani R Burra 		.pp		= ctlq->pp,
101caed480fSPhani R Burra 		.fqes		= ctlq->rx_fqes,
102caed480fSPhani R Burra 		.truesize	= ctlq->truesize,
103caed480fSPhani R Burra 		.count		= ctlq->ring_len,
104caed480fSPhani R Burra 	};
105caed480fSPhani R Burra 	int ret = 0;
106caed480fSPhani R Burra 
107caed480fSPhani R Burra 	num_to_post = (ntc > ntp ? 0 : ctlq->ring_len) + ntc - ntp - 1;
108caed480fSPhani R Burra 
109caed480fSPhani R Burra 	while (num_to_post--) {
110caed480fSPhani R Burra 		dma_addr_t addr;
111caed480fSPhani R Burra 
112caed480fSPhani R Burra 		ctlq->descs[ntp] = (struct libie_ctlq_desc) {};
113caed480fSPhani R Burra 
114caed480fSPhani R Burra 		addr = libeth_rx_alloc(&fq, ntp);
115caed480fSPhani R Burra 		if (unlikely(addr == DMA_MAPPING_ERROR)) {
116caed480fSPhani R Burra 			ret = -ENOMEM;
117caed480fSPhani R Burra 			goto post_bufs;
118caed480fSPhani R Burra 		}
119caed480fSPhani R Burra 
120caed480fSPhani R Burra 		libie_ctlq_prep_rx_desc(&ctlq->descs[ntp], addr, fq.truesize);
121caed480fSPhani R Burra 
122caed480fSPhani R Burra 		if (unlikely(++ntp == ctlq->ring_len))
123caed480fSPhani R Burra 			ntp = 0;
124caed480fSPhani R Burra 	}
125caed480fSPhani R Burra 
126caed480fSPhani R Burra post_bufs:
127caed480fSPhani R Burra 	if (likely(ctlq->next_to_post != ntp)) {
128caed480fSPhani R Burra 		ctlq->next_to_post = ntp;
129caed480fSPhani R Burra 
130caed480fSPhani R Burra 		dma_wmb();
131caed480fSPhani R Burra 		writel(ntp, ctlq->reg.tail);
132caed480fSPhani R Burra 	}
133caed480fSPhani R Burra 
134caed480fSPhani R Burra 	return ret;
135caed480fSPhani R Burra }
136caed480fSPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_post_rx_buffs, "LIBIE_CP");
137caed480fSPhani R Burra 
138caed480fSPhani R Burra /**
139caed480fSPhani R Burra  * libie_ctlq_free_tx_msgs - Free Tx control queue messages
140caed480fSPhani R Burra  * @ctlq: Tx control queue being destroyed
141caed480fSPhani R Burra  * @num_msgs: number of messages allocated so far
142caed480fSPhani R Burra  */
libie_ctlq_free_tx_msgs(struct libie_ctlq_info * ctlq,u32 num_msgs)143caed480fSPhani R Burra static void libie_ctlq_free_tx_msgs(struct libie_ctlq_info *ctlq,
144caed480fSPhani R Burra 				    u32 num_msgs)
145caed480fSPhani R Burra {
146caed480fSPhani R Burra 	for (u32 i = 0; i < num_msgs; i++)
147caed480fSPhani R Burra 		kfree(ctlq->tx_msg[i]);
148caed480fSPhani R Burra 
149caed480fSPhani R Burra 	kvfree(ctlq->tx_msg);
150caed480fSPhani R Burra }
151caed480fSPhani R Burra 
152caed480fSPhani R Burra /**
153caed480fSPhani R Burra  * libie_ctlq_alloc_tx_msgs - Allocate Tx control queue messages
154caed480fSPhani R Burra  * @ctlq: Tx control queue being created
155caed480fSPhani R Burra  *
156caed480fSPhani R Burra  * Return: %0 on success, -%ENOMEM on allocation error
157caed480fSPhani R Burra  */
libie_ctlq_alloc_tx_msgs(struct libie_ctlq_info * ctlq)158caed480fSPhani R Burra static int libie_ctlq_alloc_tx_msgs(struct libie_ctlq_info *ctlq)
159caed480fSPhani R Burra {
160caed480fSPhani R Burra 	ctlq->tx_msg = kvzalloc_objs(*ctlq->tx_msg, ctlq->ring_len,
161caed480fSPhani R Burra 				     GFP_KERNEL);
162caed480fSPhani R Burra 	if (!ctlq->tx_msg)
163caed480fSPhani R Burra 		return -ENOMEM;
164caed480fSPhani R Burra 
165caed480fSPhani R Burra 	for (u32 i = 0; i < ctlq->ring_len; i++) {
166caed480fSPhani R Burra 		ctlq->tx_msg[i] = kzalloc_obj(*ctlq->tx_msg[i]);
167caed480fSPhani R Burra 		if (!ctlq->tx_msg[i]) {
168caed480fSPhani R Burra 			libie_ctlq_free_tx_msgs(ctlq, i);
169caed480fSPhani R Burra 			return -ENOMEM;
170caed480fSPhani R Burra 		}
171caed480fSPhani R Burra 	}
172caed480fSPhani R Burra 
173caed480fSPhani R Burra 	return 0;
174caed480fSPhani R Burra }
175caed480fSPhani R Burra 
176caed480fSPhani R Burra /**
177caed480fSPhani R Burra  * libie_cp_free_desc_mem - free the previously allocated descriptor DMA memory
178caed480fSPhani R Burra  * @dev: device information
179caed480fSPhani R Burra  * @mem: DMA memory information
180caed480fSPhani R Burra  */
libie_cp_free_desc_mem(struct device * dev,struct libie_cp_dma_mem * mem)181caed480fSPhani R Burra static void libie_cp_free_desc_mem(struct device *dev,
182caed480fSPhani R Burra 				   struct libie_cp_dma_mem *mem)
183caed480fSPhani R Burra {
184caed480fSPhani R Burra 	dma_free_coherent(dev, mem->size, mem->va, mem->pa);
185caed480fSPhani R Burra 	mem->va = NULL;
186caed480fSPhani R Burra }
187caed480fSPhani R Burra 
188caed480fSPhani R Burra /**
189caed480fSPhani R Burra  * libie_ctlq_dealloc_ring_res - free memory allocated for control queue
190caed480fSPhani R Burra  * @ctlq: control queue that requires its ring memory to be freed
191caed480fSPhani R Burra  *
192caed480fSPhani R Burra  * Free the memory used by the ring, buffers and other related structures.
193caed480fSPhani R Burra  */
libie_ctlq_dealloc_ring_res(struct libie_ctlq_info * ctlq)194caed480fSPhani R Burra static void libie_ctlq_dealloc_ring_res(struct libie_ctlq_info *ctlq)
195caed480fSPhani R Burra {
196caed480fSPhani R Burra 	struct libie_cp_dma_mem *dma = &ctlq->ring_mem;
197caed480fSPhani R Burra 
198caed480fSPhani R Burra 	if (ctlq->type == LIBIE_CTLQ_TYPE_TX)
199caed480fSPhani R Burra 		libie_ctlq_free_tx_msgs(ctlq, ctlq->ring_len);
200caed480fSPhani R Burra 	else
201caed480fSPhani R Burra 		libie_ctlq_free_fq(ctlq);
202caed480fSPhani R Burra 
203caed480fSPhani R Burra 	libie_cp_free_desc_mem(ctlq->dev, dma);
204caed480fSPhani R Burra }
205caed480fSPhani R Burra 
206caed480fSPhani R Burra /**
207caed480fSPhani R Burra  * libie_cp_alloc_desc_mem - allocate DMA memory for descriptor ring
208caed480fSPhani R Burra  * @dev: device information
209caed480fSPhani R Burra  * @mem: memory for DMA information to be stored
210caed480fSPhani R Burra  * @size: size of the memory to allocate
211caed480fSPhani R Burra  *
212caed480fSPhani R Burra  * Return: virtual address of DMA memory or NULL.
213caed480fSPhani R Burra  */
libie_cp_alloc_desc_mem(struct device * dev,struct libie_cp_dma_mem * mem,u32 size)214caed480fSPhani R Burra static void *libie_cp_alloc_desc_mem(struct device *dev,
215caed480fSPhani R Burra 				     struct libie_cp_dma_mem *mem, u32 size)
216caed480fSPhani R Burra {
217caed480fSPhani R Burra 	size = LARGEST_ALIGN(size);
218caed480fSPhani R Burra 
219caed480fSPhani R Burra 	mem->va = dma_alloc_coherent(dev, size, &mem->pa, GFP_KERNEL);
220caed480fSPhani R Burra 	mem->size = size;
221caed480fSPhani R Burra 	mem->direction = DMA_BIDIRECTIONAL;
222caed480fSPhani R Burra 
223caed480fSPhani R Burra 	return mem->va;
224caed480fSPhani R Burra }
225caed480fSPhani R Burra 
226caed480fSPhani R Burra /**
227caed480fSPhani R Burra  * libie_ctlq_alloc_queue_res - allocate memory for descriptor ring and bufs
228caed480fSPhani R Burra  * @ctlq: control queue that requires its ring resources to be allocated
229caed480fSPhani R Burra  *
230caed480fSPhani R Burra  * Return: %0 on success, -%errno on failure
231caed480fSPhani R Burra  */
libie_ctlq_alloc_queue_res(struct libie_ctlq_info * ctlq)232caed480fSPhani R Burra static int libie_ctlq_alloc_queue_res(struct libie_ctlq_info *ctlq)
233caed480fSPhani R Burra {
234caed480fSPhani R Burra 	size_t size = array_size(ctlq->ring_len, sizeof(*ctlq->descs));
235caed480fSPhani R Burra 	struct libie_cp_dma_mem *dma = &ctlq->ring_mem;
236caed480fSPhani R Burra 	int err = -ENOMEM;
237caed480fSPhani R Burra 
238caed480fSPhani R Burra 	if (!libie_cp_alloc_desc_mem(ctlq->dev, dma, size))
239caed480fSPhani R Burra 		return -ENOMEM;
240caed480fSPhani R Burra 
241caed480fSPhani R Burra 	ctlq->descs = dma->va;
242caed480fSPhani R Burra 
243caed480fSPhani R Burra 	if (ctlq->type == LIBIE_CTLQ_TYPE_TX) {
244caed480fSPhani R Burra 		if (libie_ctlq_alloc_tx_msgs(ctlq))
245caed480fSPhani R Burra 			goto free_dma_mem;
246caed480fSPhani R Burra 	} else {
247caed480fSPhani R Burra 		err = libie_ctlq_init_fq(ctlq);
248caed480fSPhani R Burra 		if (err)
249caed480fSPhani R Burra 			goto free_dma_mem;
250caed480fSPhani R Burra 
251caed480fSPhani R Burra 		err = libie_ctlq_post_rx_buffs(ctlq);
252caed480fSPhani R Burra 		if (err) {
253caed480fSPhani R Burra 			libie_ctlq_free_fq(ctlq);
254caed480fSPhani R Burra 			goto free_dma_mem;
255caed480fSPhani R Burra 		}
256caed480fSPhani R Burra 	}
257caed480fSPhani R Burra 
258caed480fSPhani R Burra 	return 0;
259caed480fSPhani R Burra 
260caed480fSPhani R Burra free_dma_mem:
261caed480fSPhani R Burra 	libie_cp_free_desc_mem(ctlq->dev, dma);
262caed480fSPhani R Burra 
263caed480fSPhani R Burra 	return err;
264caed480fSPhani R Burra }
265caed480fSPhani R Burra 
266caed480fSPhani R Burra /**
267caed480fSPhani R Burra  * libie_ctlq_init_regs - Initialize control queue registers
268caed480fSPhani R Burra  * @ctlq: control queue that needs to be initialized
269caed480fSPhani R Burra  *
270caed480fSPhani R Burra  * Initialize registers. The caller is expected to have already initialized the
271caed480fSPhani R Burra  * descriptor ring memory and buffer memory.
272caed480fSPhani R Burra  */
libie_ctlq_init_regs(struct libie_ctlq_info * ctlq)273caed480fSPhani R Burra static void libie_ctlq_init_regs(struct libie_ctlq_info *ctlq)
274caed480fSPhani R Burra {
275caed480fSPhani R Burra 	u32 dword;
276caed480fSPhani R Burra 
277caed480fSPhani R Burra 	if (ctlq->type == LIBIE_CTLQ_TYPE_RX)
278caed480fSPhani R Burra 		writel(ctlq->ring_len - 1, ctlq->reg.tail);
279caed480fSPhani R Burra 	else
280caed480fSPhani R Burra 		writel(0, ctlq->reg.tail);
281caed480fSPhani R Burra 
282caed480fSPhani R Burra 	writel(0, ctlq->reg.head);
283caed480fSPhani R Burra 	writel(lower_32_bits(ctlq->ring_mem.pa), ctlq->reg.addr_low);
284caed480fSPhani R Burra 	writel(upper_32_bits(ctlq->ring_mem.pa), ctlq->reg.addr_high);
285caed480fSPhani R Burra 
286caed480fSPhani R Burra 	dword = FIELD_PREP(LIBIE_CTLQ_MBX_ATQ_LEN, ctlq->ring_len) |
287caed480fSPhani R Burra 		ctlq->reg.len_ena_mask;
288caed480fSPhani R Burra 	writel(dword, ctlq->reg.len);
289caed480fSPhani R Burra }
290caed480fSPhani R Burra 
291caed480fSPhani R Burra /**
292caed480fSPhani R Burra  * libie_find_ctlq - find the controlq for the given id and type
293caed480fSPhani R Burra  * @ctx: libie CP context information
294caed480fSPhani R Burra  * @type: type of controlq to find
295caed480fSPhani R Burra  * @id: controlq id to find
296caed480fSPhani R Burra  *
297caed480fSPhani R Burra  * Return: control queue info pointer on success, NULL on failure
298caed480fSPhani R Burra  */
libie_find_ctlq(struct libie_ctlq_ctx * ctx,enum libie_ctlq_type type,int id)299caed480fSPhani R Burra struct libie_ctlq_info *libie_find_ctlq(struct libie_ctlq_ctx *ctx,
300caed480fSPhani R Burra 					enum libie_ctlq_type type,
301caed480fSPhani R Burra 					int id)
302caed480fSPhani R Burra {
303caed480fSPhani R Burra 	struct libie_ctlq_info *cq;
304caed480fSPhani R Burra 
305caed480fSPhani R Burra 	guard(spinlock)(&ctx->ctlqs_lock);
306caed480fSPhani R Burra 
307caed480fSPhani R Burra 	list_for_each_entry(cq, &ctx->ctlqs, list)
308caed480fSPhani R Burra 		if (cq->qid == id && cq->type == type)
309caed480fSPhani R Burra 			return cq;
310caed480fSPhani R Burra 
311caed480fSPhani R Burra 	return NULL;
312caed480fSPhani R Burra }
313caed480fSPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_find_ctlq, "LIBIE_CP");
314caed480fSPhani R Burra 
315caed480fSPhani R Burra /**
316caed480fSPhani R Burra  * libie_ctlq_add - add one control queue
317caed480fSPhani R Burra  * @ctx: libie CP context information
318caed480fSPhani R Burra  * @qinfo: information required for queue creation
319caed480fSPhani R Burra  *
320caed480fSPhani R Burra  * Allocate and initialize a control queue and add it to the control queue list.
321caed480fSPhani R Burra  * libie_ctlq_init() must be called prior to any calls to libie_ctlq_add.
322caed480fSPhani R Burra  *
323caed480fSPhani R Burra  * Return: added control queue info pointer on success, error pointer on failure
324caed480fSPhani R Burra  */
325caed480fSPhani R Burra static struct libie_ctlq_info *
libie_ctlq_add(struct libie_ctlq_ctx * ctx,const struct libie_ctlq_create_info * qinfo)326caed480fSPhani R Burra libie_ctlq_add(struct libie_ctlq_ctx *ctx,
327caed480fSPhani R Burra 	       const struct libie_ctlq_create_info *qinfo)
328caed480fSPhani R Burra {
329caed480fSPhani R Burra 	struct libie_ctlq_info *ctlq;
330caed480fSPhani R Burra 	int err;
331caed480fSPhani R Burra 
332caed480fSPhani R Burra 	if (qinfo->id != LIBIE_CTLQ_MBX_ID)
333caed480fSPhani R Burra 		return ERR_PTR(-EOPNOTSUPP);
334caed480fSPhani R Burra 
335caed480fSPhani R Burra 	if (qinfo->len > FIELD_MAX(LIBIE_CTLQ_MBX_ATQ_LEN) || !qinfo->len)
336caed480fSPhani R Burra 		return ERR_PTR(-EINVAL);
337caed480fSPhani R Burra 
338caed480fSPhani R Burra 	ctlq = kvzalloc_obj(*ctlq);
339caed480fSPhani R Burra 	if (!ctlq)
340caed480fSPhani R Burra 		return ERR_PTR(-ENOMEM);
341caed480fSPhani R Burra 
342caed480fSPhani R Burra 	ctlq->type = qinfo->type;
343caed480fSPhani R Burra 	ctlq->qid = qinfo->id;
344caed480fSPhani R Burra 	ctlq->ring_len = qinfo->len;
345caed480fSPhani R Burra 	ctlq->dev = &ctx->mmio_info.pdev->dev;
346caed480fSPhani R Burra 	ctlq->reg = qinfo->reg;
347caed480fSPhani R Burra 
348caed480fSPhani R Burra 	err = libie_ctlq_alloc_queue_res(ctlq);
349caed480fSPhani R Burra 	if (err) {
350caed480fSPhani R Burra 		kvfree(ctlq);
351caed480fSPhani R Burra 		return ERR_PTR(err);
352caed480fSPhani R Burra 	}
353caed480fSPhani R Burra 
354caed480fSPhani R Burra 	libie_ctlq_init_regs(ctlq);
355caed480fSPhani R Burra 
356caed480fSPhani R Burra 	spin_lock_init(&ctlq->lock);
357caed480fSPhani R Burra 
358caed480fSPhani R Burra 	scoped_guard(spinlock, &ctx->ctlqs_lock)
359caed480fSPhani R Burra 		list_add(&ctlq->list, &ctx->ctlqs);
360caed480fSPhani R Burra 
361caed480fSPhani R Burra 	return ctlq;
362caed480fSPhani R Burra }
363caed480fSPhani R Burra 
364caed480fSPhani R Burra /**
365caed480fSPhani R Burra  * libie_ctlq_remove - deallocate and remove specified control queue
366caed480fSPhani R Burra  * @ctx: libie CP context information
367caed480fSPhani R Burra  * @ctlq: specific control queue that needs to be removed
368caed480fSPhani R Burra  */
libie_ctlq_remove(struct libie_ctlq_ctx * ctx,struct libie_ctlq_info * ctlq)369caed480fSPhani R Burra static void libie_ctlq_remove(struct libie_ctlq_ctx *ctx,
370caed480fSPhani R Burra 			      struct libie_ctlq_info *ctlq)
371caed480fSPhani R Burra {
372caed480fSPhani R Burra 	scoped_guard(spinlock, &ctx->ctlqs_lock)
373caed480fSPhani R Burra 		list_del(&ctlq->list);
374caed480fSPhani R Burra 
375caed480fSPhani R Burra 	libie_ctlq_dealloc_ring_res(ctlq);
376caed480fSPhani R Burra 	kvfree(ctlq);
377caed480fSPhani R Burra }
378caed480fSPhani R Burra 
379caed480fSPhani R Burra /**
380caed480fSPhani R Burra  * libie_ctlq_init - main initialization routine for all control queues
381caed480fSPhani R Burra  * @ctx: libie CP context information
382caed480fSPhani R Burra  * @qinfo: array of structs containing info for each queue to be initialized
383caed480fSPhani R Burra  * @numq: number of queues to initialize
384caed480fSPhani R Burra  *
385caed480fSPhani R Burra  * This initializes queue list and adds any number and any type of control
386caed480fSPhani R Burra  * queues. This is an all or nothing routine; if one fails, all previously
387caed480fSPhani R Burra  * allocated queues will be destroyed.
388caed480fSPhani R Burra  *
389caed480fSPhani R Burra  * Please note that any control queue send/receive functions are not
390caed480fSPhani R Burra  * softirq/NAPI safe, and therefore API can be used in process context only.
391caed480fSPhani R Burra  *
392caed480fSPhani R Burra  * Return: %0 on success, -%errno on failure
393caed480fSPhani R Burra  */
libie_ctlq_init(struct libie_ctlq_ctx * ctx,const struct libie_ctlq_create_info * qinfo,u32 numq)394caed480fSPhani R Burra int libie_ctlq_init(struct libie_ctlq_ctx *ctx,
395caed480fSPhani R Burra 		    const struct libie_ctlq_create_info *qinfo,
396caed480fSPhani R Burra 		    u32 numq)
397caed480fSPhani R Burra {
398caed480fSPhani R Burra 	INIT_LIST_HEAD(&ctx->ctlqs);
399caed480fSPhani R Burra 	spin_lock_init(&ctx->ctlqs_lock);
400caed480fSPhani R Burra 
401caed480fSPhani R Burra 	for (u32 i = 0; i < numq; i++) {
402caed480fSPhani R Burra 		struct libie_ctlq_info *ctlq;
403caed480fSPhani R Burra 
404caed480fSPhani R Burra 		ctlq = libie_ctlq_add(ctx, &qinfo[i]);
405caed480fSPhani R Burra 		if (IS_ERR(ctlq)) {
406caed480fSPhani R Burra 			libie_ctlq_deinit(ctx);
407caed480fSPhani R Burra 			return PTR_ERR(ctlq);
408caed480fSPhani R Burra 		}
409caed480fSPhani R Burra 	}
410caed480fSPhani R Burra 
411caed480fSPhani R Burra 	return 0;
412caed480fSPhani R Burra }
413caed480fSPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_init, "LIBIE_CP");
414caed480fSPhani R Burra 
415caed480fSPhani R Burra /**
416caed480fSPhani R Burra  * libie_ctlq_deinit - destroy all control queues
417caed480fSPhani R Burra  * @ctx: libie CP context information
418caed480fSPhani R Burra  */
libie_ctlq_deinit(struct libie_ctlq_ctx * ctx)419caed480fSPhani R Burra void libie_ctlq_deinit(struct libie_ctlq_ctx *ctx)
420caed480fSPhani R Burra {
421caed480fSPhani R Burra 	struct libie_ctlq_info *ctlq, *tmp;
422caed480fSPhani R Burra 
423caed480fSPhani R Burra 	list_for_each_entry_safe(ctlq, tmp, &ctx->ctlqs, list)
424caed480fSPhani R Burra 		libie_ctlq_remove(ctx, ctlq);
425caed480fSPhani R Burra }
426caed480fSPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_deinit, "LIBIE_CP");
427caed480fSPhani R Burra 
428caed480fSPhani R Burra /**
429caed480fSPhani R Burra  * libie_ctlq_tx_desc_from_msg - initialize a Tx descriptor from a message
430caed480fSPhani R Burra  * @desc: descriptor to be initialized
431caed480fSPhani R Burra  * @msg: filled control queue message
432caed480fSPhani R Burra  */
libie_ctlq_tx_desc_from_msg(struct libie_ctlq_desc * desc,const struct libie_ctlq_msg * msg)433caed480fSPhani R Burra static void libie_ctlq_tx_desc_from_msg(struct libie_ctlq_desc *desc,
434caed480fSPhani R Burra 					const struct libie_ctlq_msg *msg)
435caed480fSPhani R Burra {
436caed480fSPhani R Burra 	const struct libie_cp_dma_mem *dma = &msg->send_mem;
437caed480fSPhani R Burra 	u64 qword;
438caed480fSPhani R Burra 
439caed480fSPhani R Burra 	qword = FIELD_PREP(LIBIE_CTLQ_DESC_FLAGS, msg->flags) |
440caed480fSPhani R Burra 		FIELD_PREP(LIBIE_CTLQ_DESC_INFRA_OPCODE, msg->opcode) |
441caed480fSPhani R Burra 		FIELD_PREP(LIBIE_CTLQ_DESC_PFID_VFID, msg->func_id);
442caed480fSPhani R Burra 	desc->qword0 = cpu_to_le64(qword);
443caed480fSPhani R Burra 
444caed480fSPhani R Burra 	qword = FIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_OPCODE,
445caed480fSPhani R Burra 			   msg->chnl_opcode) |
446caed480fSPhani R Burra 		FIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_MSG_RET_VAL,
447caed480fSPhani R Burra 			   msg->chnl_retval);
448caed480fSPhani R Burra 	desc->qword1 = cpu_to_le64(qword);
449caed480fSPhani R Burra 
450caed480fSPhani R Burra 	qword = FIELD_PREP(LIBIE_CTLQ_DESC_MSG_PARAM0, msg->param0) |
451caed480fSPhani R Burra 		FIELD_PREP(LIBIE_CTLQ_DESC_SW_COOKIE,
452caed480fSPhani R Burra 			   msg->sw_cookie) |
453caed480fSPhani R Burra 		FIELD_PREP(LIBIE_CTLQ_DESC_VIRTCHNL_FLAGS,
454caed480fSPhani R Burra 			   msg->virt_flags);
455caed480fSPhani R Burra 	desc->qword2 = cpu_to_le64(qword);
456caed480fSPhani R Burra 
457caed480fSPhani R Burra 	if (likely(msg->data_len)) {
458caed480fSPhani R Burra 		desc->qword0 |=
459caed480fSPhani R Burra 			cpu_to_le64(LIBIE_CTLQ_DESC_QWORD0(msg->data_len));
460caed480fSPhani R Burra 		qword = FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_HIGH,
461caed480fSPhani R Burra 				   upper_32_bits(dma->pa)) |
462caed480fSPhani R Burra 			FIELD_PREP(LIBIE_CTLQ_DESC_DATA_ADDR_LOW,
463caed480fSPhani R Burra 				   lower_32_bits(dma->pa));
464caed480fSPhani R Burra 	} else {
465caed480fSPhani R Burra 		qword = msg->addr_param;
466caed480fSPhani R Burra 	}
467caed480fSPhani R Burra 
468caed480fSPhani R Burra 	desc->qword3 = cpu_to_le64(qword);
469caed480fSPhani R Burra }
470caed480fSPhani R Burra 
471caed480fSPhani R Burra /**
472caed480fSPhani R Burra  * libie_ctlq_send_desc_avail - get number of free descriptors on a Tx ctlq
473caed480fSPhani R Burra  * @ctlq: specific control queue which is going be used for sending messages
474caed480fSPhani R Burra  *
475caed480fSPhani R Burra  * The caller must hold ctlq->lock. Any dependent sending must be done
476caed480fSPhani R Burra  * in the same critical section.
477caed480fSPhani R Burra  *
478caed480fSPhani R Burra  * Return: number of available descriptors/messages on a given control queue.
479caed480fSPhani R Burra  */
libie_ctlq_send_desc_avail(const struct libie_ctlq_info * ctlq)480caed480fSPhani R Burra u32 libie_ctlq_send_desc_avail(const struct libie_ctlq_info *ctlq)
481caed480fSPhani R Burra {
482caed480fSPhani R Burra 	u32 ntu = ctlq->next_to_use, ntc = ctlq->next_to_clean;
483caed480fSPhani R Burra 
484caed480fSPhani R Burra 	lockdep_assert_held(&ctlq->lock);
485caed480fSPhani R Burra 
486caed480fSPhani R Burra 	return (ntc > ntu ? 0 : ctlq->ring_len) + ntc - ntu - 1;
487caed480fSPhani R Burra }
488caed480fSPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_send_desc_avail, "LIBIE_CP");
489caed480fSPhani R Burra 
490caed480fSPhani R Burra /**
491caed480fSPhani R Burra  * libie_ctlq_send - send a message to Control Plane or Peer
492caed480fSPhani R Burra  * @ctlq: specific control queue which is used for sending a message
493caed480fSPhani R Burra  * @num_q_msg: number of messages present to send on @ctlq,
494caed480fSPhani R Burra  *	       positive and no greater than the number of available descriptors
495caed480fSPhani R Burra  *
496caed480fSPhani R Burra  * The caller must fill in @num_q_msg Tx messages starting at ntu beforehand.
497caed480fSPhani R Burra  *
498caed480fSPhani R Burra  * The caller must hold ctlq->lock. The intended pattern is to first check
499caed480fSPhani R Burra  * the number of descriptors available, then fill in the messages and perform
500caed480fSPhani R Burra  * send within a single critical section.
501caed480fSPhani R Burra  */
libie_ctlq_send(struct libie_ctlq_info * ctlq,u32 num_q_msg)502caed480fSPhani R Burra void libie_ctlq_send(struct libie_ctlq_info *ctlq, u32 num_q_msg)
503caed480fSPhani R Burra {
504caed480fSPhani R Burra 	u32 ntu = ctlq->next_to_use;
505caed480fSPhani R Burra 
506caed480fSPhani R Burra 	lockdep_assert_held(&ctlq->lock);
507caed480fSPhani R Burra 
508caed480fSPhani R Burra 	for (int i = 0; i < num_q_msg; i++) {
509caed480fSPhani R Burra 		struct libie_ctlq_msg *msg = ctlq->tx_msg[ntu];
510caed480fSPhani R Burra 		struct libie_ctlq_desc *desc;
511caed480fSPhani R Burra 
512caed480fSPhani R Burra 		desc = &ctlq->descs[ntu];
513caed480fSPhani R Burra 		libie_ctlq_tx_desc_from_msg(desc, msg);
514caed480fSPhani R Burra 
515caed480fSPhani R Burra 		if (unlikely(++ntu == ctlq->ring_len))
516caed480fSPhani R Burra 			ntu = 0;
517caed480fSPhani R Burra 	}
518caed480fSPhani R Burra 	dma_wmb();
519caed480fSPhani R Burra 	writel(ntu, ctlq->reg.tail);
520caed480fSPhani R Burra 	ctlq->next_to_use = ntu;
521caed480fSPhani R Burra }
522caed480fSPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_send, "LIBIE_CP");
523caed480fSPhani R Burra 
524caed480fSPhani R Burra /**
525caed480fSPhani R Burra  * libie_ctlq_send_clean - cleanup the send control queue message buffers
526caed480fSPhani R Burra  * @params: information for handling of Tx completions
527caed480fSPhani R Burra  *
528caed480fSPhani R Burra  * Cleanup the send buffers for the given control queue, if force is set, then
529caed480fSPhani R Burra  * clear all the outstanding send messages irrespective of their send status,
530caed480fSPhani R Burra  * until a zero-length message is encountered, which is either a message that
531caed480fSPhani R Burra  * is already cleared, or a VF reset message, which is always last.
532caed480fSPhani R Burra  * Force should be used during deinit or reset.
533caed480fSPhani R Burra  *
534caed480fSPhani R Burra  * Return: number of send buffers cleaned.
535caed480fSPhani R Burra  */
libie_ctlq_send_clean(const struct libie_ctlq_clean_params * params)536caed480fSPhani R Burra u32 libie_ctlq_send_clean(const struct libie_ctlq_clean_params *params)
537caed480fSPhani R Burra {
538caed480fSPhani R Burra 	struct libie_ctlq_info *ctlq = params->ctlq;
539caed480fSPhani R Burra 	u32 ntc, i;
540caed480fSPhani R Burra 
541caed480fSPhani R Burra 	spin_lock(&ctlq->lock);
542caed480fSPhani R Burra 	ntc = ctlq->next_to_clean;
543caed480fSPhani R Burra 
544caed480fSPhani R Burra 	for (i = 0; i < params->num_msgs; i++) {
545caed480fSPhani R Burra 		struct libie_ctlq_msg *msg = ctlq->tx_msg[ntc];
546caed480fSPhani R Burra 		struct libie_ctlq_desc *desc;
547caed480fSPhani R Burra 		u64 qword;
548caed480fSPhani R Burra 
549caed480fSPhani R Burra 		desc = &ctlq->descs[ntc];
550caed480fSPhani R Burra 		qword = le64_to_cpu(desc->qword0);
551caed480fSPhani R Burra 
552caed480fSPhani R Burra 		if (!FIELD_GET(LIBIE_CTLQ_DESC_FLAG_DD, qword) &&
553caed480fSPhani R Burra 		    !(unlikely(params->force) && msg->data_len))
554caed480fSPhani R Burra 			break;
555caed480fSPhani R Burra 
556caed480fSPhani R Burra 		/* This cannot be reordered and lock is taken, so no barriers */
557caed480fSPhani R Burra 		desc->qword0 = 0;
558caed480fSPhani R Burra 
559caed480fSPhani R Burra 		params->rel_dma_mem(params->rel_ctx, &msg->send_mem);
560caed480fSPhani R Burra 		memset(msg, 0, sizeof(*msg));
561caed480fSPhani R Burra 
562caed480fSPhani R Burra 		if (unlikely(++ntc == ctlq->ring_len))
563caed480fSPhani R Burra 			ntc = 0;
564caed480fSPhani R Burra 	}
565caed480fSPhani R Burra 
566caed480fSPhani R Burra 	ctlq->next_to_clean = ntc;
567caed480fSPhani R Burra 	spin_unlock(&ctlq->lock);
568caed480fSPhani R Burra 
569caed480fSPhani R Burra 	return i;
570caed480fSPhani R Burra }
571caed480fSPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_send_clean, "LIBIE_CP");
572caed480fSPhani R Burra 
573caed480fSPhani R Burra /**
574caed480fSPhani R Burra  * libie_ctlq_fill_rx_msg - fill in a message from Rx descriptor and buffer
575caed480fSPhani R Burra  * @msg: message to be filled in
576caed480fSPhani R Burra  * @desc: received descriptor
577caed480fSPhani R Burra  * @rx_buf: fill queue buffer associated with the descriptor
578caed480fSPhani R Burra  */
libie_ctlq_fill_rx_msg(struct libie_ctlq_msg * msg,const struct libie_ctlq_desc * desc,struct libeth_fqe * rx_buf)579caed480fSPhani R Burra static void libie_ctlq_fill_rx_msg(struct libie_ctlq_msg *msg,
580caed480fSPhani R Burra 				   const struct libie_ctlq_desc *desc,
581caed480fSPhani R Burra 				   struct libeth_fqe *rx_buf)
582caed480fSPhani R Burra {
583caed480fSPhani R Burra 	u64 qword = le64_to_cpu(desc->qword0);
584caed480fSPhani R Burra 
585caed480fSPhani R Burra 	msg->flags = FIELD_GET(LIBIE_CTLQ_DESC_FLAGS, qword);
586caed480fSPhani R Burra 	msg->opcode = FIELD_GET(LIBIE_CTLQ_DESC_INFRA_OPCODE, qword);
587caed480fSPhani R Burra 	msg->data_len = FIELD_GET(LIBIE_CTLQ_DESC_DATA_LEN, qword);
588caed480fSPhani R Burra 	msg->hw_retval = FIELD_GET(LIBIE_CTLQ_DESC_HW_RETVAL, qword);
589caed480fSPhani R Burra 
590caed480fSPhani R Burra 	qword = le64_to_cpu(desc->qword1);
591caed480fSPhani R Burra 	msg->chnl_opcode =
592caed480fSPhani R Burra 		FIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_OPCODE, qword);
593caed480fSPhani R Burra 	msg->chnl_retval =
594caed480fSPhani R Burra 		FIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_MSG_RET_VAL, qword);
595caed480fSPhani R Burra 
596caed480fSPhani R Burra 	qword = le64_to_cpu(desc->qword2);
597caed480fSPhani R Burra 	msg->param0 =
598caed480fSPhani R Burra 		FIELD_GET(LIBIE_CTLQ_DESC_MSG_PARAM0, qword);
599caed480fSPhani R Burra 	msg->sw_cookie =
600caed480fSPhani R Burra 		FIELD_GET(LIBIE_CTLQ_DESC_SW_COOKIE, qword);
601caed480fSPhani R Burra 	msg->virt_flags =
602caed480fSPhani R Burra 		FIELD_GET(LIBIE_CTLQ_DESC_VIRTCHNL_FLAGS, qword);
603caed480fSPhani R Burra 
604caed480fSPhani R Burra 	if (likely(msg->data_len)) {
605caed480fSPhani R Burra 		if (unlikely(msg->data_len > LIBIE_CTLQ_MAX_BUF_LEN)) {
606caed480fSPhani R Burra 			msg->data_len = LIBIE_CTLQ_MAX_BUF_LEN;
607caed480fSPhani R Burra 			msg->chnl_retval = U32_MAX;
608caed480fSPhani R Burra 		}
609caed480fSPhani R Burra 		msg->recv_mem = (struct kvec) {
610caed480fSPhani R Burra 			.iov_base = netmem_address(rx_buf->netmem) +
611caed480fSPhani R Burra 				    rx_buf->offset,
612caed480fSPhani R Burra 			.iov_len = msg->data_len,
613caed480fSPhani R Burra 		};
614caed480fSPhani R Burra 		libeth_rx_sync_for_cpu(rx_buf, msg->data_len);
615caed480fSPhani R Burra 	} else {
616caed480fSPhani R Burra 		msg->recv_mem = (struct kvec) {};
617caed480fSPhani R Burra 		msg->addr_param = le64_to_cpu(desc->qword3);
618caed480fSPhani R Burra 		page_pool_put_full_netmem(netmem_get_pp(rx_buf->netmem),
619caed480fSPhani R Burra 					  rx_buf->netmem, false);
620caed480fSPhani R Burra 	}
621caed480fSPhani R Burra }
622caed480fSPhani R Burra 
623caed480fSPhani R Burra /**
624caed480fSPhani R Burra  * libie_ctlq_recv - receive control queue messages
625caed480fSPhani R Burra  * @ctlq: control queue that needs to processed for receive
626caed480fSPhani R Burra  * @msg: array of received control queue messages on this q;
627caed480fSPhani R Burra  *	 needs to be pre-allocated by caller for as many messages as requested
628caed480fSPhani R Burra  * @num_q_msg: number of messages that can be stored in msg buffer,
629caed480fSPhani R Burra  *	       no greater than number of posted buffers
630caed480fSPhani R Burra  *
631caed480fSPhani R Burra  * Caller is expected to return buffers via libie_ctlq_release_rx_buf().
632caed480fSPhani R Burra  *
633caed480fSPhani R Burra  * The caller must make sure that calls to libie_ctlq_post_rx_buffs()
634caed480fSPhani R Burra  * and libie_ctlq_recv() for each queue are either serialized
635caed480fSPhani R Burra  * or used under ctlq->lock.
636caed480fSPhani R Burra  *
637caed480fSPhani R Burra  * Return: number of messages received
638caed480fSPhani R Burra  */
libie_ctlq_recv(struct libie_ctlq_info * ctlq,struct libie_ctlq_msg * msg,u32 num_q_msg)639caed480fSPhani R Burra u32 libie_ctlq_recv(struct libie_ctlq_info *ctlq, struct libie_ctlq_msg *msg,
640caed480fSPhani R Burra 		    u32 num_q_msg)
641caed480fSPhani R Burra {
642caed480fSPhani R Burra 	u32 ntc, i;
643caed480fSPhani R Burra 
644caed480fSPhani R Burra 	ntc = ctlq->next_to_clean;
645caed480fSPhani R Burra 
646caed480fSPhani R Burra 	for (i = 0; i < num_q_msg; i++) {
647caed480fSPhani R Burra 		struct libie_ctlq_desc *desc = &ctlq->descs[ntc];
648caed480fSPhani R Burra 		struct libeth_fqe *rx_buf = &ctlq->rx_fqes[ntc];
649caed480fSPhani R Burra 		u64 qword;
650caed480fSPhani R Burra 
651caed480fSPhani R Burra 		qword = le64_to_cpu(desc->qword0);
652caed480fSPhani R Burra 		if (!FIELD_GET(LIBIE_CTLQ_DESC_FLAG_DD, qword))
653caed480fSPhani R Burra 			break;
654caed480fSPhani R Burra 
655caed480fSPhani R Burra 		dma_rmb();
656caed480fSPhani R Burra 
657caed480fSPhani R Burra 		libie_ctlq_fill_rx_msg(&msg[i], desc, rx_buf);
658caed480fSPhani R Burra 		desc->qword0 = 0;
659caed480fSPhani R Burra 
660caed480fSPhani R Burra 		if (unlikely(++ntc == ctlq->ring_len))
661caed480fSPhani R Burra 			ntc = 0;
662caed480fSPhani R Burra 	}
663caed480fSPhani R Burra 
664caed480fSPhani R Burra 	ctlq->next_to_clean = ntc;
665caed480fSPhani R Burra 
666caed480fSPhani R Burra 	return i;
667caed480fSPhani R Burra }
668caed480fSPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_recv, "LIBIE_CP");
669caed480fSPhani R Burra 
670*b4ff4e62SPhani R Burra /**
671*b4ff4e62SPhani R Burra  * libie_ctlq_xn_pop_free - get a free Xn entry from the free list
672*b4ff4e62SPhani R Burra  * @xnm: Xn transaction manager
673*b4ff4e62SPhani R Burra  *
674*b4ff4e62SPhani R Burra  * Retrieve a free Xn entry from the free list.
675*b4ff4e62SPhani R Burra  *
676*b4ff4e62SPhani R Burra  * Return: valid Xn entry pointer or NULL if there are no free Xn entries.
677*b4ff4e62SPhani R Burra  */
678*b4ff4e62SPhani R Burra static struct libie_ctlq_xn *
libie_ctlq_xn_pop_free(struct libie_ctlq_xn_manager * xnm)679*b4ff4e62SPhani R Burra libie_ctlq_xn_pop_free(struct libie_ctlq_xn_manager *xnm)
680*b4ff4e62SPhani R Burra {
681*b4ff4e62SPhani R Burra 	struct libie_ctlq_xn *xn;
682*b4ff4e62SPhani R Burra 	u32 free_idx;
683*b4ff4e62SPhani R Burra 
684*b4ff4e62SPhani R Burra 	guard(spinlock)(&xnm->free_xns_bm_lock);
685*b4ff4e62SPhani R Burra 
686*b4ff4e62SPhani R Burra 	if (unlikely(xnm->shutdown))
687*b4ff4e62SPhani R Burra 		return NULL;
688*b4ff4e62SPhani R Burra 
689*b4ff4e62SPhani R Burra 	for_each_set_bit(free_idx, xnm->free_xns_bm,
690*b4ff4e62SPhani R Burra 			 LIBIE_CTLQ_MAX_XN_ENTRIES) {
691*b4ff4e62SPhani R Burra 		xn = &xnm->ring[free_idx];
692*b4ff4e62SPhani R Burra 
693*b4ff4e62SPhani R Burra 		/* Torn read of the physical address is possible, the worst case
694*b4ff4e62SPhani R Burra 		 * scenario is a transient spurious skip. If the physical
695*b4ff4e62SPhani R Burra 		 * address is dirty in any way, reuse is already safe.
696*b4ff4e62SPhani R Burra 		 */
697*b4ff4e62SPhani R Burra 		if (xn->tx_msg &&
698*b4ff4e62SPhani R Burra 		    data_race(xn->tx_msg->send_mem.pa) == xn->small_dma_mem.pa)
699*b4ff4e62SPhani R Burra 			continue;
700*b4ff4e62SPhani R Burra 
701*b4ff4e62SPhani R Burra 		clear_bit(free_idx, xnm->free_xns_bm);
702*b4ff4e62SPhani R Burra 
703*b4ff4e62SPhani R Burra 		return xn;
704*b4ff4e62SPhani R Burra 	}
705*b4ff4e62SPhani R Burra 
706*b4ff4e62SPhani R Burra 	return NULL;
707*b4ff4e62SPhani R Burra }
708*b4ff4e62SPhani R Burra 
709*b4ff4e62SPhani R Burra /**
710*b4ff4e62SPhani R Burra  * __libie_ctlq_xn_push_free - unsafely push an xn entry into the free list
711*b4ff4e62SPhani R Burra  * @xnm: Xn transaction manager
712*b4ff4e62SPhani R Burra  * @xn: xn entry to be added into the free list
713*b4ff4e62SPhani R Burra  *
714*b4ff4e62SPhani R Burra  * Return: whether xnm destruction can be triggered by the caller
715*b4ff4e62SPhani R Burra  */
__libie_ctlq_xn_push_free(struct libie_ctlq_xn_manager * xnm,struct libie_ctlq_xn * xn)716*b4ff4e62SPhani R Burra static bool __libie_ctlq_xn_push_free(struct libie_ctlq_xn_manager *xnm,
717*b4ff4e62SPhani R Burra 				      struct libie_ctlq_xn *xn)
718*b4ff4e62SPhani R Burra {
719*b4ff4e62SPhani R Burra 	xn->cookie++;
720*b4ff4e62SPhani R Burra 	set_bit(xn->index, xnm->free_xns_bm);
721*b4ff4e62SPhani R Burra 
722*b4ff4e62SPhani R Burra 	if (unlikely(xnm->shutdown) &&
723*b4ff4e62SPhani R Burra 	    bitmap_full(xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES))
724*b4ff4e62SPhani R Burra 		return true;
725*b4ff4e62SPhani R Burra 
726*b4ff4e62SPhani R Burra 	return false;
727*b4ff4e62SPhani R Burra }
728*b4ff4e62SPhani R Burra 
729*b4ff4e62SPhani R Burra /**
730*b4ff4e62SPhani R Burra  * libie_ctlq_xn_push_free - push a Xn entry into the free list
731*b4ff4e62SPhani R Burra  * @xnm: Xn transaction manager
732*b4ff4e62SPhani R Burra  * @xn: xn entry to be added into the free list, not locked
733*b4ff4e62SPhani R Burra  *
734*b4ff4e62SPhani R Burra  * Safely add a used Xn entry back to the free list.
735*b4ff4e62SPhani R Burra  */
libie_ctlq_xn_push_free(struct libie_ctlq_xn_manager * xnm,struct libie_ctlq_xn * xn)736*b4ff4e62SPhani R Burra static void libie_ctlq_xn_push_free(struct libie_ctlq_xn_manager *xnm,
737*b4ff4e62SPhani R Burra 				    struct libie_ctlq_xn *xn)
738*b4ff4e62SPhani R Burra {
739*b4ff4e62SPhani R Burra 	bool can_destroy;
740*b4ff4e62SPhani R Burra 
741*b4ff4e62SPhani R Burra 	scoped_guard(spinlock, &xnm->free_xns_bm_lock)
742*b4ff4e62SPhani R Burra 		can_destroy = __libie_ctlq_xn_push_free(xnm, xn);
743*b4ff4e62SPhani R Burra 
744*b4ff4e62SPhani R Burra 	if (can_destroy)
745*b4ff4e62SPhani R Burra 		complete(&xnm->can_destroy);
746*b4ff4e62SPhani R Burra }
747*b4ff4e62SPhani R Burra 
748*b4ff4e62SPhani R Burra /**
749*b4ff4e62SPhani R Burra  * libie_ctlq_xn_deinit_dma - free the DMA memory allocated for send messages
750*b4ff4e62SPhani R Burra  * @xnm: pointer to the transaction manager
751*b4ff4e62SPhani R Burra  * @num_entries: number of Xn entries to free the DMA for
752*b4ff4e62SPhani R Burra  */
libie_ctlq_xn_deinit_dma(struct libie_ctlq_xn_manager * xnm,u32 num_entries)753*b4ff4e62SPhani R Burra static void libie_ctlq_xn_deinit_dma(struct libie_ctlq_xn_manager *xnm,
754*b4ff4e62SPhani R Burra 				     u32 num_entries)
755*b4ff4e62SPhani R Burra {
756*b4ff4e62SPhani R Burra 	for (u32 i = 0; i < num_entries; i++) {
757*b4ff4e62SPhani R Burra 		struct libie_ctlq_xn *xn = &xnm->ring[i];
758*b4ff4e62SPhani R Burra 
759*b4ff4e62SPhani R Burra 		dma_pool_free(xnm->small_buff_pool, xn->small_dma_mem.va,
760*b4ff4e62SPhani R Burra 			      xn->small_dma_mem.pa);
761*b4ff4e62SPhani R Burra 	}
762*b4ff4e62SPhani R Burra 
763*b4ff4e62SPhani R Burra 	dma_pool_destroy(xnm->small_buff_pool);
764*b4ff4e62SPhani R Burra }
765*b4ff4e62SPhani R Burra 
766*b4ff4e62SPhani R Burra /**
767*b4ff4e62SPhani R Burra  * libie_ctlq_xn_init_dma - pre-allocate DMA memory for send messages that use
768*b4ff4e62SPhani R Burra  * stack variables
769*b4ff4e62SPhani R Burra  * @dev: device pointer
770*b4ff4e62SPhani R Burra  * @xnm: pointer to transaction manager
771*b4ff4e62SPhani R Burra  *
772*b4ff4e62SPhani R Burra  * Return: %0 on success or error if memory allocation fails
773*b4ff4e62SPhani R Burra  */
libie_ctlq_xn_init_dma(struct device * dev,struct libie_ctlq_xn_manager * xnm)774*b4ff4e62SPhani R Burra static int libie_ctlq_xn_init_dma(struct device *dev,
775*b4ff4e62SPhani R Burra 				  struct libie_ctlq_xn_manager *xnm)
776*b4ff4e62SPhani R Burra {
777*b4ff4e62SPhani R Burra 	u32 i;
778*b4ff4e62SPhani R Burra 
779*b4ff4e62SPhani R Burra 	xnm->small_buff_pool =
780*b4ff4e62SPhani R Burra 		dma_pool_create("libie_ctlq_xn_tx", dev, LIBIE_CP_TX_COPYBREAK,
781*b4ff4e62SPhani R Burra 				LIBIE_CP_TX_COPYBREAK, 0);
782*b4ff4e62SPhani R Burra 	if (!xnm->small_buff_pool)
783*b4ff4e62SPhani R Burra 		return -ENOMEM;
784*b4ff4e62SPhani R Burra 
785*b4ff4e62SPhani R Burra 	for (i = 0; i < LIBIE_CTLQ_MAX_XN_ENTRIES; i++) {
786*b4ff4e62SPhani R Burra 		struct libie_cp_dma_mem *mem = &xnm->ring[i].small_dma_mem;
787*b4ff4e62SPhani R Burra 
788*b4ff4e62SPhani R Burra 		mem->va = dma_pool_zalloc(xnm->small_buff_pool, GFP_KERNEL,
789*b4ff4e62SPhani R Burra 					  &mem->pa);
790*b4ff4e62SPhani R Burra 		if (!mem->va)
791*b4ff4e62SPhani R Burra 			goto dealloc_dma;
792*b4ff4e62SPhani R Burra 
793*b4ff4e62SPhani R Burra 		mem->direction = DMA_BIDIRECTIONAL;
794*b4ff4e62SPhani R Burra 		mem->size = LIBIE_CP_TX_COPYBREAK;
795*b4ff4e62SPhani R Burra 	}
796*b4ff4e62SPhani R Burra 
797*b4ff4e62SPhani R Burra 	return 0;
798*b4ff4e62SPhani R Burra 
799*b4ff4e62SPhani R Burra dealloc_dma:
800*b4ff4e62SPhani R Burra 	libie_ctlq_xn_deinit_dma(xnm, i);
801*b4ff4e62SPhani R Burra 
802*b4ff4e62SPhani R Burra 	return -ENOMEM;
803*b4ff4e62SPhani R Burra }
804*b4ff4e62SPhani R Burra 
805*b4ff4e62SPhani R Burra /**
806*b4ff4e62SPhani R Burra  * libie_ctlq_xn_process_recv - process Xn data in receive message
807*b4ff4e62SPhani R Burra  * @params: Xn receive param information to handle a receive message
808*b4ff4e62SPhani R Burra  * @ctlq_msg: received control queue message
809*b4ff4e62SPhani R Burra  *
810*b4ff4e62SPhani R Burra  * Process a control queue receive message and send a complete event
811*b4ff4e62SPhani R Burra  * notification.
812*b4ff4e62SPhani R Burra  *
813*b4ff4e62SPhani R Burra  * Return: true if a message has been processed, false otherwise.
814*b4ff4e62SPhani R Burra  */
815*b4ff4e62SPhani R Burra static bool
libie_ctlq_xn_process_recv(struct libie_ctlq_xn_recv_params * params,struct libie_ctlq_msg * ctlq_msg)816*b4ff4e62SPhani R Burra libie_ctlq_xn_process_recv(struct libie_ctlq_xn_recv_params *params,
817*b4ff4e62SPhani R Burra 			   struct libie_ctlq_msg *ctlq_msg)
818*b4ff4e62SPhani R Burra {
819*b4ff4e62SPhani R Burra 	struct libie_ctlq_xn_manager *xnm = params->xnm;
820*b4ff4e62SPhani R Burra 	struct libie_ctlq_xn *xn;
821*b4ff4e62SPhani R Burra 	u16 msg_cookie, xn_index;
822*b4ff4e62SPhani R Burra 	struct kvec *response;
823*b4ff4e62SPhani R Burra 	int status;
824*b4ff4e62SPhani R Burra 	u16 data;
825*b4ff4e62SPhani R Burra 
826*b4ff4e62SPhani R Burra 	data = ctlq_msg->sw_cookie;
827*b4ff4e62SPhani R Burra 	xn_index = FIELD_GET(LIBIE_CTLQ_XN_INDEX_M, data);
828*b4ff4e62SPhani R Burra 	msg_cookie = FIELD_GET(LIBIE_CTLQ_XN_COOKIE_M, data);
829*b4ff4e62SPhani R Burra 	status = ctlq_msg->chnl_retval ? -EFAULT : 0;
830*b4ff4e62SPhani R Burra 
831*b4ff4e62SPhani R Burra 	xn = &xnm->ring[xn_index];
832*b4ff4e62SPhani R Burra 	spin_lock(&xn->xn_lock);
833*b4ff4e62SPhani R Burra 	if (ctlq_msg->chnl_opcode != xn->virtchnl_opcode ||
834*b4ff4e62SPhani R Burra 	    msg_cookie != xn->cookie) {
835*b4ff4e62SPhani R Burra 		spin_unlock(&xn->xn_lock);
836*b4ff4e62SPhani R Burra 		return false;
837*b4ff4e62SPhani R Burra 	}
838*b4ff4e62SPhani R Burra 
839*b4ff4e62SPhani R Burra 	if (xn->state != LIBIE_CTLQ_XN_ASYNC &&
840*b4ff4e62SPhani R Burra 	    xn->state != LIBIE_CTLQ_XN_WAITING) {
841*b4ff4e62SPhani R Burra 		spin_unlock(&xn->xn_lock);
842*b4ff4e62SPhani R Burra 		return false;
843*b4ff4e62SPhani R Burra 	}
844*b4ff4e62SPhani R Burra 
845*b4ff4e62SPhani R Burra 	response = &ctlq_msg->recv_mem;
846*b4ff4e62SPhani R Burra 	if (xn->state == LIBIE_CTLQ_XN_ASYNC) {
847*b4ff4e62SPhani R Burra 		xn->resp_cb(xn->send_ctx, response, status);
848*b4ff4e62SPhani R Burra 		libie_ctlq_release_rx_buf(response);
849*b4ff4e62SPhani R Burra 		xn->state = LIBIE_CTLQ_XN_IDLE;
850*b4ff4e62SPhani R Burra 		spin_unlock(&xn->xn_lock);
851*b4ff4e62SPhani R Burra 		libie_ctlq_xn_push_free(xnm, xn);
852*b4ff4e62SPhani R Burra 
853*b4ff4e62SPhani R Burra 		return true;
854*b4ff4e62SPhani R Burra 	}
855*b4ff4e62SPhani R Burra 
856*b4ff4e62SPhani R Burra 	xn->recv_mem = *response;
857*b4ff4e62SPhani R Burra 	xn->state = status ? LIBIE_CTLQ_XN_COMPLETED_FAILED :
858*b4ff4e62SPhani R Burra 			     LIBIE_CTLQ_XN_COMPLETED_SUCCESS;
859*b4ff4e62SPhani R Burra 
860*b4ff4e62SPhani R Burra 	complete(&xn->cmd_completion_event);
861*b4ff4e62SPhani R Burra 	spin_unlock(&xn->xn_lock);
862*b4ff4e62SPhani R Burra 
863*b4ff4e62SPhani R Burra 	return true;
864*b4ff4e62SPhani R Burra }
865*b4ff4e62SPhani R Burra 
866*b4ff4e62SPhani R Burra /**
867*b4ff4e62SPhani R Burra  * libie_xn_check_async_timeout - Check for asynchronous message timeouts
868*b4ff4e62SPhani R Burra  * @xnm: Xn transaction manager
869*b4ff4e62SPhani R Burra  *
870*b4ff4e62SPhani R Burra  * Call the corresponding callback to notify the caller about the timeout.
871*b4ff4e62SPhani R Burra  * Iterates free_xns_bm locklessly, potential races are caught under
872*b4ff4e62SPhani R Burra  * xn->xn_lock.
873*b4ff4e62SPhani R Burra  */
libie_xn_check_async_timeout(struct libie_ctlq_xn_manager * xnm)874*b4ff4e62SPhani R Burra static void libie_xn_check_async_timeout(struct libie_ctlq_xn_manager *xnm)
875*b4ff4e62SPhani R Burra {
876*b4ff4e62SPhani R Burra 	u32 idx;
877*b4ff4e62SPhani R Burra 
878*b4ff4e62SPhani R Burra 	for_each_clear_bit(idx, xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES) {
879*b4ff4e62SPhani R Burra 		struct libie_ctlq_xn *xn = &xnm->ring[idx];
880*b4ff4e62SPhani R Burra 		u64 timeout_ms;
881*b4ff4e62SPhani R Burra 
882*b4ff4e62SPhani R Burra 		spin_lock(&xn->xn_lock);
883*b4ff4e62SPhani R Burra 
884*b4ff4e62SPhani R Burra 		timeout_ms = ktime_ms_delta(ktime_get(), xn->timestamp);
885*b4ff4e62SPhani R Burra 		if (xn->state != LIBIE_CTLQ_XN_ASYNC ||
886*b4ff4e62SPhani R Burra 		    timeout_ms < xn->timeout_ms) {
887*b4ff4e62SPhani R Burra 			spin_unlock(&xn->xn_lock);
888*b4ff4e62SPhani R Burra 			continue;
889*b4ff4e62SPhani R Burra 		}
890*b4ff4e62SPhani R Burra 
891*b4ff4e62SPhani R Burra 		xn->resp_cb(xn->send_ctx, NULL, -ETIMEDOUT);
892*b4ff4e62SPhani R Burra 		xn->state = LIBIE_CTLQ_XN_IDLE;
893*b4ff4e62SPhani R Burra 		spin_unlock(&xn->xn_lock);
894*b4ff4e62SPhani R Burra 		libie_ctlq_xn_push_free(xnm, xn);
895*b4ff4e62SPhani R Burra 	}
896*b4ff4e62SPhani R Burra }
897*b4ff4e62SPhani R Burra 
898*b4ff4e62SPhani R Burra /**
899*b4ff4e62SPhani R Burra  * libie_ctlq_xn_recv - process control queue receive message
900*b4ff4e62SPhani R Burra  * @params: Xn receive param information to handle a receive message
901*b4ff4e62SPhani R Burra  *
902*b4ff4e62SPhani R Burra  * Process a receive message and update the receive queue buffer.
903*b4ff4e62SPhani R Burra  * Also terminates async transactions for which it failed to receive a response
904*b4ff4e62SPhani R Burra  * within a given timeframe.
905*b4ff4e62SPhani R Burra  * Function is intended to be called periodically from a single task.
906*b4ff4e62SPhani R Burra  *
907*b4ff4e62SPhani R Burra  * Return: remaining budget.
908*b4ff4e62SPhani R Burra  */
libie_ctlq_xn_recv(struct libie_ctlq_xn_recv_params * params)909*b4ff4e62SPhani R Burra u32 libie_ctlq_xn_recv(struct libie_ctlq_xn_recv_params *params)
910*b4ff4e62SPhani R Burra {
911*b4ff4e62SPhani R Burra 	struct libie_ctlq_msg ctlq_msg;
912*b4ff4e62SPhani R Burra 	u32 budget = params->budget;
913*b4ff4e62SPhani R Burra 
914*b4ff4e62SPhani R Burra 	while (budget && libie_ctlq_recv(params->ctlq, &ctlq_msg, 1)) {
915*b4ff4e62SPhani R Burra 		budget--;
916*b4ff4e62SPhani R Burra 		if (!libie_ctlq_xn_process_recv(params, &ctlq_msg))
917*b4ff4e62SPhani R Burra 			params->ctlq_msg_handler(params->xnm->ctx, &ctlq_msg);
918*b4ff4e62SPhani R Burra 	}
919*b4ff4e62SPhani R Burra 
920*b4ff4e62SPhani R Burra 	libie_ctlq_post_rx_buffs(params->ctlq);
921*b4ff4e62SPhani R Burra 	libie_xn_check_async_timeout(params->xnm);
922*b4ff4e62SPhani R Burra 
923*b4ff4e62SPhani R Burra 	return budget;
924*b4ff4e62SPhani R Burra }
925*b4ff4e62SPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_recv, "LIBIE_CP");
926*b4ff4e62SPhani R Burra 
927*b4ff4e62SPhani R Burra /**
928*b4ff4e62SPhani R Burra  * libie_cp_map_dma_mem - map a given virtual address for DMA
929*b4ff4e62SPhani R Burra  * @dev: device information
930*b4ff4e62SPhani R Burra  * @va: virtual address to be mapped
931*b4ff4e62SPhani R Burra  * @size: size of the memory
932*b4ff4e62SPhani R Burra  * @direction: DMA direction either from/to device
933*b4ff4e62SPhani R Burra  * @dma_mem: memory for DMA information to be stored
934*b4ff4e62SPhani R Burra  *
935*b4ff4e62SPhani R Burra  * Return: true on success, false on DMA map failure.
936*b4ff4e62SPhani R Burra  */
libie_cp_map_dma_mem(struct device * dev,void * va,size_t size,int direction,struct libie_cp_dma_mem * dma_mem)937*b4ff4e62SPhani R Burra static bool libie_cp_map_dma_mem(struct device *dev, void *va, size_t size,
938*b4ff4e62SPhani R Burra 				 int direction,
939*b4ff4e62SPhani R Burra 				 struct libie_cp_dma_mem *dma_mem)
940*b4ff4e62SPhani R Burra {
941*b4ff4e62SPhani R Burra 	dma_mem->pa = dma_map_single(dev, va, size, direction);
942*b4ff4e62SPhani R Burra 
943*b4ff4e62SPhani R Burra 	return dma_mapping_error(dev, dma_mem->pa) ? false : true;
944*b4ff4e62SPhani R Burra }
945*b4ff4e62SPhani R Burra 
946*b4ff4e62SPhani R Burra /**
947*b4ff4e62SPhani R Burra  * libie_cp_unmap_dma_mem - unmap previously mapped DMA address
948*b4ff4e62SPhani R Burra  * @dev: device information
949*b4ff4e62SPhani R Burra  * @dma_mem: DMA memory information
950*b4ff4e62SPhani R Burra  */
libie_cp_unmap_dma_mem(struct device * dev,const struct libie_cp_dma_mem * dma_mem)951*b4ff4e62SPhani R Burra static void libie_cp_unmap_dma_mem(struct device *dev,
952*b4ff4e62SPhani R Burra 				   const struct libie_cp_dma_mem *dma_mem)
953*b4ff4e62SPhani R Burra {
954*b4ff4e62SPhani R Burra 	dma_unmap_single(dev, dma_mem->pa, dma_mem->size,
955*b4ff4e62SPhani R Burra 			 dma_mem->direction);
956*b4ff4e62SPhani R Burra }
957*b4ff4e62SPhani R Burra 
958*b4ff4e62SPhani R Burra /**
959*b4ff4e62SPhani R Burra  * libie_ctlq_xn_process_send - process and send a control queue message
960*b4ff4e62SPhani R Burra  * @params: Xn send param information for sending a control queue message
961*b4ff4e62SPhani R Burra  * @xn: Assigned Xn entry for tracking the control queue message
962*b4ff4e62SPhani R Burra  *
963*b4ff4e62SPhani R Burra  * Return: %0 on success, -%errno on failure.
964*b4ff4e62SPhani R Burra  */
965*b4ff4e62SPhani R Burra static
libie_ctlq_xn_process_send(struct libie_ctlq_xn_send_params * params,struct libie_ctlq_xn * xn)966*b4ff4e62SPhani R Burra int libie_ctlq_xn_process_send(struct libie_ctlq_xn_send_params *params,
967*b4ff4e62SPhani R Burra 			       struct libie_ctlq_xn *xn)
968*b4ff4e62SPhani R Burra {
969*b4ff4e62SPhani R Burra 	size_t buf_len = params->send_buf.iov_len;
970*b4ff4e62SPhani R Burra 	struct device *dev = params->ctlq->dev;
971*b4ff4e62SPhani R Burra 	void *buf = params->send_buf.iov_base;
972*b4ff4e62SPhani R Burra 	struct libie_cp_dma_mem *dma_mem;
973*b4ff4e62SPhani R Burra 	u16 cookie;
974*b4ff4e62SPhani R Burra 
975*b4ff4e62SPhani R Burra 	if (!buf || !buf_len)
976*b4ff4e62SPhani R Burra 		return -EOPNOTSUPP;
977*b4ff4e62SPhani R Burra 
978*b4ff4e62SPhani R Burra 	if (libie_cp_can_send_onstack(buf_len)) {
979*b4ff4e62SPhani R Burra 		dma_mem = &xn->small_dma_mem;
980*b4ff4e62SPhani R Burra 		memcpy(dma_mem->va, buf, buf_len);
981*b4ff4e62SPhani R Burra 	} else {
982*b4ff4e62SPhani R Burra 		dma_mem = &xn->send_dma_mem;
983*b4ff4e62SPhani R Burra 		dma_mem->va = buf;
984*b4ff4e62SPhani R Burra 		dma_mem->size = buf_len;
985*b4ff4e62SPhani R Burra 		dma_mem->direction = DMA_TO_DEVICE;
986*b4ff4e62SPhani R Burra 
987*b4ff4e62SPhani R Burra 		if (!libie_cp_map_dma_mem(dev, buf, buf_len, DMA_TO_DEVICE,
988*b4ff4e62SPhani R Burra 					  dma_mem))
989*b4ff4e62SPhani R Burra 			return -ENOMEM;
990*b4ff4e62SPhani R Burra 	}
991*b4ff4e62SPhani R Burra 
992*b4ff4e62SPhani R Burra 	cookie = FIELD_PREP(LIBIE_CTLQ_XN_COOKIE_M, xn->cookie) |
993*b4ff4e62SPhani R Burra 		 FIELD_PREP(LIBIE_CTLQ_XN_INDEX_M, xn->index);
994*b4ff4e62SPhani R Burra 
995*b4ff4e62SPhani R Burra 	scoped_guard(spinlock, &params->ctlq->lock) {
996*b4ff4e62SPhani R Burra 		struct libie_ctlq_info *ctlq = params->ctlq;
997*b4ff4e62SPhani R Burra 		struct libie_ctlq_msg *ctlq_msg;
998*b4ff4e62SPhani R Burra 
999*b4ff4e62SPhani R Burra 		if (!libie_ctlq_send_desc_avail(ctlq)) {
1000*b4ff4e62SPhani R Burra 			if (!libie_cp_can_send_onstack(buf_len))
1001*b4ff4e62SPhani R Burra 				libie_cp_unmap_dma_mem(dev, dma_mem);
1002*b4ff4e62SPhani R Burra 
1003*b4ff4e62SPhani R Burra 			return -EBUSY;
1004*b4ff4e62SPhani R Burra 		}
1005*b4ff4e62SPhani R Burra 
1006*b4ff4e62SPhani R Burra 		ctlq_msg = ctlq->tx_msg[ctlq->next_to_use];
1007*b4ff4e62SPhani R Burra 		xn->tx_msg = dma_mem == &xn->small_dma_mem ? ctlq_msg : NULL;
1008*b4ff4e62SPhani R Burra 		if (params->ctlq_msg)
1009*b4ff4e62SPhani R Burra 			*ctlq_msg = *params->ctlq_msg;
1010*b4ff4e62SPhani R Burra 		else
1011*b4ff4e62SPhani R Burra 			/* Unused ctlq messages are already zeroed */
1012*b4ff4e62SPhani R Burra 			ctlq_msg->opcode = LIBIE_CTLQ_SEND_MSG_TO_CP;
1013*b4ff4e62SPhani R Burra 
1014*b4ff4e62SPhani R Burra 		ctlq_msg->sw_cookie = cookie;
1015*b4ff4e62SPhani R Burra 		ctlq_msg->send_mem = *dma_mem;
1016*b4ff4e62SPhani R Burra 		ctlq_msg->data_len = buf_len;
1017*b4ff4e62SPhani R Burra 		ctlq_msg->chnl_opcode = params->chnl_opcode;
1018*b4ff4e62SPhani R Burra 		libie_ctlq_send(params->ctlq, 1);
1019*b4ff4e62SPhani R Burra 	}
1020*b4ff4e62SPhani R Burra 
1021*b4ff4e62SPhani R Burra 	return 0;
1022*b4ff4e62SPhani R Burra }
1023*b4ff4e62SPhani R Burra 
1024*b4ff4e62SPhani R Burra /**
1025*b4ff4e62SPhani R Burra  * libie_ctlq_xn_send - send a control queue message, initiating a transaction
1026*b4ff4e62SPhani R Burra  * @params: Xn send param information for sending a control queue message
1027*b4ff4e62SPhani R Burra  *
1028*b4ff4e62SPhani R Burra  * Send a control queue (mailbox or config) message.
1029*b4ff4e62SPhani R Burra  * Based on the params value, the call can be completed synchronously or
1030*b4ff4e62SPhani R Burra  * asynchronously.
1031*b4ff4e62SPhani R Burra  *
1032*b4ff4e62SPhani R Burra  * Return: %0 on success, -%errno on failure.
1033*b4ff4e62SPhani R Burra  */
libie_ctlq_xn_send(struct libie_ctlq_xn_send_params * params)1034*b4ff4e62SPhani R Burra int libie_ctlq_xn_send(struct libie_ctlq_xn_send_params *params)
1035*b4ff4e62SPhani R Burra {
1036*b4ff4e62SPhani R Burra 	bool free_send = !libie_cp_can_send_onstack(params->send_buf.iov_len);
1037*b4ff4e62SPhani R Burra 	struct libie_ctlq_xn *xn;
1038*b4ff4e62SPhani R Burra 	int ret;
1039*b4ff4e62SPhani R Burra 
1040*b4ff4e62SPhani R Burra 	if (params->send_buf.iov_len > LIBIE_CTLQ_MAX_BUF_LEN) {
1041*b4ff4e62SPhani R Burra 		ret = -EINVAL;
1042*b4ff4e62SPhani R Burra 		goto free_buf;
1043*b4ff4e62SPhani R Burra 	}
1044*b4ff4e62SPhani R Burra 
1045*b4ff4e62SPhani R Burra 	xn = libie_ctlq_xn_pop_free(params->xnm);
1046*b4ff4e62SPhani R Burra 	/* no free transactions available */
1047*b4ff4e62SPhani R Burra 	if (unlikely(!xn)) {
1048*b4ff4e62SPhani R Burra 		ret = -EAGAIN;
1049*b4ff4e62SPhani R Burra 		goto free_buf;
1050*b4ff4e62SPhani R Burra 	}
1051*b4ff4e62SPhani R Burra 
1052*b4ff4e62SPhani R Burra 	spin_lock(&xn->xn_lock);
1053*b4ff4e62SPhani R Burra 	if (xn->state == LIBIE_CTLQ_XN_SHUTDOWN) {
1054*b4ff4e62SPhani R Burra 		ret = -ENXIO;
1055*b4ff4e62SPhani R Burra 		goto unlock_xn;
1056*b4ff4e62SPhani R Burra 	}
1057*b4ff4e62SPhani R Burra 
1058*b4ff4e62SPhani R Burra 	xn->state = params->resp_cb ? LIBIE_CTLQ_XN_ASYNC :
1059*b4ff4e62SPhani R Burra 				      LIBIE_CTLQ_XN_WAITING;
1060*b4ff4e62SPhani R Burra 	xn->virtchnl_opcode = params->chnl_opcode;
1061*b4ff4e62SPhani R Burra 
1062*b4ff4e62SPhani R Burra 	if (params->resp_cb) {
1063*b4ff4e62SPhani R Burra 		xn->send_ctx = params->send_ctx;
1064*b4ff4e62SPhani R Burra 		xn->resp_cb = params->resp_cb;
1065*b4ff4e62SPhani R Burra 		xn->timeout_ms = params->timeout_ms;
1066*b4ff4e62SPhani R Burra 		xn->timestamp = ktime_get();
1067*b4ff4e62SPhani R Burra 	}
1068*b4ff4e62SPhani R Burra 
1069*b4ff4e62SPhani R Burra 	ret = libie_ctlq_xn_process_send(params, xn);
1070*b4ff4e62SPhani R Burra 	if (ret)
1071*b4ff4e62SPhani R Burra 		goto release_xn;
1072*b4ff4e62SPhani R Burra 	else
1073*b4ff4e62SPhani R Burra 		free_send = false;
1074*b4ff4e62SPhani R Burra 
1075*b4ff4e62SPhani R Burra 	spin_unlock(&xn->xn_lock);
1076*b4ff4e62SPhani R Burra 
1077*b4ff4e62SPhani R Burra 	if (params->resp_cb)
1078*b4ff4e62SPhani R Burra 		return 0;
1079*b4ff4e62SPhani R Burra 
1080*b4ff4e62SPhani R Burra 	wait_for_completion_timeout(&xn->cmd_completion_event,
1081*b4ff4e62SPhani R Burra 				    msecs_to_jiffies(params->timeout_ms));
1082*b4ff4e62SPhani R Burra 
1083*b4ff4e62SPhani R Burra 	spin_lock(&xn->xn_lock);
1084*b4ff4e62SPhani R Burra 	switch (xn->state) {
1085*b4ff4e62SPhani R Burra 	case LIBIE_CTLQ_XN_WAITING:
1086*b4ff4e62SPhani R Burra 		ret = -ETIMEDOUT;
1087*b4ff4e62SPhani R Burra 		break;
1088*b4ff4e62SPhani R Burra 	case LIBIE_CTLQ_XN_COMPLETED_SUCCESS:
1089*b4ff4e62SPhani R Burra 		params->recv_mem = xn->recv_mem;
1090*b4ff4e62SPhani R Burra 		break;
1091*b4ff4e62SPhani R Burra 	default:
1092*b4ff4e62SPhani R Burra 		ret = -EBADMSG;
1093*b4ff4e62SPhani R Burra 		break;
1094*b4ff4e62SPhani R Burra 	}
1095*b4ff4e62SPhani R Burra 
1096*b4ff4e62SPhani R Burra 	/* Free the receive buffer in case of failure. On timeout, receive
1097*b4ff4e62SPhani R Burra 	 * buffer is not allocated.
1098*b4ff4e62SPhani R Burra 	 */
1099*b4ff4e62SPhani R Burra 	if (ret && ret != -ETIMEDOUT)
1100*b4ff4e62SPhani R Burra 		libie_ctlq_release_rx_buf(&xn->recv_mem);
1101*b4ff4e62SPhani R Burra 
1102*b4ff4e62SPhani R Burra release_xn:
1103*b4ff4e62SPhani R Burra 	xn->state = LIBIE_CTLQ_XN_IDLE;
1104*b4ff4e62SPhani R Burra 	reinit_completion(&xn->cmd_completion_event);
1105*b4ff4e62SPhani R Burra unlock_xn:
1106*b4ff4e62SPhani R Burra 	spin_unlock(&xn->xn_lock);
1107*b4ff4e62SPhani R Burra 	libie_ctlq_xn_push_free(params->xnm, xn);
1108*b4ff4e62SPhani R Burra free_buf:
1109*b4ff4e62SPhani R Burra 	if (free_send)
1110*b4ff4e62SPhani R Burra 		params->rel_tx_buf(params->send_buf.iov_base);
1111*b4ff4e62SPhani R Burra 
1112*b4ff4e62SPhani R Burra 	return ret;
1113*b4ff4e62SPhani R Burra }
1114*b4ff4e62SPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_send, "LIBIE_CP");
1115*b4ff4e62SPhani R Burra 
1116*b4ff4e62SPhani R Burra /**
1117*b4ff4e62SPhani R Burra  * struct libie_ctlq_xn_rel_tx_ctx - context needed to release xn Tx message
1118*b4ff4e62SPhani R Burra  * @dev: device for which DMA was mapped
1119*b4ff4e62SPhani R Burra  * @rel_tx_buf: freeing function for non-small buffers
1120*b4ff4e62SPhani R Burra  */
1121*b4ff4e62SPhani R Burra struct libie_ctlq_xn_rel_tx_ctx {
1122*b4ff4e62SPhani R Burra 	struct device *dev;
1123*b4ff4e62SPhani R Burra 	void (*rel_tx_buf)(const void *buf_va);
1124*b4ff4e62SPhani R Burra };
1125*b4ff4e62SPhani R Burra 
1126*b4ff4e62SPhani R Burra /**
1127*b4ff4e62SPhani R Burra  * libie_ctlq_xn_rel_tx_buf - release xn-controlled Tx message buffer
1128*b4ff4e62SPhani R Burra  * @ctx: context, namely DMA device and freeing function
1129*b4ff4e62SPhani R Burra  * @dma_mem: DMA memory to reclaim/unmap
1130*b4ff4e62SPhani R Burra  */
libie_ctlq_xn_rel_tx_buf(const void * ctx,struct libie_cp_dma_mem * dma_mem)1131*b4ff4e62SPhani R Burra static void libie_ctlq_xn_rel_tx_buf(const void *ctx,
1132*b4ff4e62SPhani R Burra 				     struct libie_cp_dma_mem *dma_mem)
1133*b4ff4e62SPhani R Burra {
1134*b4ff4e62SPhani R Burra 	const struct libie_ctlq_xn_rel_tx_ctx *rel_ctx = ctx;
1135*b4ff4e62SPhani R Burra 
1136*b4ff4e62SPhani R Burra 	if (!libie_cp_can_send_onstack(dma_mem->size)) {
1137*b4ff4e62SPhani R Burra 		libie_cp_unmap_dma_mem(rel_ctx->dev, dma_mem);
1138*b4ff4e62SPhani R Burra 		rel_ctx->rel_tx_buf(dma_mem->va);
1139*b4ff4e62SPhani R Burra 	}
1140*b4ff4e62SPhani R Burra }
1141*b4ff4e62SPhani R Burra 
1142*b4ff4e62SPhani R Burra /**
1143*b4ff4e62SPhani R Burra  * libie_ctlq_xn_send_clean - clean xn-controlled Tx messages
1144*b4ff4e62SPhani R Burra  * @ctlq: control queue to clean
1145*b4ff4e62SPhani R Burra  * @rel_tx_buf: driver callback to free the buffer
1146*b4ff4e62SPhani R Burra  * @force: clean regardless of DD
1147*b4ff4e62SPhani R Burra  *
1148*b4ff4e62SPhani R Burra  * Return: number of completed/released messages.
1149*b4ff4e62SPhani R Burra  */
libie_ctlq_xn_send_clean(struct libie_ctlq_info * ctlq,void (* rel_tx_buf)(const void * buf_va),bool force)1150*b4ff4e62SPhani R Burra u32 libie_ctlq_xn_send_clean(struct libie_ctlq_info *ctlq,
1151*b4ff4e62SPhani R Burra 			     void (*rel_tx_buf)(const void *buf_va),
1152*b4ff4e62SPhani R Burra 			     bool force)
1153*b4ff4e62SPhani R Burra {
1154*b4ff4e62SPhani R Burra 	struct libie_ctlq_xn_rel_tx_ctx rel_ctx = {
1155*b4ff4e62SPhani R Burra 		.dev = ctlq->dev,
1156*b4ff4e62SPhani R Burra 		.rel_tx_buf = rel_tx_buf,
1157*b4ff4e62SPhani R Burra 	};
1158*b4ff4e62SPhani R Burra 	struct libie_ctlq_clean_params params = {
1159*b4ff4e62SPhani R Burra 		.ctlq = ctlq,
1160*b4ff4e62SPhani R Burra 		.force = force,
1161*b4ff4e62SPhani R Burra 		.num_msgs = ctlq->ring_len,
1162*b4ff4e62SPhani R Burra 		.rel_ctx = &rel_ctx,
1163*b4ff4e62SPhani R Burra 		.rel_dma_mem = libie_ctlq_xn_rel_tx_buf,
1164*b4ff4e62SPhani R Burra 	};
1165*b4ff4e62SPhani R Burra 
1166*b4ff4e62SPhani R Burra 	return libie_ctlq_send_clean(&params);
1167*b4ff4e62SPhani R Burra }
1168*b4ff4e62SPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_send_clean, "LIBIE_CP");
1169*b4ff4e62SPhani R Burra 
1170*b4ff4e62SPhani R Burra /**
1171*b4ff4e62SPhani R Burra  * libie_ctlq_xn_shutdown - terminate control queue transactions
1172*b4ff4e62SPhani R Burra  * @xnm: pointer to the transaction manager
1173*b4ff4e62SPhani R Burra  *
1174*b4ff4e62SPhani R Burra  * Synchronously terminate existing transactions and stop accepting new ones.
1175*b4ff4e62SPhani R Burra  * Async transactions are discarded without invoking resp_cb.
1176*b4ff4e62SPhani R Burra  */
libie_ctlq_xn_shutdown(struct libie_ctlq_xn_manager * xnm)1177*b4ff4e62SPhani R Burra void libie_ctlq_xn_shutdown(struct libie_ctlq_xn_manager *xnm)
1178*b4ff4e62SPhani R Burra {
1179*b4ff4e62SPhani R Burra 	bool must_wait = false;
1180*b4ff4e62SPhani R Burra 	u32 i;
1181*b4ff4e62SPhani R Burra 
1182*b4ff4e62SPhani R Burra 	/* Should be no new clear bits after this */
1183*b4ff4e62SPhani R Burra 	spin_lock(&xnm->free_xns_bm_lock);
1184*b4ff4e62SPhani R Burra 	xnm->shutdown = true;
1185*b4ff4e62SPhani R Burra 
1186*b4ff4e62SPhani R Burra 	for_each_clear_bit(i, xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES) {
1187*b4ff4e62SPhani R Burra 		struct libie_ctlq_xn *xn = &xnm->ring[i];
1188*b4ff4e62SPhani R Burra 
1189*b4ff4e62SPhani R Burra 		spin_lock(&xn->xn_lock);
1190*b4ff4e62SPhani R Burra 
1191*b4ff4e62SPhani R Burra 		switch (xn->state) {
1192*b4ff4e62SPhani R Burra 		/* if an idle xn is not free, it is about to be either
1193*b4ff4e62SPhani R Burra 		 * freed or initialized, prevent the latter and wait
1194*b4ff4e62SPhani R Burra 		 */
1195*b4ff4e62SPhani R Burra 		case LIBIE_CTLQ_XN_IDLE:
1196*b4ff4e62SPhani R Burra 			xn->state = LIBIE_CTLQ_XN_SHUTDOWN;
1197*b4ff4e62SPhani R Burra 			fallthrough;
1198*b4ff4e62SPhani R Burra 		/* waiting thread possibly needs a push to return the xn,
1199*b4ff4e62SPhani R Burra 		 * transaction will be reported as timed out
1200*b4ff4e62SPhani R Burra 		 */
1201*b4ff4e62SPhani R Burra 		case LIBIE_CTLQ_XN_WAITING:
1202*b4ff4e62SPhani R Burra 			complete(&xn->cmd_completion_event);
1203*b4ff4e62SPhani R Burra 			fallthrough;
1204*b4ff4e62SPhani R Burra 		/* these states will return the xn soon */
1205*b4ff4e62SPhani R Burra 		case LIBIE_CTLQ_XN_COMPLETED_SUCCESS:
1206*b4ff4e62SPhani R Burra 		case LIBIE_CTLQ_XN_COMPLETED_FAILED:
1207*b4ff4e62SPhani R Burra 		case LIBIE_CTLQ_XN_SHUTDOWN:
1208*b4ff4e62SPhani R Burra 			must_wait = true;
1209*b4ff4e62SPhani R Burra 			break;
1210*b4ff4e62SPhani R Burra 		/* no thread should reference async xns at this point */
1211*b4ff4e62SPhani R Burra 		case LIBIE_CTLQ_XN_ASYNC:
1212*b4ff4e62SPhani R Burra 			xn->state = LIBIE_CTLQ_XN_IDLE;
1213*b4ff4e62SPhani R Burra 			__libie_ctlq_xn_push_free(xnm, xn);
1214*b4ff4e62SPhani R Burra 			break;
1215*b4ff4e62SPhani R Burra 		}
1216*b4ff4e62SPhani R Burra 
1217*b4ff4e62SPhani R Burra 		spin_unlock(&xn->xn_lock);
1218*b4ff4e62SPhani R Burra 	}
1219*b4ff4e62SPhani R Burra 
1220*b4ff4e62SPhani R Burra 	spin_unlock(&xnm->free_xns_bm_lock);
1221*b4ff4e62SPhani R Burra 
1222*b4ff4e62SPhani R Burra 	if (must_wait)
1223*b4ff4e62SPhani R Burra 		wait_for_completion(&xnm->can_destroy);
1224*b4ff4e62SPhani R Burra }
1225*b4ff4e62SPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_shutdown, "LIBIE_CP");
1226*b4ff4e62SPhani R Burra 
1227*b4ff4e62SPhani R Burra /**
1228*b4ff4e62SPhani R Burra  * libie_ctlq_xn_deinit - deallocate and free the transaction manager resources
1229*b4ff4e62SPhani R Burra  * @xnm: pointer to the transaction manager
1230*b4ff4e62SPhani R Burra  * @ctx: libie CP context information
1231*b4ff4e62SPhani R Burra  *
1232*b4ff4e62SPhani R Burra  * Rx processing must be stopped beforehand via cancelling tasks.
1233*b4ff4e62SPhani R Burra  * Tx processing must be stopped beforehand via libie_ctlq_xn_shutdown(),
1234*b4ff4e62SPhani R Burra  * all buffers must be force-cleaned from the send queue.
1235*b4ff4e62SPhani R Burra  */
libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager * xnm,struct libie_ctlq_ctx * ctx)1236*b4ff4e62SPhani R Burra void libie_ctlq_xn_deinit(struct libie_ctlq_xn_manager *xnm,
1237*b4ff4e62SPhani R Burra 			  struct libie_ctlq_ctx *ctx)
1238*b4ff4e62SPhani R Burra {
1239*b4ff4e62SPhani R Burra 	libie_ctlq_xn_deinit_dma(xnm, LIBIE_CTLQ_MAX_XN_ENTRIES);
1240*b4ff4e62SPhani R Burra 	kvfree(xnm);
1241*b4ff4e62SPhani R Burra 	libie_ctlq_deinit(ctx);
1242*b4ff4e62SPhani R Burra }
1243*b4ff4e62SPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_deinit, "LIBIE_CP");
1244*b4ff4e62SPhani R Burra 
1245*b4ff4e62SPhani R Burra /**
1246*b4ff4e62SPhani R Burra  * libie_ctlq_xn_init - initialize the Xn transaction manager
1247*b4ff4e62SPhani R Burra  * @params: Xn init param information for allocating Xn manager resources
1248*b4ff4e62SPhani R Burra  *
1249*b4ff4e62SPhani R Burra  * Return: %0 on success, -%errno on failure.
1250*b4ff4e62SPhani R Burra  */
libie_ctlq_xn_init(struct libie_ctlq_xn_init_params * params)1251*b4ff4e62SPhani R Burra int libie_ctlq_xn_init(struct libie_ctlq_xn_init_params *params)
1252*b4ff4e62SPhani R Burra {
1253*b4ff4e62SPhani R Burra 	struct libie_ctlq_xn_manager *xnm;
1254*b4ff4e62SPhani R Burra 	int ret;
1255*b4ff4e62SPhani R Burra 
1256*b4ff4e62SPhani R Burra 	ret = libie_ctlq_init(params->ctx, params->cctlq_info, params->num_qs);
1257*b4ff4e62SPhani R Burra 	if (ret)
1258*b4ff4e62SPhani R Burra 		return ret;
1259*b4ff4e62SPhani R Burra 
1260*b4ff4e62SPhani R Burra 	xnm = kvzalloc_obj(*xnm);
1261*b4ff4e62SPhani R Burra 	if (!xnm)
1262*b4ff4e62SPhani R Burra 		goto ctlq_deinit;
1263*b4ff4e62SPhani R Burra 
1264*b4ff4e62SPhani R Burra 	ret = libie_ctlq_xn_init_dma(&params->ctx->mmio_info.pdev->dev, xnm);
1265*b4ff4e62SPhani R Burra 	if (ret)
1266*b4ff4e62SPhani R Burra 		goto free_xnm;
1267*b4ff4e62SPhani R Burra 
1268*b4ff4e62SPhani R Burra 	spin_lock_init(&xnm->free_xns_bm_lock);
1269*b4ff4e62SPhani R Burra 	init_completion(&xnm->can_destroy);
1270*b4ff4e62SPhani R Burra 	bitmap_fill(xnm->free_xns_bm, LIBIE_CTLQ_MAX_XN_ENTRIES);
1271*b4ff4e62SPhani R Burra 
1272*b4ff4e62SPhani R Burra 	for (u32 i = 0; i < LIBIE_CTLQ_MAX_XN_ENTRIES; i++) {
1273*b4ff4e62SPhani R Burra 		struct libie_ctlq_xn *xn = &xnm->ring[i];
1274*b4ff4e62SPhani R Burra 
1275*b4ff4e62SPhani R Burra 		xn->index = i;
1276*b4ff4e62SPhani R Burra 		init_completion(&xn->cmd_completion_event);
1277*b4ff4e62SPhani R Burra 		spin_lock_init(&xn->xn_lock);
1278*b4ff4e62SPhani R Burra 	}
1279*b4ff4e62SPhani R Burra 	xnm->ctx = params->ctx;
1280*b4ff4e62SPhani R Burra 	params->xnm = xnm;
1281*b4ff4e62SPhani R Burra 
1282*b4ff4e62SPhani R Burra 	return 0;
1283*b4ff4e62SPhani R Burra 
1284*b4ff4e62SPhani R Burra free_xnm:
1285*b4ff4e62SPhani R Burra 	kvfree(xnm);
1286*b4ff4e62SPhani R Burra ctlq_deinit:
1287*b4ff4e62SPhani R Burra 	libie_ctlq_deinit(params->ctx);
1288*b4ff4e62SPhani R Burra 
1289*b4ff4e62SPhani R Burra 	return -ENOMEM;
1290*b4ff4e62SPhani R Burra }
1291*b4ff4e62SPhani R Burra EXPORT_SYMBOL_NS_GPL(libie_ctlq_xn_init, "LIBIE_CP");
1292*b4ff4e62SPhani R Burra 
1293caed480fSPhani R Burra MODULE_DESCRIPTION("Control Plane communication API");
1294caed480fSPhani R Burra MODULE_IMPORT_NS("LIBETH");
1295caed480fSPhani R Burra MODULE_LICENSE("GPL");
1296