xref: /linux/drivers/net/ethernet/alibaba/eea/eea_ring.c (revision 039ce329dfe6fb74f6394dcb59607425af8d0601)
1*039ce329SXuan Zhuo // SPDX-License-Identifier: GPL-2.0-or-later
2*039ce329SXuan Zhuo /*
3*039ce329SXuan Zhuo  * Driver for Alibaba Elastic Ethernet Adapter.
4*039ce329SXuan Zhuo  *
5*039ce329SXuan Zhuo  * Copyright (C) 2025 Alibaba Inc.
6*039ce329SXuan Zhuo  */
7*039ce329SXuan Zhuo 
8*039ce329SXuan Zhuo #include "eea_pci.h"
9*039ce329SXuan Zhuo #include "eea_ring.h"
10*039ce329SXuan Zhuo 
11*039ce329SXuan Zhuo void eea_ering_irq_active(struct eea_ring *ering, struct eea_ring *tx_ering)
12*039ce329SXuan Zhuo {
13*039ce329SXuan Zhuo 	u64 value = 0, rx_idx, tx_idx;
14*039ce329SXuan Zhuo 
15*039ce329SXuan Zhuo 	tx_idx = (u64)tx_ering->cq.hw_idx;
16*039ce329SXuan Zhuo 	rx_idx = (u64)ering->cq.hw_idx;
17*039ce329SXuan Zhuo 
18*039ce329SXuan Zhuo 	value |= EEA_IRQ_UNMASK << EEA_DB_FLAGS_OFF;
19*039ce329SXuan Zhuo 	value |= tx_idx << EEA_DB_TX_CQ_HEAD_OFF;
20*039ce329SXuan Zhuo 	value |= rx_idx << EEA_DB_RX_CQ_HEAD_OFF;
21*039ce329SXuan Zhuo 
22*039ce329SXuan Zhuo 	writeq(value, ering->db);
23*039ce329SXuan Zhuo }
24*039ce329SXuan Zhuo 
25*039ce329SXuan Zhuo void *eea_ering_cq_get_desc(const struct eea_ring *ering)
26*039ce329SXuan Zhuo {
27*039ce329SXuan Zhuo 	u8 phase;
28*039ce329SXuan Zhuo 	u8 *desc;
29*039ce329SXuan Zhuo 
30*039ce329SXuan Zhuo 	desc = ering->cq.desc + (ering->cq.head << ering->cq.desc_size_shift);
31*039ce329SXuan Zhuo 
32*039ce329SXuan Zhuo 	phase = READ_ONCE(*(u8 *)(desc + ering->cq.desc_size - 1));
33*039ce329SXuan Zhuo 
34*039ce329SXuan Zhuo 	if ((phase & EEA_RING_DESC_F_CQ_PHASE) == ering->cq.phase) {
35*039ce329SXuan Zhuo 		dma_rmb();
36*039ce329SXuan Zhuo 		return desc;
37*039ce329SXuan Zhuo 	}
38*039ce329SXuan Zhuo 
39*039ce329SXuan Zhuo 	return NULL;
40*039ce329SXuan Zhuo }
41*039ce329SXuan Zhuo 
42*039ce329SXuan Zhuo /* sq api */
43*039ce329SXuan Zhuo void *eea_ering_sq_alloc_desc(struct eea_ring *ering, u16 id, bool is_last,
44*039ce329SXuan Zhuo 			      u16 flags)
45*039ce329SXuan Zhuo {
46*039ce329SXuan Zhuo 	struct eea_ring_sq *sq = &ering->sq;
47*039ce329SXuan Zhuo 	struct eea_common_desc *desc;
48*039ce329SXuan Zhuo 
49*039ce329SXuan Zhuo 	if (!sq->shadow_num) {
50*039ce329SXuan Zhuo 		sq->shadow_idx = sq->head;
51*039ce329SXuan Zhuo 		sq->shadow_id = cpu_to_le16(id);
52*039ce329SXuan Zhuo 	}
53*039ce329SXuan Zhuo 
54*039ce329SXuan Zhuo 	if (!is_last)
55*039ce329SXuan Zhuo 		flags |= EEA_RING_DESC_F_MORE;
56*039ce329SXuan Zhuo 
57*039ce329SXuan Zhuo 	desc = sq->desc + (sq->shadow_idx << sq->desc_size_shift);
58*039ce329SXuan Zhuo 
59*039ce329SXuan Zhuo 	desc->flags = cpu_to_le16(flags);
60*039ce329SXuan Zhuo 	desc->id = sq->shadow_id;
61*039ce329SXuan Zhuo 
62*039ce329SXuan Zhuo 	if (unlikely(++sq->shadow_idx >= ering->num))
63*039ce329SXuan Zhuo 		sq->shadow_idx = 0;
64*039ce329SXuan Zhuo 
65*039ce329SXuan Zhuo 	++sq->shadow_num;
66*039ce329SXuan Zhuo 
67*039ce329SXuan Zhuo 	return desc;
68*039ce329SXuan Zhuo }
69*039ce329SXuan Zhuo 
70*039ce329SXuan Zhuo /* This is an allocation API for admin Q. For each call to admin Q, only one
71*039ce329SXuan Zhuo  * desc will be allocated.
72*039ce329SXuan Zhuo  */
73*039ce329SXuan Zhuo void *eea_ering_aq_alloc_desc(struct eea_ring *ering)
74*039ce329SXuan Zhuo {
75*039ce329SXuan Zhuo 	struct eea_ring_sq *sq = &ering->sq;
76*039ce329SXuan Zhuo 	struct eea_common_desc *desc;
77*039ce329SXuan Zhuo 
78*039ce329SXuan Zhuo 	if (!sq->shadow_num)
79*039ce329SXuan Zhuo 		sq->shadow_idx = sq->head;
80*039ce329SXuan Zhuo 
81*039ce329SXuan Zhuo 	desc = sq->desc + (sq->shadow_idx << sq->desc_size_shift);
82*039ce329SXuan Zhuo 
83*039ce329SXuan Zhuo 	if (unlikely(++sq->shadow_idx >= ering->num))
84*039ce329SXuan Zhuo 		sq->shadow_idx = 0;
85*039ce329SXuan Zhuo 
86*039ce329SXuan Zhuo 	++sq->shadow_num;
87*039ce329SXuan Zhuo 
88*039ce329SXuan Zhuo 	return desc;
89*039ce329SXuan Zhuo }
90*039ce329SXuan Zhuo 
91*039ce329SXuan Zhuo void eea_ering_sq_commit_desc(struct eea_ring *ering)
92*039ce329SXuan Zhuo {
93*039ce329SXuan Zhuo 	struct eea_ring_sq *sq = &ering->sq;
94*039ce329SXuan Zhuo 	int num;
95*039ce329SXuan Zhuo 
96*039ce329SXuan Zhuo 	num = sq->shadow_num;
97*039ce329SXuan Zhuo 
98*039ce329SXuan Zhuo 	ering->num_free -= num;
99*039ce329SXuan Zhuo 
100*039ce329SXuan Zhuo 	sq->head       = sq->shadow_idx;
101*039ce329SXuan Zhuo 	sq->hw_idx     += num;
102*039ce329SXuan Zhuo 	sq->shadow_num = 0;
103*039ce329SXuan Zhuo }
104*039ce329SXuan Zhuo 
105*039ce329SXuan Zhuo void eea_ering_sq_cancel(struct eea_ring *ering)
106*039ce329SXuan Zhuo {
107*039ce329SXuan Zhuo 	ering->sq.shadow_num = 0;
108*039ce329SXuan Zhuo }
109*039ce329SXuan Zhuo 
110*039ce329SXuan Zhuo /* cq api */
111*039ce329SXuan Zhuo void eea_ering_cq_ack_desc(struct eea_ring *ering, u32 num)
112*039ce329SXuan Zhuo {
113*039ce329SXuan Zhuo 	struct eea_ring_cq *cq = &ering->cq;
114*039ce329SXuan Zhuo 
115*039ce329SXuan Zhuo 	cq->head += num;
116*039ce329SXuan Zhuo 	cq->hw_idx += num;
117*039ce329SXuan Zhuo 
118*039ce329SXuan Zhuo 	if (unlikely(cq->head >= ering->num)) {
119*039ce329SXuan Zhuo 		cq->head -= ering->num;
120*039ce329SXuan Zhuo 		cq->phase ^= EEA_RING_DESC_F_CQ_PHASE;
121*039ce329SXuan Zhuo 	}
122*039ce329SXuan Zhuo 
123*039ce329SXuan Zhuo 	ering->num_free += num;
124*039ce329SXuan Zhuo }
125*039ce329SXuan Zhuo 
126*039ce329SXuan Zhuo /* notify */
127*039ce329SXuan Zhuo void eea_ering_kick(struct eea_ring *ering)
128*039ce329SXuan Zhuo {
129*039ce329SXuan Zhuo 	u64 value = 0, idx;
130*039ce329SXuan Zhuo 
131*039ce329SXuan Zhuo 	idx = (u64)ering->sq.hw_idx;
132*039ce329SXuan Zhuo 
133*039ce329SXuan Zhuo 	value |= EEA_IDX_PRESENT << EEA_DB_FLAGS_OFF;
134*039ce329SXuan Zhuo 	value |= idx << EEA_DB_IDX_OFF;
135*039ce329SXuan Zhuo 
136*039ce329SXuan Zhuo 	writeq(value, ering->db);
137*039ce329SXuan Zhuo }
138*039ce329SXuan Zhuo 
139*039ce329SXuan Zhuo /* ering alloc/free */
140*039ce329SXuan Zhuo static void ering_free_queue(struct eea_device *edev, size_t size,
141*039ce329SXuan Zhuo 			     void *queue, dma_addr_t dma_handle)
142*039ce329SXuan Zhuo {
143*039ce329SXuan Zhuo 	dma_free_coherent(edev->dma_dev, size, queue, dma_handle);
144*039ce329SXuan Zhuo }
145*039ce329SXuan Zhuo 
146*039ce329SXuan Zhuo static void *ering_alloc_queue(struct eea_device *edev, size_t size,
147*039ce329SXuan Zhuo 			       dma_addr_t *dma_handle)
148*039ce329SXuan Zhuo {
149*039ce329SXuan Zhuo 	gfp_t flags = GFP_KERNEL | __GFP_NOWARN;
150*039ce329SXuan Zhuo 
151*039ce329SXuan Zhuo 	return dma_alloc_coherent(edev->dma_dev, size, dma_handle, flags);
152*039ce329SXuan Zhuo }
153*039ce329SXuan Zhuo 
154*039ce329SXuan Zhuo static int ering_alloc_queues(struct eea_ring *ering, struct eea_device *edev,
155*039ce329SXuan Zhuo 			      size_t num, u8 sq_desc_size, u8 cq_desc_size)
156*039ce329SXuan Zhuo {
157*039ce329SXuan Zhuo 	dma_addr_t addr;
158*039ce329SXuan Zhuo 	size_t size;
159*039ce329SXuan Zhuo 	void *ring;
160*039ce329SXuan Zhuo 
161*039ce329SXuan Zhuo 	size = num * sq_desc_size;
162*039ce329SXuan Zhuo 
163*039ce329SXuan Zhuo 	ring = ering_alloc_queue(edev, size, &addr);
164*039ce329SXuan Zhuo 	if (!ring)
165*039ce329SXuan Zhuo 		return -ENOMEM;
166*039ce329SXuan Zhuo 
167*039ce329SXuan Zhuo 	ering->sq.desc     = ring;
168*039ce329SXuan Zhuo 	ering->sq.dma_addr = addr;
169*039ce329SXuan Zhuo 	ering->sq.dma_size = size;
170*039ce329SXuan Zhuo 	ering->sq.desc_size = sq_desc_size;
171*039ce329SXuan Zhuo 	ering->sq.desc_size_shift = fls(sq_desc_size) - 1;
172*039ce329SXuan Zhuo 
173*039ce329SXuan Zhuo 	size = num * cq_desc_size;
174*039ce329SXuan Zhuo 
175*039ce329SXuan Zhuo 	ring = ering_alloc_queue(edev, size, &addr);
176*039ce329SXuan Zhuo 	if (!ring)
177*039ce329SXuan Zhuo 		goto err_free_sq;
178*039ce329SXuan Zhuo 
179*039ce329SXuan Zhuo 	ering->cq.desc     = ring;
180*039ce329SXuan Zhuo 	ering->cq.dma_addr = addr;
181*039ce329SXuan Zhuo 	ering->cq.dma_size = size;
182*039ce329SXuan Zhuo 	ering->cq.desc_size = cq_desc_size;
183*039ce329SXuan Zhuo 	ering->cq.desc_size_shift = fls(cq_desc_size) - 1;
184*039ce329SXuan Zhuo 
185*039ce329SXuan Zhuo 	ering->num = num;
186*039ce329SXuan Zhuo 
187*039ce329SXuan Zhuo 	return 0;
188*039ce329SXuan Zhuo 
189*039ce329SXuan Zhuo err_free_sq:
190*039ce329SXuan Zhuo 	ering_free_queue(ering->edev, ering->sq.dma_size,
191*039ce329SXuan Zhuo 			 ering->sq.desc, ering->sq.dma_addr);
192*039ce329SXuan Zhuo 	return -ENOMEM;
193*039ce329SXuan Zhuo }
194*039ce329SXuan Zhuo 
195*039ce329SXuan Zhuo static void ering_init(struct eea_ring *ering)
196*039ce329SXuan Zhuo {
197*039ce329SXuan Zhuo 	ering->cq.phase = EEA_RING_DESC_F_CQ_PHASE;
198*039ce329SXuan Zhuo 	ering->num_free = ering->num;
199*039ce329SXuan Zhuo }
200*039ce329SXuan Zhuo 
201*039ce329SXuan Zhuo struct eea_ring *eea_ering_alloc(u32 index, u32 num, struct eea_device *edev,
202*039ce329SXuan Zhuo 				 u8 sq_desc_size, u8 cq_desc_size,
203*039ce329SXuan Zhuo 				 const char *name)
204*039ce329SXuan Zhuo {
205*039ce329SXuan Zhuo 	struct eea_ring *ering;
206*039ce329SXuan Zhuo 
207*039ce329SXuan Zhuo 	if (num > EEA_NET_IO_HW_RING_DEPTH_MAX ||
208*039ce329SXuan Zhuo 	    num < EEA_NET_IO_RING_DEPTH_MIN)
209*039ce329SXuan Zhuo 		return NULL;
210*039ce329SXuan Zhuo 
211*039ce329SXuan Zhuo 	if (!is_power_of_2(num))
212*039ce329SXuan Zhuo 		return NULL;
213*039ce329SXuan Zhuo 
214*039ce329SXuan Zhuo 	if (!sq_desc_size || !is_power_of_2(sq_desc_size))
215*039ce329SXuan Zhuo 		return NULL;
216*039ce329SXuan Zhuo 
217*039ce329SXuan Zhuo 	if (!cq_desc_size || !is_power_of_2(cq_desc_size))
218*039ce329SXuan Zhuo 		return NULL;
219*039ce329SXuan Zhuo 
220*039ce329SXuan Zhuo 	ering = kzalloc(sizeof(*ering), GFP_KERNEL);
221*039ce329SXuan Zhuo 	if (!ering)
222*039ce329SXuan Zhuo 		return NULL;
223*039ce329SXuan Zhuo 
224*039ce329SXuan Zhuo 	ering->edev = edev;
225*039ce329SXuan Zhuo 	ering->name = name;
226*039ce329SXuan Zhuo 	ering->index = index;
227*039ce329SXuan Zhuo 
228*039ce329SXuan Zhuo 	if (ering_alloc_queues(ering, edev, num, sq_desc_size, cq_desc_size))
229*039ce329SXuan Zhuo 		goto err_free;
230*039ce329SXuan Zhuo 
231*039ce329SXuan Zhuo 	ering_init(ering);
232*039ce329SXuan Zhuo 
233*039ce329SXuan Zhuo 	return ering;
234*039ce329SXuan Zhuo 
235*039ce329SXuan Zhuo err_free:
236*039ce329SXuan Zhuo 	kfree(ering);
237*039ce329SXuan Zhuo 	return NULL;
238*039ce329SXuan Zhuo }
239*039ce329SXuan Zhuo 
240*039ce329SXuan Zhuo void eea_ering_free(struct eea_ring *ering)
241*039ce329SXuan Zhuo {
242*039ce329SXuan Zhuo 	ering_free_queue(ering->edev, ering->cq.dma_size,
243*039ce329SXuan Zhuo 			 ering->cq.desc, ering->cq.dma_addr);
244*039ce329SXuan Zhuo 
245*039ce329SXuan Zhuo 	ering_free_queue(ering->edev, ering->sq.dma_size,
246*039ce329SXuan Zhuo 			 ering->sq.desc, ering->sq.dma_addr);
247*039ce329SXuan Zhuo 
248*039ce329SXuan Zhuo 	kfree(ering);
249*039ce329SXuan Zhuo }
250