1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2012 Intel Corporation. All rights reserved.
3*4882a593Smuzhiyun * Copyright (c) 2007 - 2012 QLogic Corporation. All rights reserved.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * This software is available to you under a choice of one of two
6*4882a593Smuzhiyun * licenses. You may choose to be licensed under the terms of the GNU
7*4882a593Smuzhiyun * General Public License (GPL) Version 2, available from the file
8*4882a593Smuzhiyun * COPYING in the main directory of this source tree, or the
9*4882a593Smuzhiyun * OpenIB.org BSD license below:
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Redistribution and use in source and binary forms, with or
12*4882a593Smuzhiyun * without modification, are permitted provided that the following
13*4882a593Smuzhiyun * conditions are met:
14*4882a593Smuzhiyun *
15*4882a593Smuzhiyun * - Redistributions of source code must retain the above
16*4882a593Smuzhiyun * copyright notice, this list of conditions and the following
17*4882a593Smuzhiyun * disclaimer.
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * - Redistributions in binary form must reproduce the above
20*4882a593Smuzhiyun * copyright notice, this list of conditions and the following
21*4882a593Smuzhiyun * disclaimer in the documentation and/or other materials
22*4882a593Smuzhiyun * provided with the distribution.
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25*4882a593Smuzhiyun * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26*4882a593Smuzhiyun * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27*4882a593Smuzhiyun * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28*4882a593Smuzhiyun * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29*4882a593Smuzhiyun * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30*4882a593Smuzhiyun * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31*4882a593Smuzhiyun * SOFTWARE.
32*4882a593Smuzhiyun */
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #include <linux/spinlock.h>
35*4882a593Smuzhiyun #include <linux/netdevice.h>
36*4882a593Smuzhiyun #include <linux/moduleparam.h>
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun #include "qib.h"
39*4882a593Smuzhiyun #include "qib_common.h"
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun /* default pio off, sdma on */
42*4882a593Smuzhiyun static ushort sdma_descq_cnt = 256;
43*4882a593Smuzhiyun module_param_named(sdma_descq_cnt, sdma_descq_cnt, ushort, S_IRUGO);
44*4882a593Smuzhiyun MODULE_PARM_DESC(sdma_descq_cnt, "Number of SDMA descq entries");
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /*
47*4882a593Smuzhiyun * Bits defined in the send DMA descriptor.
48*4882a593Smuzhiyun */
49*4882a593Smuzhiyun #define SDMA_DESC_LAST (1ULL << 11)
50*4882a593Smuzhiyun #define SDMA_DESC_FIRST (1ULL << 12)
51*4882a593Smuzhiyun #define SDMA_DESC_DMA_HEAD (1ULL << 13)
52*4882a593Smuzhiyun #define SDMA_DESC_USE_LARGE_BUF (1ULL << 14)
53*4882a593Smuzhiyun #define SDMA_DESC_INTR (1ULL << 15)
54*4882a593Smuzhiyun #define SDMA_DESC_COUNT_LSB 16
55*4882a593Smuzhiyun #define SDMA_DESC_GEN_LSB 30
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun /* declare all statics here rather than keep sorting */
58*4882a593Smuzhiyun static int alloc_sdma(struct qib_pportdata *);
59*4882a593Smuzhiyun static void sdma_complete(struct kref *);
60*4882a593Smuzhiyun static void sdma_finalput(struct qib_sdma_state *);
61*4882a593Smuzhiyun static void sdma_get(struct qib_sdma_state *);
62*4882a593Smuzhiyun static void sdma_put(struct qib_sdma_state *);
63*4882a593Smuzhiyun static void sdma_set_state(struct qib_pportdata *, enum qib_sdma_states);
64*4882a593Smuzhiyun static void sdma_start_sw_clean_up(struct qib_pportdata *);
65*4882a593Smuzhiyun static void sdma_sw_clean_up_task(struct tasklet_struct *);
66*4882a593Smuzhiyun static void unmap_desc(struct qib_pportdata *, unsigned);
67*4882a593Smuzhiyun
sdma_get(struct qib_sdma_state * ss)68*4882a593Smuzhiyun static void sdma_get(struct qib_sdma_state *ss)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun kref_get(&ss->kref);
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
sdma_complete(struct kref * kref)73*4882a593Smuzhiyun static void sdma_complete(struct kref *kref)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun struct qib_sdma_state *ss =
76*4882a593Smuzhiyun container_of(kref, struct qib_sdma_state, kref);
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun complete(&ss->comp);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
sdma_put(struct qib_sdma_state * ss)81*4882a593Smuzhiyun static void sdma_put(struct qib_sdma_state *ss)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun kref_put(&ss->kref, sdma_complete);
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
sdma_finalput(struct qib_sdma_state * ss)86*4882a593Smuzhiyun static void sdma_finalput(struct qib_sdma_state *ss)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun sdma_put(ss);
89*4882a593Smuzhiyun wait_for_completion(&ss->comp);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun /*
93*4882a593Smuzhiyun * Complete all the sdma requests on the active list, in the correct
94*4882a593Smuzhiyun * order, and with appropriate processing. Called when cleaning up
95*4882a593Smuzhiyun * after sdma shutdown, and when new sdma requests are submitted for
96*4882a593Smuzhiyun * a link that is down. This matches what is done for requests
97*4882a593Smuzhiyun * that complete normally, it's just the full list.
98*4882a593Smuzhiyun *
99*4882a593Smuzhiyun * Must be called with sdma_lock held
100*4882a593Smuzhiyun */
clear_sdma_activelist(struct qib_pportdata * ppd)101*4882a593Smuzhiyun static void clear_sdma_activelist(struct qib_pportdata *ppd)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun struct qib_sdma_txreq *txp, *txp_next;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun list_for_each_entry_safe(txp, txp_next, &ppd->sdma_activelist, list) {
106*4882a593Smuzhiyun list_del_init(&txp->list);
107*4882a593Smuzhiyun if (txp->flags & QIB_SDMA_TXREQ_F_FREEDESC) {
108*4882a593Smuzhiyun unsigned idx;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun idx = txp->start_idx;
111*4882a593Smuzhiyun while (idx != txp->next_descq_idx) {
112*4882a593Smuzhiyun unmap_desc(ppd, idx);
113*4882a593Smuzhiyun if (++idx == ppd->sdma_descq_cnt)
114*4882a593Smuzhiyun idx = 0;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun if (txp->callback)
118*4882a593Smuzhiyun (*txp->callback)(txp, QIB_SDMA_TXREQ_S_ABORTED);
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
sdma_sw_clean_up_task(struct tasklet_struct * t)122*4882a593Smuzhiyun static void sdma_sw_clean_up_task(struct tasklet_struct *t)
123*4882a593Smuzhiyun {
124*4882a593Smuzhiyun struct qib_pportdata *ppd = from_tasklet(ppd, t,
125*4882a593Smuzhiyun sdma_sw_clean_up_task);
126*4882a593Smuzhiyun unsigned long flags;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun spin_lock_irqsave(&ppd->sdma_lock, flags);
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /*
131*4882a593Smuzhiyun * At this point, the following should always be true:
132*4882a593Smuzhiyun * - We are halted, so no more descriptors are getting retired.
133*4882a593Smuzhiyun * - We are not running, so no one is submitting new work.
134*4882a593Smuzhiyun * - Only we can send the e40_sw_cleaned, so we can't start
135*4882a593Smuzhiyun * running again until we say so. So, the active list and
136*4882a593Smuzhiyun * descq are ours to play with.
137*4882a593Smuzhiyun */
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun /* Process all retired requests. */
140*4882a593Smuzhiyun qib_sdma_make_progress(ppd);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun clear_sdma_activelist(ppd);
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /*
145*4882a593Smuzhiyun * Resync count of added and removed. It is VERY important that
146*4882a593Smuzhiyun * sdma_descq_removed NEVER decrement - user_sdma depends on it.
147*4882a593Smuzhiyun */
148*4882a593Smuzhiyun ppd->sdma_descq_removed = ppd->sdma_descq_added;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /*
151*4882a593Smuzhiyun * Reset our notion of head and tail.
152*4882a593Smuzhiyun * Note that the HW registers will be reset when switching states
153*4882a593Smuzhiyun * due to calling __qib_sdma_process_event() below.
154*4882a593Smuzhiyun */
155*4882a593Smuzhiyun ppd->sdma_descq_tail = 0;
156*4882a593Smuzhiyun ppd->sdma_descq_head = 0;
157*4882a593Smuzhiyun ppd->sdma_head_dma[0] = 0;
158*4882a593Smuzhiyun ppd->sdma_generation = 0;
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun __qib_sdma_process_event(ppd, qib_sdma_event_e40_sw_cleaned);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun spin_unlock_irqrestore(&ppd->sdma_lock, flags);
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun /*
166*4882a593Smuzhiyun * This is called when changing to state qib_sdma_state_s10_hw_start_up_wait
167*4882a593Smuzhiyun * as a result of send buffer errors or send DMA descriptor errors.
168*4882a593Smuzhiyun * We want to disarm the buffers in these cases.
169*4882a593Smuzhiyun */
sdma_hw_start_up(struct qib_pportdata * ppd)170*4882a593Smuzhiyun static void sdma_hw_start_up(struct qib_pportdata *ppd)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun struct qib_sdma_state *ss = &ppd->sdma_state;
173*4882a593Smuzhiyun unsigned bufno;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun for (bufno = ss->first_sendbuf; bufno < ss->last_sendbuf; ++bufno)
176*4882a593Smuzhiyun ppd->dd->f_sendctrl(ppd, QIB_SENDCTRL_DISARM_BUF(bufno));
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun ppd->dd->f_sdma_hw_start_up(ppd);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
sdma_sw_tear_down(struct qib_pportdata * ppd)181*4882a593Smuzhiyun static void sdma_sw_tear_down(struct qib_pportdata *ppd)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun struct qib_sdma_state *ss = &ppd->sdma_state;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun /* Releasing this reference means the state machine has stopped. */
186*4882a593Smuzhiyun sdma_put(ss);
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
sdma_start_sw_clean_up(struct qib_pportdata * ppd)189*4882a593Smuzhiyun static void sdma_start_sw_clean_up(struct qib_pportdata *ppd)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun tasklet_hi_schedule(&ppd->sdma_sw_clean_up_task);
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
sdma_set_state(struct qib_pportdata * ppd,enum qib_sdma_states next_state)194*4882a593Smuzhiyun static void sdma_set_state(struct qib_pportdata *ppd,
195*4882a593Smuzhiyun enum qib_sdma_states next_state)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun struct qib_sdma_state *ss = &ppd->sdma_state;
198*4882a593Smuzhiyun struct sdma_set_state_action *action = ss->set_state_action;
199*4882a593Smuzhiyun unsigned op = 0;
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun /* debugging bookkeeping */
202*4882a593Smuzhiyun ss->previous_state = ss->current_state;
203*4882a593Smuzhiyun ss->previous_op = ss->current_op;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun ss->current_state = next_state;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun if (action[next_state].op_enable)
208*4882a593Smuzhiyun op |= QIB_SDMA_SENDCTRL_OP_ENABLE;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun if (action[next_state].op_intenable)
211*4882a593Smuzhiyun op |= QIB_SDMA_SENDCTRL_OP_INTENABLE;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (action[next_state].op_halt)
214*4882a593Smuzhiyun op |= QIB_SDMA_SENDCTRL_OP_HALT;
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun if (action[next_state].op_drain)
217*4882a593Smuzhiyun op |= QIB_SDMA_SENDCTRL_OP_DRAIN;
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun if (action[next_state].go_s99_running_tofalse)
220*4882a593Smuzhiyun ss->go_s99_running = 0;
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun if (action[next_state].go_s99_running_totrue)
223*4882a593Smuzhiyun ss->go_s99_running = 1;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun ss->current_op = op;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun ppd->dd->f_sdma_sendctrl(ppd, ss->current_op);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun
unmap_desc(struct qib_pportdata * ppd,unsigned head)230*4882a593Smuzhiyun static void unmap_desc(struct qib_pportdata *ppd, unsigned head)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun __le64 *descqp = &ppd->sdma_descq[head].qw[0];
233*4882a593Smuzhiyun u64 desc[2];
234*4882a593Smuzhiyun dma_addr_t addr;
235*4882a593Smuzhiyun size_t len;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun desc[0] = le64_to_cpu(descqp[0]);
238*4882a593Smuzhiyun desc[1] = le64_to_cpu(descqp[1]);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun addr = (desc[1] << 32) | (desc[0] >> 32);
241*4882a593Smuzhiyun len = (desc[0] >> 14) & (0x7ffULL << 2);
242*4882a593Smuzhiyun dma_unmap_single(&ppd->dd->pcidev->dev, addr, len, DMA_TO_DEVICE);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun
alloc_sdma(struct qib_pportdata * ppd)245*4882a593Smuzhiyun static int alloc_sdma(struct qib_pportdata *ppd)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun ppd->sdma_descq_cnt = sdma_descq_cnt;
248*4882a593Smuzhiyun if (!ppd->sdma_descq_cnt)
249*4882a593Smuzhiyun ppd->sdma_descq_cnt = 256;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun /* Allocate memory for SendDMA descriptor FIFO */
252*4882a593Smuzhiyun ppd->sdma_descq = dma_alloc_coherent(&ppd->dd->pcidev->dev,
253*4882a593Smuzhiyun ppd->sdma_descq_cnt * sizeof(u64[2]), &ppd->sdma_descq_phys,
254*4882a593Smuzhiyun GFP_KERNEL);
255*4882a593Smuzhiyun
256*4882a593Smuzhiyun if (!ppd->sdma_descq) {
257*4882a593Smuzhiyun qib_dev_err(ppd->dd,
258*4882a593Smuzhiyun "failed to allocate SendDMA descriptor FIFO memory\n");
259*4882a593Smuzhiyun goto bail;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun /* Allocate memory for DMA of head register to memory */
263*4882a593Smuzhiyun ppd->sdma_head_dma = dma_alloc_coherent(&ppd->dd->pcidev->dev,
264*4882a593Smuzhiyun PAGE_SIZE, &ppd->sdma_head_phys, GFP_KERNEL);
265*4882a593Smuzhiyun if (!ppd->sdma_head_dma) {
266*4882a593Smuzhiyun qib_dev_err(ppd->dd,
267*4882a593Smuzhiyun "failed to allocate SendDMA head memory\n");
268*4882a593Smuzhiyun goto cleanup_descq;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun ppd->sdma_head_dma[0] = 0;
271*4882a593Smuzhiyun return 0;
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun cleanup_descq:
274*4882a593Smuzhiyun dma_free_coherent(&ppd->dd->pcidev->dev,
275*4882a593Smuzhiyun ppd->sdma_descq_cnt * sizeof(u64[2]), (void *)ppd->sdma_descq,
276*4882a593Smuzhiyun ppd->sdma_descq_phys);
277*4882a593Smuzhiyun ppd->sdma_descq = NULL;
278*4882a593Smuzhiyun ppd->sdma_descq_phys = 0;
279*4882a593Smuzhiyun bail:
280*4882a593Smuzhiyun ppd->sdma_descq_cnt = 0;
281*4882a593Smuzhiyun return -ENOMEM;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun
free_sdma(struct qib_pportdata * ppd)284*4882a593Smuzhiyun static void free_sdma(struct qib_pportdata *ppd)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun struct qib_devdata *dd = ppd->dd;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun if (ppd->sdma_head_dma) {
289*4882a593Smuzhiyun dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
290*4882a593Smuzhiyun (void *)ppd->sdma_head_dma,
291*4882a593Smuzhiyun ppd->sdma_head_phys);
292*4882a593Smuzhiyun ppd->sdma_head_dma = NULL;
293*4882a593Smuzhiyun ppd->sdma_head_phys = 0;
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun if (ppd->sdma_descq) {
297*4882a593Smuzhiyun dma_free_coherent(&dd->pcidev->dev,
298*4882a593Smuzhiyun ppd->sdma_descq_cnt * sizeof(u64[2]),
299*4882a593Smuzhiyun ppd->sdma_descq, ppd->sdma_descq_phys);
300*4882a593Smuzhiyun ppd->sdma_descq = NULL;
301*4882a593Smuzhiyun ppd->sdma_descq_phys = 0;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
make_sdma_desc(struct qib_pportdata * ppd,u64 * sdmadesc,u64 addr,u64 dwlen,u64 dwoffset)305*4882a593Smuzhiyun static inline void make_sdma_desc(struct qib_pportdata *ppd,
306*4882a593Smuzhiyun u64 *sdmadesc, u64 addr, u64 dwlen,
307*4882a593Smuzhiyun u64 dwoffset)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun WARN_ON(addr & 3);
311*4882a593Smuzhiyun /* SDmaPhyAddr[47:32] */
312*4882a593Smuzhiyun sdmadesc[1] = addr >> 32;
313*4882a593Smuzhiyun /* SDmaPhyAddr[31:0] */
314*4882a593Smuzhiyun sdmadesc[0] = (addr & 0xfffffffcULL) << 32;
315*4882a593Smuzhiyun /* SDmaGeneration[1:0] */
316*4882a593Smuzhiyun sdmadesc[0] |= (ppd->sdma_generation & 3ULL) <<
317*4882a593Smuzhiyun SDMA_DESC_GEN_LSB;
318*4882a593Smuzhiyun /* SDmaDwordCount[10:0] */
319*4882a593Smuzhiyun sdmadesc[0] |= (dwlen & 0x7ffULL) << SDMA_DESC_COUNT_LSB;
320*4882a593Smuzhiyun /* SDmaBufOffset[12:2] */
321*4882a593Smuzhiyun sdmadesc[0] |= dwoffset & 0x7ffULL;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun /* sdma_lock must be held */
qib_sdma_make_progress(struct qib_pportdata * ppd)325*4882a593Smuzhiyun int qib_sdma_make_progress(struct qib_pportdata *ppd)
326*4882a593Smuzhiyun {
327*4882a593Smuzhiyun struct list_head *lp = NULL;
328*4882a593Smuzhiyun struct qib_sdma_txreq *txp = NULL;
329*4882a593Smuzhiyun struct qib_devdata *dd = ppd->dd;
330*4882a593Smuzhiyun int progress = 0;
331*4882a593Smuzhiyun u16 hwhead;
332*4882a593Smuzhiyun u16 idx = 0;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun hwhead = dd->f_sdma_gethead(ppd);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun /* The reason for some of the complexity of this code is that
337*4882a593Smuzhiyun * not all descriptors have corresponding txps. So, we have to
338*4882a593Smuzhiyun * be able to skip over descs until we wander into the range of
339*4882a593Smuzhiyun * the next txp on the list.
340*4882a593Smuzhiyun */
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun if (!list_empty(&ppd->sdma_activelist)) {
343*4882a593Smuzhiyun lp = ppd->sdma_activelist.next;
344*4882a593Smuzhiyun txp = list_entry(lp, struct qib_sdma_txreq, list);
345*4882a593Smuzhiyun idx = txp->start_idx;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun while (ppd->sdma_descq_head != hwhead) {
349*4882a593Smuzhiyun /* if desc is part of this txp, unmap if needed */
350*4882a593Smuzhiyun if (txp && (txp->flags & QIB_SDMA_TXREQ_F_FREEDESC) &&
351*4882a593Smuzhiyun (idx == ppd->sdma_descq_head)) {
352*4882a593Smuzhiyun unmap_desc(ppd, ppd->sdma_descq_head);
353*4882a593Smuzhiyun if (++idx == ppd->sdma_descq_cnt)
354*4882a593Smuzhiyun idx = 0;
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun /* increment dequed desc count */
358*4882a593Smuzhiyun ppd->sdma_descq_removed++;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun /* advance head, wrap if needed */
361*4882a593Smuzhiyun if (++ppd->sdma_descq_head == ppd->sdma_descq_cnt)
362*4882a593Smuzhiyun ppd->sdma_descq_head = 0;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun /* if now past this txp's descs, do the callback */
365*4882a593Smuzhiyun if (txp && txp->next_descq_idx == ppd->sdma_descq_head) {
366*4882a593Smuzhiyun /* remove from active list */
367*4882a593Smuzhiyun list_del_init(&txp->list);
368*4882a593Smuzhiyun if (txp->callback)
369*4882a593Smuzhiyun (*txp->callback)(txp, QIB_SDMA_TXREQ_S_OK);
370*4882a593Smuzhiyun /* see if there is another txp */
371*4882a593Smuzhiyun if (list_empty(&ppd->sdma_activelist))
372*4882a593Smuzhiyun txp = NULL;
373*4882a593Smuzhiyun else {
374*4882a593Smuzhiyun lp = ppd->sdma_activelist.next;
375*4882a593Smuzhiyun txp = list_entry(lp, struct qib_sdma_txreq,
376*4882a593Smuzhiyun list);
377*4882a593Smuzhiyun idx = txp->start_idx;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun progress = 1;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun if (progress)
383*4882a593Smuzhiyun qib_verbs_sdma_desc_avail(ppd, qib_sdma_descq_freecnt(ppd));
384*4882a593Smuzhiyun return progress;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun /*
388*4882a593Smuzhiyun * This is called from interrupt context.
389*4882a593Smuzhiyun */
qib_sdma_intr(struct qib_pportdata * ppd)390*4882a593Smuzhiyun void qib_sdma_intr(struct qib_pportdata *ppd)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun unsigned long flags;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun spin_lock_irqsave(&ppd->sdma_lock, flags);
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun __qib_sdma_intr(ppd);
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun spin_unlock_irqrestore(&ppd->sdma_lock, flags);
399*4882a593Smuzhiyun }
400*4882a593Smuzhiyun
__qib_sdma_intr(struct qib_pportdata * ppd)401*4882a593Smuzhiyun void __qib_sdma_intr(struct qib_pportdata *ppd)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun if (__qib_sdma_running(ppd)) {
404*4882a593Smuzhiyun qib_sdma_make_progress(ppd);
405*4882a593Smuzhiyun if (!list_empty(&ppd->sdma_userpending))
406*4882a593Smuzhiyun qib_user_sdma_send_desc(ppd, &ppd->sdma_userpending);
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
qib_setup_sdma(struct qib_pportdata * ppd)410*4882a593Smuzhiyun int qib_setup_sdma(struct qib_pportdata *ppd)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun struct qib_devdata *dd = ppd->dd;
413*4882a593Smuzhiyun unsigned long flags;
414*4882a593Smuzhiyun int ret = 0;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun ret = alloc_sdma(ppd);
417*4882a593Smuzhiyun if (ret)
418*4882a593Smuzhiyun goto bail;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun /* set consistent sdma state */
421*4882a593Smuzhiyun ppd->dd->f_sdma_init_early(ppd);
422*4882a593Smuzhiyun spin_lock_irqsave(&ppd->sdma_lock, flags);
423*4882a593Smuzhiyun sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
424*4882a593Smuzhiyun spin_unlock_irqrestore(&ppd->sdma_lock, flags);
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun /* set up reference counting */
427*4882a593Smuzhiyun kref_init(&ppd->sdma_state.kref);
428*4882a593Smuzhiyun init_completion(&ppd->sdma_state.comp);
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun ppd->sdma_generation = 0;
431*4882a593Smuzhiyun ppd->sdma_descq_head = 0;
432*4882a593Smuzhiyun ppd->sdma_descq_removed = 0;
433*4882a593Smuzhiyun ppd->sdma_descq_added = 0;
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun ppd->sdma_intrequest = 0;
436*4882a593Smuzhiyun INIT_LIST_HEAD(&ppd->sdma_userpending);
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun INIT_LIST_HEAD(&ppd->sdma_activelist);
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun tasklet_setup(&ppd->sdma_sw_clean_up_task, sdma_sw_clean_up_task);
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun ret = dd->f_init_sdma_regs(ppd);
443*4882a593Smuzhiyun if (ret)
444*4882a593Smuzhiyun goto bail_alloc;
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun qib_sdma_process_event(ppd, qib_sdma_event_e10_go_hw_start);
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun return 0;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun bail_alloc:
451*4882a593Smuzhiyun qib_teardown_sdma(ppd);
452*4882a593Smuzhiyun bail:
453*4882a593Smuzhiyun return ret;
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun
qib_teardown_sdma(struct qib_pportdata * ppd)456*4882a593Smuzhiyun void qib_teardown_sdma(struct qib_pportdata *ppd)
457*4882a593Smuzhiyun {
458*4882a593Smuzhiyun qib_sdma_process_event(ppd, qib_sdma_event_e00_go_hw_down);
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun /*
461*4882a593Smuzhiyun * This waits for the state machine to exit so it is not
462*4882a593Smuzhiyun * necessary to kill the sdma_sw_clean_up_task to make sure
463*4882a593Smuzhiyun * it is not running.
464*4882a593Smuzhiyun */
465*4882a593Smuzhiyun sdma_finalput(&ppd->sdma_state);
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun free_sdma(ppd);
468*4882a593Smuzhiyun }
469*4882a593Smuzhiyun
qib_sdma_running(struct qib_pportdata * ppd)470*4882a593Smuzhiyun int qib_sdma_running(struct qib_pportdata *ppd)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun unsigned long flags;
473*4882a593Smuzhiyun int ret;
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun spin_lock_irqsave(&ppd->sdma_lock, flags);
476*4882a593Smuzhiyun ret = __qib_sdma_running(ppd);
477*4882a593Smuzhiyun spin_unlock_irqrestore(&ppd->sdma_lock, flags);
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun return ret;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun /*
483*4882a593Smuzhiyun * Complete a request when sdma not running; likely only request
484*4882a593Smuzhiyun * but to simplify the code, always queue it, then process the full
485*4882a593Smuzhiyun * activelist. We process the entire list to ensure that this particular
486*4882a593Smuzhiyun * request does get it's callback, but in the correct order.
487*4882a593Smuzhiyun * Must be called with sdma_lock held
488*4882a593Smuzhiyun */
complete_sdma_err_req(struct qib_pportdata * ppd,struct qib_verbs_txreq * tx)489*4882a593Smuzhiyun static void complete_sdma_err_req(struct qib_pportdata *ppd,
490*4882a593Smuzhiyun struct qib_verbs_txreq *tx)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun struct qib_qp_priv *priv = tx->qp->priv;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun atomic_inc(&priv->s_dma_busy);
495*4882a593Smuzhiyun /* no sdma descriptors, so no unmap_desc */
496*4882a593Smuzhiyun tx->txreq.start_idx = 0;
497*4882a593Smuzhiyun tx->txreq.next_descq_idx = 0;
498*4882a593Smuzhiyun list_add_tail(&tx->txreq.list, &ppd->sdma_activelist);
499*4882a593Smuzhiyun clear_sdma_activelist(ppd);
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun /*
503*4882a593Smuzhiyun * This function queues one IB packet onto the send DMA queue per call.
504*4882a593Smuzhiyun * The caller is responsible for checking:
505*4882a593Smuzhiyun * 1) The number of send DMA descriptor entries is less than the size of
506*4882a593Smuzhiyun * the descriptor queue.
507*4882a593Smuzhiyun * 2) The IB SGE addresses and lengths are 32-bit aligned
508*4882a593Smuzhiyun * (except possibly the last SGE's length)
509*4882a593Smuzhiyun * 3) The SGE addresses are suitable for passing to dma_map_single().
510*4882a593Smuzhiyun */
qib_sdma_verbs_send(struct qib_pportdata * ppd,struct rvt_sge_state * ss,u32 dwords,struct qib_verbs_txreq * tx)511*4882a593Smuzhiyun int qib_sdma_verbs_send(struct qib_pportdata *ppd,
512*4882a593Smuzhiyun struct rvt_sge_state *ss, u32 dwords,
513*4882a593Smuzhiyun struct qib_verbs_txreq *tx)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun unsigned long flags;
516*4882a593Smuzhiyun struct rvt_sge *sge;
517*4882a593Smuzhiyun struct rvt_qp *qp;
518*4882a593Smuzhiyun int ret = 0;
519*4882a593Smuzhiyun u16 tail;
520*4882a593Smuzhiyun __le64 *descqp;
521*4882a593Smuzhiyun u64 sdmadesc[2];
522*4882a593Smuzhiyun u32 dwoffset;
523*4882a593Smuzhiyun dma_addr_t addr;
524*4882a593Smuzhiyun struct qib_qp_priv *priv;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun spin_lock_irqsave(&ppd->sdma_lock, flags);
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun retry:
529*4882a593Smuzhiyun if (unlikely(!__qib_sdma_running(ppd))) {
530*4882a593Smuzhiyun complete_sdma_err_req(ppd, tx);
531*4882a593Smuzhiyun goto unlock;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun if (tx->txreq.sg_count > qib_sdma_descq_freecnt(ppd)) {
535*4882a593Smuzhiyun if (qib_sdma_make_progress(ppd))
536*4882a593Smuzhiyun goto retry;
537*4882a593Smuzhiyun if (ppd->dd->flags & QIB_HAS_SDMA_TIMEOUT)
538*4882a593Smuzhiyun ppd->dd->f_sdma_set_desc_cnt(ppd,
539*4882a593Smuzhiyun ppd->sdma_descq_cnt / 2);
540*4882a593Smuzhiyun goto busy;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun dwoffset = tx->hdr_dwords;
544*4882a593Smuzhiyun make_sdma_desc(ppd, sdmadesc, (u64) tx->txreq.addr, dwoffset, 0);
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun sdmadesc[0] |= SDMA_DESC_FIRST;
547*4882a593Smuzhiyun if (tx->txreq.flags & QIB_SDMA_TXREQ_F_USELARGEBUF)
548*4882a593Smuzhiyun sdmadesc[0] |= SDMA_DESC_USE_LARGE_BUF;
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun /* write to the descq */
551*4882a593Smuzhiyun tail = ppd->sdma_descq_tail;
552*4882a593Smuzhiyun descqp = &ppd->sdma_descq[tail].qw[0];
553*4882a593Smuzhiyun *descqp++ = cpu_to_le64(sdmadesc[0]);
554*4882a593Smuzhiyun *descqp++ = cpu_to_le64(sdmadesc[1]);
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun /* increment the tail */
557*4882a593Smuzhiyun if (++tail == ppd->sdma_descq_cnt) {
558*4882a593Smuzhiyun tail = 0;
559*4882a593Smuzhiyun descqp = &ppd->sdma_descq[0].qw[0];
560*4882a593Smuzhiyun ++ppd->sdma_generation;
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun
563*4882a593Smuzhiyun tx->txreq.start_idx = tail;
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun sge = &ss->sge;
566*4882a593Smuzhiyun while (dwords) {
567*4882a593Smuzhiyun u32 dw;
568*4882a593Smuzhiyun u32 len = rvt_get_sge_length(sge, dwords << 2);
569*4882a593Smuzhiyun
570*4882a593Smuzhiyun dw = (len + 3) >> 2;
571*4882a593Smuzhiyun addr = dma_map_single(&ppd->dd->pcidev->dev, sge->vaddr,
572*4882a593Smuzhiyun dw << 2, DMA_TO_DEVICE);
573*4882a593Smuzhiyun if (dma_mapping_error(&ppd->dd->pcidev->dev, addr)) {
574*4882a593Smuzhiyun ret = -ENOMEM;
575*4882a593Smuzhiyun goto unmap;
576*4882a593Smuzhiyun }
577*4882a593Smuzhiyun sdmadesc[0] = 0;
578*4882a593Smuzhiyun make_sdma_desc(ppd, sdmadesc, (u64) addr, dw, dwoffset);
579*4882a593Smuzhiyun /* SDmaUseLargeBuf has to be set in every descriptor */
580*4882a593Smuzhiyun if (tx->txreq.flags & QIB_SDMA_TXREQ_F_USELARGEBUF)
581*4882a593Smuzhiyun sdmadesc[0] |= SDMA_DESC_USE_LARGE_BUF;
582*4882a593Smuzhiyun /* write to the descq */
583*4882a593Smuzhiyun *descqp++ = cpu_to_le64(sdmadesc[0]);
584*4882a593Smuzhiyun *descqp++ = cpu_to_le64(sdmadesc[1]);
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun /* increment the tail */
587*4882a593Smuzhiyun if (++tail == ppd->sdma_descq_cnt) {
588*4882a593Smuzhiyun tail = 0;
589*4882a593Smuzhiyun descqp = &ppd->sdma_descq[0].qw[0];
590*4882a593Smuzhiyun ++ppd->sdma_generation;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun rvt_update_sge(ss, len, false);
593*4882a593Smuzhiyun dwoffset += dw;
594*4882a593Smuzhiyun dwords -= dw;
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun
597*4882a593Smuzhiyun if (!tail)
598*4882a593Smuzhiyun descqp = &ppd->sdma_descq[ppd->sdma_descq_cnt].qw[0];
599*4882a593Smuzhiyun descqp -= 2;
600*4882a593Smuzhiyun descqp[0] |= cpu_to_le64(SDMA_DESC_LAST);
601*4882a593Smuzhiyun if (tx->txreq.flags & QIB_SDMA_TXREQ_F_HEADTOHOST)
602*4882a593Smuzhiyun descqp[0] |= cpu_to_le64(SDMA_DESC_DMA_HEAD);
603*4882a593Smuzhiyun if (tx->txreq.flags & QIB_SDMA_TXREQ_F_INTREQ)
604*4882a593Smuzhiyun descqp[0] |= cpu_to_le64(SDMA_DESC_INTR);
605*4882a593Smuzhiyun priv = tx->qp->priv;
606*4882a593Smuzhiyun atomic_inc(&priv->s_dma_busy);
607*4882a593Smuzhiyun tx->txreq.next_descq_idx = tail;
608*4882a593Smuzhiyun ppd->dd->f_sdma_update_tail(ppd, tail);
609*4882a593Smuzhiyun ppd->sdma_descq_added += tx->txreq.sg_count;
610*4882a593Smuzhiyun list_add_tail(&tx->txreq.list, &ppd->sdma_activelist);
611*4882a593Smuzhiyun goto unlock;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun unmap:
614*4882a593Smuzhiyun for (;;) {
615*4882a593Smuzhiyun if (!tail)
616*4882a593Smuzhiyun tail = ppd->sdma_descq_cnt - 1;
617*4882a593Smuzhiyun else
618*4882a593Smuzhiyun tail--;
619*4882a593Smuzhiyun if (tail == ppd->sdma_descq_tail)
620*4882a593Smuzhiyun break;
621*4882a593Smuzhiyun unmap_desc(ppd, tail);
622*4882a593Smuzhiyun }
623*4882a593Smuzhiyun qp = tx->qp;
624*4882a593Smuzhiyun priv = qp->priv;
625*4882a593Smuzhiyun qib_put_txreq(tx);
626*4882a593Smuzhiyun spin_lock(&qp->r_lock);
627*4882a593Smuzhiyun spin_lock(&qp->s_lock);
628*4882a593Smuzhiyun if (qp->ibqp.qp_type == IB_QPT_RC) {
629*4882a593Smuzhiyun /* XXX what about error sending RDMA read responses? */
630*4882a593Smuzhiyun if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK)
631*4882a593Smuzhiyun rvt_error_qp(qp, IB_WC_GENERAL_ERR);
632*4882a593Smuzhiyun } else if (qp->s_wqe)
633*4882a593Smuzhiyun rvt_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR);
634*4882a593Smuzhiyun spin_unlock(&qp->s_lock);
635*4882a593Smuzhiyun spin_unlock(&qp->r_lock);
636*4882a593Smuzhiyun /* return zero to process the next send work request */
637*4882a593Smuzhiyun goto unlock;
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun busy:
640*4882a593Smuzhiyun qp = tx->qp;
641*4882a593Smuzhiyun priv = qp->priv;
642*4882a593Smuzhiyun spin_lock(&qp->s_lock);
643*4882a593Smuzhiyun if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) {
644*4882a593Smuzhiyun struct qib_ibdev *dev;
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun /*
647*4882a593Smuzhiyun * If we couldn't queue the DMA request, save the info
648*4882a593Smuzhiyun * and try again later rather than destroying the
649*4882a593Smuzhiyun * buffer and undoing the side effects of the copy.
650*4882a593Smuzhiyun */
651*4882a593Smuzhiyun tx->ss = ss;
652*4882a593Smuzhiyun tx->dwords = dwords;
653*4882a593Smuzhiyun priv->s_tx = tx;
654*4882a593Smuzhiyun dev = &ppd->dd->verbs_dev;
655*4882a593Smuzhiyun spin_lock(&dev->rdi.pending_lock);
656*4882a593Smuzhiyun if (list_empty(&priv->iowait)) {
657*4882a593Smuzhiyun struct qib_ibport *ibp;
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun ibp = &ppd->ibport_data;
660*4882a593Smuzhiyun ibp->rvp.n_dmawait++;
661*4882a593Smuzhiyun qp->s_flags |= RVT_S_WAIT_DMA_DESC;
662*4882a593Smuzhiyun list_add_tail(&priv->iowait, &dev->dmawait);
663*4882a593Smuzhiyun }
664*4882a593Smuzhiyun spin_unlock(&dev->rdi.pending_lock);
665*4882a593Smuzhiyun qp->s_flags &= ~RVT_S_BUSY;
666*4882a593Smuzhiyun spin_unlock(&qp->s_lock);
667*4882a593Smuzhiyun ret = -EBUSY;
668*4882a593Smuzhiyun } else {
669*4882a593Smuzhiyun spin_unlock(&qp->s_lock);
670*4882a593Smuzhiyun qib_put_txreq(tx);
671*4882a593Smuzhiyun }
672*4882a593Smuzhiyun unlock:
673*4882a593Smuzhiyun spin_unlock_irqrestore(&ppd->sdma_lock, flags);
674*4882a593Smuzhiyun return ret;
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun /*
678*4882a593Smuzhiyun * sdma_lock should be acquired before calling this routine
679*4882a593Smuzhiyun */
dump_sdma_state(struct qib_pportdata * ppd)680*4882a593Smuzhiyun void dump_sdma_state(struct qib_pportdata *ppd)
681*4882a593Smuzhiyun {
682*4882a593Smuzhiyun struct qib_sdma_desc *descq;
683*4882a593Smuzhiyun struct qib_sdma_txreq *txp, *txpnext;
684*4882a593Smuzhiyun __le64 *descqp;
685*4882a593Smuzhiyun u64 desc[2];
686*4882a593Smuzhiyun u64 addr;
687*4882a593Smuzhiyun u16 gen, dwlen, dwoffset;
688*4882a593Smuzhiyun u16 head, tail, cnt;
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun head = ppd->sdma_descq_head;
691*4882a593Smuzhiyun tail = ppd->sdma_descq_tail;
692*4882a593Smuzhiyun cnt = qib_sdma_descq_freecnt(ppd);
693*4882a593Smuzhiyun descq = ppd->sdma_descq;
694*4882a593Smuzhiyun
695*4882a593Smuzhiyun qib_dev_porterr(ppd->dd, ppd->port,
696*4882a593Smuzhiyun "SDMA ppd->sdma_descq_head: %u\n", head);
697*4882a593Smuzhiyun qib_dev_porterr(ppd->dd, ppd->port,
698*4882a593Smuzhiyun "SDMA ppd->sdma_descq_tail: %u\n", tail);
699*4882a593Smuzhiyun qib_dev_porterr(ppd->dd, ppd->port,
700*4882a593Smuzhiyun "SDMA sdma_descq_freecnt: %u\n", cnt);
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun /* print info for each entry in the descriptor queue */
703*4882a593Smuzhiyun while (head != tail) {
704*4882a593Smuzhiyun char flags[6] = { 'x', 'x', 'x', 'x', 'x', 0 };
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun descqp = &descq[head].qw[0];
707*4882a593Smuzhiyun desc[0] = le64_to_cpu(descqp[0]);
708*4882a593Smuzhiyun desc[1] = le64_to_cpu(descqp[1]);
709*4882a593Smuzhiyun flags[0] = (desc[0] & 1<<15) ? 'I' : '-';
710*4882a593Smuzhiyun flags[1] = (desc[0] & 1<<14) ? 'L' : 'S';
711*4882a593Smuzhiyun flags[2] = (desc[0] & 1<<13) ? 'H' : '-';
712*4882a593Smuzhiyun flags[3] = (desc[0] & 1<<12) ? 'F' : '-';
713*4882a593Smuzhiyun flags[4] = (desc[0] & 1<<11) ? 'L' : '-';
714*4882a593Smuzhiyun addr = (desc[1] << 32) | ((desc[0] >> 32) & 0xfffffffcULL);
715*4882a593Smuzhiyun gen = (desc[0] >> 30) & 3ULL;
716*4882a593Smuzhiyun dwlen = (desc[0] >> 14) & (0x7ffULL << 2);
717*4882a593Smuzhiyun dwoffset = (desc[0] & 0x7ffULL) << 2;
718*4882a593Smuzhiyun qib_dev_porterr(ppd->dd, ppd->port,
719*4882a593Smuzhiyun "SDMA sdmadesc[%u]: flags:%s addr:0x%016llx gen:%u len:%u bytes offset:%u bytes\n",
720*4882a593Smuzhiyun head, flags, addr, gen, dwlen, dwoffset);
721*4882a593Smuzhiyun if (++head == ppd->sdma_descq_cnt)
722*4882a593Smuzhiyun head = 0;
723*4882a593Smuzhiyun }
724*4882a593Smuzhiyun
725*4882a593Smuzhiyun /* print dma descriptor indices from the TX requests */
726*4882a593Smuzhiyun list_for_each_entry_safe(txp, txpnext, &ppd->sdma_activelist,
727*4882a593Smuzhiyun list)
728*4882a593Smuzhiyun qib_dev_porterr(ppd->dd, ppd->port,
729*4882a593Smuzhiyun "SDMA txp->start_idx: %u txp->next_descq_idx: %u\n",
730*4882a593Smuzhiyun txp->start_idx, txp->next_descq_idx);
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun
qib_sdma_process_event(struct qib_pportdata * ppd,enum qib_sdma_events event)733*4882a593Smuzhiyun void qib_sdma_process_event(struct qib_pportdata *ppd,
734*4882a593Smuzhiyun enum qib_sdma_events event)
735*4882a593Smuzhiyun {
736*4882a593Smuzhiyun unsigned long flags;
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun spin_lock_irqsave(&ppd->sdma_lock, flags);
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun __qib_sdma_process_event(ppd, event);
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun if (ppd->sdma_state.current_state == qib_sdma_state_s99_running)
743*4882a593Smuzhiyun qib_verbs_sdma_desc_avail(ppd, qib_sdma_descq_freecnt(ppd));
744*4882a593Smuzhiyun
745*4882a593Smuzhiyun spin_unlock_irqrestore(&ppd->sdma_lock, flags);
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun
__qib_sdma_process_event(struct qib_pportdata * ppd,enum qib_sdma_events event)748*4882a593Smuzhiyun void __qib_sdma_process_event(struct qib_pportdata *ppd,
749*4882a593Smuzhiyun enum qib_sdma_events event)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun struct qib_sdma_state *ss = &ppd->sdma_state;
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun switch (ss->current_state) {
754*4882a593Smuzhiyun case qib_sdma_state_s00_hw_down:
755*4882a593Smuzhiyun switch (event) {
756*4882a593Smuzhiyun case qib_sdma_event_e00_go_hw_down:
757*4882a593Smuzhiyun break;
758*4882a593Smuzhiyun case qib_sdma_event_e30_go_running:
759*4882a593Smuzhiyun /*
760*4882a593Smuzhiyun * If down, but running requested (usually result
761*4882a593Smuzhiyun * of link up, then we need to start up.
762*4882a593Smuzhiyun * This can happen when hw down is requested while
763*4882a593Smuzhiyun * bringing the link up with traffic active on
764*4882a593Smuzhiyun * 7220, e.g. */
765*4882a593Smuzhiyun ss->go_s99_running = 1;
766*4882a593Smuzhiyun fallthrough; /* and start dma engine */
767*4882a593Smuzhiyun case qib_sdma_event_e10_go_hw_start:
768*4882a593Smuzhiyun /* This reference means the state machine is started */
769*4882a593Smuzhiyun sdma_get(&ppd->sdma_state);
770*4882a593Smuzhiyun sdma_set_state(ppd,
771*4882a593Smuzhiyun qib_sdma_state_s10_hw_start_up_wait);
772*4882a593Smuzhiyun break;
773*4882a593Smuzhiyun case qib_sdma_event_e20_hw_started:
774*4882a593Smuzhiyun break;
775*4882a593Smuzhiyun case qib_sdma_event_e40_sw_cleaned:
776*4882a593Smuzhiyun sdma_sw_tear_down(ppd);
777*4882a593Smuzhiyun break;
778*4882a593Smuzhiyun case qib_sdma_event_e50_hw_cleaned:
779*4882a593Smuzhiyun break;
780*4882a593Smuzhiyun case qib_sdma_event_e60_hw_halted:
781*4882a593Smuzhiyun break;
782*4882a593Smuzhiyun case qib_sdma_event_e70_go_idle:
783*4882a593Smuzhiyun break;
784*4882a593Smuzhiyun case qib_sdma_event_e7220_err_halted:
785*4882a593Smuzhiyun break;
786*4882a593Smuzhiyun case qib_sdma_event_e7322_err_halted:
787*4882a593Smuzhiyun break;
788*4882a593Smuzhiyun case qib_sdma_event_e90_timer_tick:
789*4882a593Smuzhiyun break;
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun break;
792*4882a593Smuzhiyun
793*4882a593Smuzhiyun case qib_sdma_state_s10_hw_start_up_wait:
794*4882a593Smuzhiyun switch (event) {
795*4882a593Smuzhiyun case qib_sdma_event_e00_go_hw_down:
796*4882a593Smuzhiyun sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
797*4882a593Smuzhiyun sdma_sw_tear_down(ppd);
798*4882a593Smuzhiyun break;
799*4882a593Smuzhiyun case qib_sdma_event_e10_go_hw_start:
800*4882a593Smuzhiyun break;
801*4882a593Smuzhiyun case qib_sdma_event_e20_hw_started:
802*4882a593Smuzhiyun sdma_set_state(ppd, ss->go_s99_running ?
803*4882a593Smuzhiyun qib_sdma_state_s99_running :
804*4882a593Smuzhiyun qib_sdma_state_s20_idle);
805*4882a593Smuzhiyun break;
806*4882a593Smuzhiyun case qib_sdma_event_e30_go_running:
807*4882a593Smuzhiyun ss->go_s99_running = 1;
808*4882a593Smuzhiyun break;
809*4882a593Smuzhiyun case qib_sdma_event_e40_sw_cleaned:
810*4882a593Smuzhiyun break;
811*4882a593Smuzhiyun case qib_sdma_event_e50_hw_cleaned:
812*4882a593Smuzhiyun break;
813*4882a593Smuzhiyun case qib_sdma_event_e60_hw_halted:
814*4882a593Smuzhiyun break;
815*4882a593Smuzhiyun case qib_sdma_event_e70_go_idle:
816*4882a593Smuzhiyun ss->go_s99_running = 0;
817*4882a593Smuzhiyun break;
818*4882a593Smuzhiyun case qib_sdma_event_e7220_err_halted:
819*4882a593Smuzhiyun break;
820*4882a593Smuzhiyun case qib_sdma_event_e7322_err_halted:
821*4882a593Smuzhiyun break;
822*4882a593Smuzhiyun case qib_sdma_event_e90_timer_tick:
823*4882a593Smuzhiyun break;
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun break;
826*4882a593Smuzhiyun
827*4882a593Smuzhiyun case qib_sdma_state_s20_idle:
828*4882a593Smuzhiyun switch (event) {
829*4882a593Smuzhiyun case qib_sdma_event_e00_go_hw_down:
830*4882a593Smuzhiyun sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
831*4882a593Smuzhiyun sdma_sw_tear_down(ppd);
832*4882a593Smuzhiyun break;
833*4882a593Smuzhiyun case qib_sdma_event_e10_go_hw_start:
834*4882a593Smuzhiyun break;
835*4882a593Smuzhiyun case qib_sdma_event_e20_hw_started:
836*4882a593Smuzhiyun break;
837*4882a593Smuzhiyun case qib_sdma_event_e30_go_running:
838*4882a593Smuzhiyun sdma_set_state(ppd, qib_sdma_state_s99_running);
839*4882a593Smuzhiyun ss->go_s99_running = 1;
840*4882a593Smuzhiyun break;
841*4882a593Smuzhiyun case qib_sdma_event_e40_sw_cleaned:
842*4882a593Smuzhiyun break;
843*4882a593Smuzhiyun case qib_sdma_event_e50_hw_cleaned:
844*4882a593Smuzhiyun break;
845*4882a593Smuzhiyun case qib_sdma_event_e60_hw_halted:
846*4882a593Smuzhiyun break;
847*4882a593Smuzhiyun case qib_sdma_event_e70_go_idle:
848*4882a593Smuzhiyun break;
849*4882a593Smuzhiyun case qib_sdma_event_e7220_err_halted:
850*4882a593Smuzhiyun break;
851*4882a593Smuzhiyun case qib_sdma_event_e7322_err_halted:
852*4882a593Smuzhiyun break;
853*4882a593Smuzhiyun case qib_sdma_event_e90_timer_tick:
854*4882a593Smuzhiyun break;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun break;
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun case qib_sdma_state_s30_sw_clean_up_wait:
859*4882a593Smuzhiyun switch (event) {
860*4882a593Smuzhiyun case qib_sdma_event_e00_go_hw_down:
861*4882a593Smuzhiyun sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
862*4882a593Smuzhiyun break;
863*4882a593Smuzhiyun case qib_sdma_event_e10_go_hw_start:
864*4882a593Smuzhiyun break;
865*4882a593Smuzhiyun case qib_sdma_event_e20_hw_started:
866*4882a593Smuzhiyun break;
867*4882a593Smuzhiyun case qib_sdma_event_e30_go_running:
868*4882a593Smuzhiyun ss->go_s99_running = 1;
869*4882a593Smuzhiyun break;
870*4882a593Smuzhiyun case qib_sdma_event_e40_sw_cleaned:
871*4882a593Smuzhiyun sdma_set_state(ppd,
872*4882a593Smuzhiyun qib_sdma_state_s10_hw_start_up_wait);
873*4882a593Smuzhiyun sdma_hw_start_up(ppd);
874*4882a593Smuzhiyun break;
875*4882a593Smuzhiyun case qib_sdma_event_e50_hw_cleaned:
876*4882a593Smuzhiyun break;
877*4882a593Smuzhiyun case qib_sdma_event_e60_hw_halted:
878*4882a593Smuzhiyun break;
879*4882a593Smuzhiyun case qib_sdma_event_e70_go_idle:
880*4882a593Smuzhiyun ss->go_s99_running = 0;
881*4882a593Smuzhiyun break;
882*4882a593Smuzhiyun case qib_sdma_event_e7220_err_halted:
883*4882a593Smuzhiyun break;
884*4882a593Smuzhiyun case qib_sdma_event_e7322_err_halted:
885*4882a593Smuzhiyun break;
886*4882a593Smuzhiyun case qib_sdma_event_e90_timer_tick:
887*4882a593Smuzhiyun break;
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun break;
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun case qib_sdma_state_s40_hw_clean_up_wait:
892*4882a593Smuzhiyun switch (event) {
893*4882a593Smuzhiyun case qib_sdma_event_e00_go_hw_down:
894*4882a593Smuzhiyun sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
895*4882a593Smuzhiyun sdma_start_sw_clean_up(ppd);
896*4882a593Smuzhiyun break;
897*4882a593Smuzhiyun case qib_sdma_event_e10_go_hw_start:
898*4882a593Smuzhiyun break;
899*4882a593Smuzhiyun case qib_sdma_event_e20_hw_started:
900*4882a593Smuzhiyun break;
901*4882a593Smuzhiyun case qib_sdma_event_e30_go_running:
902*4882a593Smuzhiyun ss->go_s99_running = 1;
903*4882a593Smuzhiyun break;
904*4882a593Smuzhiyun case qib_sdma_event_e40_sw_cleaned:
905*4882a593Smuzhiyun break;
906*4882a593Smuzhiyun case qib_sdma_event_e50_hw_cleaned:
907*4882a593Smuzhiyun sdma_set_state(ppd,
908*4882a593Smuzhiyun qib_sdma_state_s30_sw_clean_up_wait);
909*4882a593Smuzhiyun sdma_start_sw_clean_up(ppd);
910*4882a593Smuzhiyun break;
911*4882a593Smuzhiyun case qib_sdma_event_e60_hw_halted:
912*4882a593Smuzhiyun break;
913*4882a593Smuzhiyun case qib_sdma_event_e70_go_idle:
914*4882a593Smuzhiyun ss->go_s99_running = 0;
915*4882a593Smuzhiyun break;
916*4882a593Smuzhiyun case qib_sdma_event_e7220_err_halted:
917*4882a593Smuzhiyun break;
918*4882a593Smuzhiyun case qib_sdma_event_e7322_err_halted:
919*4882a593Smuzhiyun break;
920*4882a593Smuzhiyun case qib_sdma_event_e90_timer_tick:
921*4882a593Smuzhiyun break;
922*4882a593Smuzhiyun }
923*4882a593Smuzhiyun break;
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun case qib_sdma_state_s50_hw_halt_wait:
926*4882a593Smuzhiyun switch (event) {
927*4882a593Smuzhiyun case qib_sdma_event_e00_go_hw_down:
928*4882a593Smuzhiyun sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
929*4882a593Smuzhiyun sdma_start_sw_clean_up(ppd);
930*4882a593Smuzhiyun break;
931*4882a593Smuzhiyun case qib_sdma_event_e10_go_hw_start:
932*4882a593Smuzhiyun break;
933*4882a593Smuzhiyun case qib_sdma_event_e20_hw_started:
934*4882a593Smuzhiyun break;
935*4882a593Smuzhiyun case qib_sdma_event_e30_go_running:
936*4882a593Smuzhiyun ss->go_s99_running = 1;
937*4882a593Smuzhiyun break;
938*4882a593Smuzhiyun case qib_sdma_event_e40_sw_cleaned:
939*4882a593Smuzhiyun break;
940*4882a593Smuzhiyun case qib_sdma_event_e50_hw_cleaned:
941*4882a593Smuzhiyun break;
942*4882a593Smuzhiyun case qib_sdma_event_e60_hw_halted:
943*4882a593Smuzhiyun sdma_set_state(ppd,
944*4882a593Smuzhiyun qib_sdma_state_s40_hw_clean_up_wait);
945*4882a593Smuzhiyun ppd->dd->f_sdma_hw_clean_up(ppd);
946*4882a593Smuzhiyun break;
947*4882a593Smuzhiyun case qib_sdma_event_e70_go_idle:
948*4882a593Smuzhiyun ss->go_s99_running = 0;
949*4882a593Smuzhiyun break;
950*4882a593Smuzhiyun case qib_sdma_event_e7220_err_halted:
951*4882a593Smuzhiyun break;
952*4882a593Smuzhiyun case qib_sdma_event_e7322_err_halted:
953*4882a593Smuzhiyun break;
954*4882a593Smuzhiyun case qib_sdma_event_e90_timer_tick:
955*4882a593Smuzhiyun break;
956*4882a593Smuzhiyun }
957*4882a593Smuzhiyun break;
958*4882a593Smuzhiyun
959*4882a593Smuzhiyun case qib_sdma_state_s99_running:
960*4882a593Smuzhiyun switch (event) {
961*4882a593Smuzhiyun case qib_sdma_event_e00_go_hw_down:
962*4882a593Smuzhiyun sdma_set_state(ppd, qib_sdma_state_s00_hw_down);
963*4882a593Smuzhiyun sdma_start_sw_clean_up(ppd);
964*4882a593Smuzhiyun break;
965*4882a593Smuzhiyun case qib_sdma_event_e10_go_hw_start:
966*4882a593Smuzhiyun break;
967*4882a593Smuzhiyun case qib_sdma_event_e20_hw_started:
968*4882a593Smuzhiyun break;
969*4882a593Smuzhiyun case qib_sdma_event_e30_go_running:
970*4882a593Smuzhiyun break;
971*4882a593Smuzhiyun case qib_sdma_event_e40_sw_cleaned:
972*4882a593Smuzhiyun break;
973*4882a593Smuzhiyun case qib_sdma_event_e50_hw_cleaned:
974*4882a593Smuzhiyun break;
975*4882a593Smuzhiyun case qib_sdma_event_e60_hw_halted:
976*4882a593Smuzhiyun sdma_set_state(ppd,
977*4882a593Smuzhiyun qib_sdma_state_s30_sw_clean_up_wait);
978*4882a593Smuzhiyun sdma_start_sw_clean_up(ppd);
979*4882a593Smuzhiyun break;
980*4882a593Smuzhiyun case qib_sdma_event_e70_go_idle:
981*4882a593Smuzhiyun sdma_set_state(ppd, qib_sdma_state_s50_hw_halt_wait);
982*4882a593Smuzhiyun ss->go_s99_running = 0;
983*4882a593Smuzhiyun break;
984*4882a593Smuzhiyun case qib_sdma_event_e7220_err_halted:
985*4882a593Smuzhiyun sdma_set_state(ppd,
986*4882a593Smuzhiyun qib_sdma_state_s30_sw_clean_up_wait);
987*4882a593Smuzhiyun sdma_start_sw_clean_up(ppd);
988*4882a593Smuzhiyun break;
989*4882a593Smuzhiyun case qib_sdma_event_e7322_err_halted:
990*4882a593Smuzhiyun sdma_set_state(ppd, qib_sdma_state_s50_hw_halt_wait);
991*4882a593Smuzhiyun break;
992*4882a593Smuzhiyun case qib_sdma_event_e90_timer_tick:
993*4882a593Smuzhiyun break;
994*4882a593Smuzhiyun }
995*4882a593Smuzhiyun break;
996*4882a593Smuzhiyun }
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun ss->last_event = event;
999*4882a593Smuzhiyun }
1000