1145eba1aSCai Huoqing // SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
2f48ad614SDennis Dalessandro /*
3f9458bc2SKaike Wan * Copyright(c) 2015 - 2018 Intel Corporation.
4f48ad614SDennis Dalessandro */
5f48ad614SDennis Dalessandro
6f48ad614SDennis Dalessandro #include <linux/spinlock.h>
7f48ad614SDennis Dalessandro #include <linux/seqlock.h>
8f48ad614SDennis Dalessandro #include <linux/netdevice.h>
9f48ad614SDennis Dalessandro #include <linux/moduleparam.h>
10f48ad614SDennis Dalessandro #include <linux/bitops.h>
11f48ad614SDennis Dalessandro #include <linux/timer.h>
12f48ad614SDennis Dalessandro #include <linux/vmalloc.h>
13f48ad614SDennis Dalessandro #include <linux/highmem.h>
14f48ad614SDennis Dalessandro
15f48ad614SDennis Dalessandro #include "hfi.h"
16f48ad614SDennis Dalessandro #include "common.h"
17f48ad614SDennis Dalessandro #include "qp.h"
18f48ad614SDennis Dalessandro #include "sdma.h"
19f48ad614SDennis Dalessandro #include "iowait.h"
20f48ad614SDennis Dalessandro #include "trace.h"
21f48ad614SDennis Dalessandro
22f48ad614SDennis Dalessandro /* must be a power of 2 >= 64 <= 32768 */
23f48ad614SDennis Dalessandro #define SDMA_DESCQ_CNT 2048
24f48ad614SDennis Dalessandro #define SDMA_DESC_INTR 64
25f48ad614SDennis Dalessandro #define INVALID_TAIL 0xffff
2622bb1365SMike Marciniszyn #define SDMA_PAD max_t(size_t, MAX_16B_PADDING, sizeof(u32))
27f48ad614SDennis Dalessandro
28f48ad614SDennis Dalessandro static uint sdma_descq_cnt = SDMA_DESCQ_CNT;
29f48ad614SDennis Dalessandro module_param(sdma_descq_cnt, uint, S_IRUGO);
30f48ad614SDennis Dalessandro MODULE_PARM_DESC(sdma_descq_cnt, "Number of SDMA descq entries");
31f48ad614SDennis Dalessandro
32f48ad614SDennis Dalessandro static uint sdma_idle_cnt = 250;
33f48ad614SDennis Dalessandro module_param(sdma_idle_cnt, uint, S_IRUGO);
34f48ad614SDennis Dalessandro MODULE_PARM_DESC(sdma_idle_cnt, "sdma interrupt idle delay (ns,default 250)");
35f48ad614SDennis Dalessandro
36f48ad614SDennis Dalessandro uint mod_num_sdma;
37f48ad614SDennis Dalessandro module_param_named(num_sdma, mod_num_sdma, uint, S_IRUGO);
38f48ad614SDennis Dalessandro MODULE_PARM_DESC(num_sdma, "Set max number SDMA engines to use");
39f48ad614SDennis Dalessandro
40f48ad614SDennis Dalessandro static uint sdma_desct_intr = SDMA_DESC_INTR;
41f48ad614SDennis Dalessandro module_param_named(desct_intr, sdma_desct_intr, uint, S_IRUGO | S_IWUSR);
42f48ad614SDennis Dalessandro MODULE_PARM_DESC(desct_intr, "Number of SDMA descriptor before interrupt");
43f48ad614SDennis Dalessandro
44f48ad614SDennis Dalessandro #define SDMA_WAIT_BATCH_SIZE 20
45f48ad614SDennis Dalessandro /* max wait time for a SDMA engine to indicate it has halted */
46f48ad614SDennis Dalessandro #define SDMA_ERR_HALT_TIMEOUT 10 /* ms */
47f48ad614SDennis Dalessandro /* all SDMA engine errors that cause a halt */
48f48ad614SDennis Dalessandro
49f48ad614SDennis Dalessandro #define SD(name) SEND_DMA_##name
50f48ad614SDennis Dalessandro #define ALL_SDMA_ENG_HALT_ERRS \
51f48ad614SDennis Dalessandro (SD(ENG_ERR_STATUS_SDMA_WRONG_DW_ERR_SMASK) \
52f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_GEN_MISMATCH_ERR_SMASK) \
53f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_TOO_LONG_ERR_SMASK) \
54f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_TAIL_OUT_OF_BOUNDS_ERR_SMASK) \
55f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_FIRST_DESC_ERR_SMASK) \
56f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_MEM_READ_ERR_SMASK) \
57f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_HALT_ERR_SMASK) \
58f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_LENGTH_MISMATCH_ERR_SMASK) \
59f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_PACKET_DESC_OVERFLOW_ERR_SMASK) \
60f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_HEADER_SELECT_ERR_SMASK) \
61f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_HEADER_ADDRESS_ERR_SMASK) \
62f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_HEADER_LENGTH_ERR_SMASK) \
63f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_TIMEOUT_ERR_SMASK) \
64f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_DESC_TABLE_UNC_ERR_SMASK) \
65f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_ASSEMBLY_UNC_ERR_SMASK) \
66f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_PACKET_TRACKING_UNC_ERR_SMASK) \
67f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_HEADER_STORAGE_UNC_ERR_SMASK) \
68f48ad614SDennis Dalessandro | SD(ENG_ERR_STATUS_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_SMASK))
69f48ad614SDennis Dalessandro
70f48ad614SDennis Dalessandro /* sdma_sendctrl operations */
71f48ad614SDennis Dalessandro #define SDMA_SENDCTRL_OP_ENABLE BIT(0)
72f48ad614SDennis Dalessandro #define SDMA_SENDCTRL_OP_INTENABLE BIT(1)
73f48ad614SDennis Dalessandro #define SDMA_SENDCTRL_OP_HALT BIT(2)
74f48ad614SDennis Dalessandro #define SDMA_SENDCTRL_OP_CLEANUP BIT(3)
75f48ad614SDennis Dalessandro
76f48ad614SDennis Dalessandro /* handle long defines */
77f48ad614SDennis Dalessandro #define SDMA_EGRESS_PACKET_OCCUPANCY_SMASK \
78f48ad614SDennis Dalessandro SEND_EGRESS_SEND_DMA_STATUS_SDMA_EGRESS_PACKET_OCCUPANCY_SMASK
79f48ad614SDennis Dalessandro #define SDMA_EGRESS_PACKET_OCCUPANCY_SHIFT \
80f48ad614SDennis Dalessandro SEND_EGRESS_SEND_DMA_STATUS_SDMA_EGRESS_PACKET_OCCUPANCY_SHIFT
81f48ad614SDennis Dalessandro
82f48ad614SDennis Dalessandro static const char * const sdma_state_names[] = {
83f48ad614SDennis Dalessandro [sdma_state_s00_hw_down] = "s00_HwDown",
84f48ad614SDennis Dalessandro [sdma_state_s10_hw_start_up_halt_wait] = "s10_HwStartUpHaltWait",
85f48ad614SDennis Dalessandro [sdma_state_s15_hw_start_up_clean_wait] = "s15_HwStartUpCleanWait",
86f48ad614SDennis Dalessandro [sdma_state_s20_idle] = "s20_Idle",
87f48ad614SDennis Dalessandro [sdma_state_s30_sw_clean_up_wait] = "s30_SwCleanUpWait",
88f48ad614SDennis Dalessandro [sdma_state_s40_hw_clean_up_wait] = "s40_HwCleanUpWait",
89f48ad614SDennis Dalessandro [sdma_state_s50_hw_halt_wait] = "s50_HwHaltWait",
90f48ad614SDennis Dalessandro [sdma_state_s60_idle_halt_wait] = "s60_IdleHaltWait",
91f48ad614SDennis Dalessandro [sdma_state_s80_hw_freeze] = "s80_HwFreeze",
92f48ad614SDennis Dalessandro [sdma_state_s82_freeze_sw_clean] = "s82_FreezeSwClean",
93f48ad614SDennis Dalessandro [sdma_state_s99_running] = "s99_Running",
94f48ad614SDennis Dalessandro };
95f48ad614SDennis Dalessandro
96f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
97f48ad614SDennis Dalessandro static const char * const sdma_event_names[] = {
98f48ad614SDennis Dalessandro [sdma_event_e00_go_hw_down] = "e00_GoHwDown",
99f48ad614SDennis Dalessandro [sdma_event_e10_go_hw_start] = "e10_GoHwStart",
100f48ad614SDennis Dalessandro [sdma_event_e15_hw_halt_done] = "e15_HwHaltDone",
101f48ad614SDennis Dalessandro [sdma_event_e25_hw_clean_up_done] = "e25_HwCleanUpDone",
102f48ad614SDennis Dalessandro [sdma_event_e30_go_running] = "e30_GoRunning",
103f48ad614SDennis Dalessandro [sdma_event_e40_sw_cleaned] = "e40_SwCleaned",
104f48ad614SDennis Dalessandro [sdma_event_e50_hw_cleaned] = "e50_HwCleaned",
105f48ad614SDennis Dalessandro [sdma_event_e60_hw_halted] = "e60_HwHalted",
106f48ad614SDennis Dalessandro [sdma_event_e70_go_idle] = "e70_GoIdle",
107f48ad614SDennis Dalessandro [sdma_event_e80_hw_freeze] = "e80_HwFreeze",
108f48ad614SDennis Dalessandro [sdma_event_e81_hw_frozen] = "e81_HwFrozen",
109f48ad614SDennis Dalessandro [sdma_event_e82_hw_unfreeze] = "e82_HwUnfreeze",
110f48ad614SDennis Dalessandro [sdma_event_e85_link_down] = "e85_LinkDown",
111f48ad614SDennis Dalessandro [sdma_event_e90_sw_halted] = "e90_SwHalted",
112f48ad614SDennis Dalessandro };
113f48ad614SDennis Dalessandro #endif
114f48ad614SDennis Dalessandro
115f48ad614SDennis Dalessandro static const struct sdma_set_state_action sdma_action_table[] = {
116f48ad614SDennis Dalessandro [sdma_state_s00_hw_down] = {
117f48ad614SDennis Dalessandro .go_s99_running_tofalse = 1,
118f48ad614SDennis Dalessandro .op_enable = 0,
119f48ad614SDennis Dalessandro .op_intenable = 0,
120f48ad614SDennis Dalessandro .op_halt = 0,
121f48ad614SDennis Dalessandro .op_cleanup = 0,
122f48ad614SDennis Dalessandro },
123f48ad614SDennis Dalessandro [sdma_state_s10_hw_start_up_halt_wait] = {
124f48ad614SDennis Dalessandro .op_enable = 0,
125f48ad614SDennis Dalessandro .op_intenable = 0,
126f48ad614SDennis Dalessandro .op_halt = 1,
127f48ad614SDennis Dalessandro .op_cleanup = 0,
128f48ad614SDennis Dalessandro },
129f48ad614SDennis Dalessandro [sdma_state_s15_hw_start_up_clean_wait] = {
130f48ad614SDennis Dalessandro .op_enable = 0,
131f48ad614SDennis Dalessandro .op_intenable = 1,
132f48ad614SDennis Dalessandro .op_halt = 0,
133f48ad614SDennis Dalessandro .op_cleanup = 1,
134f48ad614SDennis Dalessandro },
135f48ad614SDennis Dalessandro [sdma_state_s20_idle] = {
136f48ad614SDennis Dalessandro .op_enable = 0,
137f48ad614SDennis Dalessandro .op_intenable = 1,
138f48ad614SDennis Dalessandro .op_halt = 0,
139f48ad614SDennis Dalessandro .op_cleanup = 0,
140f48ad614SDennis Dalessandro },
141f48ad614SDennis Dalessandro [sdma_state_s30_sw_clean_up_wait] = {
142f48ad614SDennis Dalessandro .op_enable = 0,
143f48ad614SDennis Dalessandro .op_intenable = 0,
144f48ad614SDennis Dalessandro .op_halt = 0,
145f48ad614SDennis Dalessandro .op_cleanup = 0,
146f48ad614SDennis Dalessandro },
147f48ad614SDennis Dalessandro [sdma_state_s40_hw_clean_up_wait] = {
148f48ad614SDennis Dalessandro .op_enable = 0,
149f48ad614SDennis Dalessandro .op_intenable = 0,
150f48ad614SDennis Dalessandro .op_halt = 0,
151f48ad614SDennis Dalessandro .op_cleanup = 1,
152f48ad614SDennis Dalessandro },
153f48ad614SDennis Dalessandro [sdma_state_s50_hw_halt_wait] = {
154f48ad614SDennis Dalessandro .op_enable = 0,
155f48ad614SDennis Dalessandro .op_intenable = 0,
156f48ad614SDennis Dalessandro .op_halt = 0,
157f48ad614SDennis Dalessandro .op_cleanup = 0,
158f48ad614SDennis Dalessandro },
159f48ad614SDennis Dalessandro [sdma_state_s60_idle_halt_wait] = {
160f48ad614SDennis Dalessandro .go_s99_running_tofalse = 1,
161f48ad614SDennis Dalessandro .op_enable = 0,
162f48ad614SDennis Dalessandro .op_intenable = 0,
163f48ad614SDennis Dalessandro .op_halt = 1,
164f48ad614SDennis Dalessandro .op_cleanup = 0,
165f48ad614SDennis Dalessandro },
166f48ad614SDennis Dalessandro [sdma_state_s80_hw_freeze] = {
167f48ad614SDennis Dalessandro .op_enable = 0,
168f48ad614SDennis Dalessandro .op_intenable = 0,
169f48ad614SDennis Dalessandro .op_halt = 0,
170f48ad614SDennis Dalessandro .op_cleanup = 0,
171f48ad614SDennis Dalessandro },
172f48ad614SDennis Dalessandro [sdma_state_s82_freeze_sw_clean] = {
173f48ad614SDennis Dalessandro .op_enable = 0,
174f48ad614SDennis Dalessandro .op_intenable = 0,
175f48ad614SDennis Dalessandro .op_halt = 0,
176f48ad614SDennis Dalessandro .op_cleanup = 0,
177f48ad614SDennis Dalessandro },
178f48ad614SDennis Dalessandro [sdma_state_s99_running] = {
179f48ad614SDennis Dalessandro .op_enable = 1,
180f48ad614SDennis Dalessandro .op_intenable = 1,
181f48ad614SDennis Dalessandro .op_halt = 0,
182f48ad614SDennis Dalessandro .op_cleanup = 0,
183f48ad614SDennis Dalessandro .go_s99_running_totrue = 1,
184f48ad614SDennis Dalessandro },
185f48ad614SDennis Dalessandro };
186f48ad614SDennis Dalessandro
187f48ad614SDennis Dalessandro #define SDMA_TAIL_UPDATE_THRESH 0x1F
188f48ad614SDennis Dalessandro
189f48ad614SDennis Dalessandro /* declare all statics here rather than keep sorting */
190f48ad614SDennis Dalessandro static void sdma_complete(struct kref *);
191f48ad614SDennis Dalessandro static void sdma_finalput(struct sdma_state *);
192f48ad614SDennis Dalessandro static void sdma_get(struct sdma_state *);
19355db47d0SAllen Pais static void sdma_hw_clean_up_task(struct tasklet_struct *);
194f48ad614SDennis Dalessandro static void sdma_put(struct sdma_state *);
195f48ad614SDennis Dalessandro static void sdma_set_state(struct sdma_engine *, enum sdma_states);
196f48ad614SDennis Dalessandro static void sdma_start_hw_clean_up(struct sdma_engine *);
19755db47d0SAllen Pais static void sdma_sw_clean_up_task(struct tasklet_struct *);
198f48ad614SDennis Dalessandro static void sdma_sendctrl(struct sdma_engine *, unsigned);
199f48ad614SDennis Dalessandro static void init_sdma_regs(struct sdma_engine *, u32, uint);
200f48ad614SDennis Dalessandro static void sdma_process_event(
201f48ad614SDennis Dalessandro struct sdma_engine *sde,
202f48ad614SDennis Dalessandro enum sdma_events event);
203f48ad614SDennis Dalessandro static void __sdma_process_event(
204f48ad614SDennis Dalessandro struct sdma_engine *sde,
205f48ad614SDennis Dalessandro enum sdma_events event);
206f48ad614SDennis Dalessandro static void dump_sdma_state(struct sdma_engine *sde);
207f48ad614SDennis Dalessandro static void sdma_make_progress(struct sdma_engine *sde, u64 status);
208bcad2913SKaike Wan static void sdma_desc_avail(struct sdma_engine *sde, uint avail);
209f48ad614SDennis Dalessandro static void sdma_flush_descq(struct sdma_engine *sde);
210f48ad614SDennis Dalessandro
211f48ad614SDennis Dalessandro /**
212f48ad614SDennis Dalessandro * sdma_state_name() - return state string from enum
213f48ad614SDennis Dalessandro * @state: state
214f48ad614SDennis Dalessandro */
sdma_state_name(enum sdma_states state)215f48ad614SDennis Dalessandro static const char *sdma_state_name(enum sdma_states state)
216f48ad614SDennis Dalessandro {
217f48ad614SDennis Dalessandro return sdma_state_names[state];
218f48ad614SDennis Dalessandro }
219f48ad614SDennis Dalessandro
sdma_get(struct sdma_state * ss)220f48ad614SDennis Dalessandro static void sdma_get(struct sdma_state *ss)
221f48ad614SDennis Dalessandro {
222f48ad614SDennis Dalessandro kref_get(&ss->kref);
223f48ad614SDennis Dalessandro }
224f48ad614SDennis Dalessandro
sdma_complete(struct kref * kref)225f48ad614SDennis Dalessandro static void sdma_complete(struct kref *kref)
226f48ad614SDennis Dalessandro {
227f48ad614SDennis Dalessandro struct sdma_state *ss =
228f48ad614SDennis Dalessandro container_of(kref, struct sdma_state, kref);
229f48ad614SDennis Dalessandro
230f48ad614SDennis Dalessandro complete(&ss->comp);
231f48ad614SDennis Dalessandro }
232f48ad614SDennis Dalessandro
sdma_put(struct sdma_state * ss)233f48ad614SDennis Dalessandro static void sdma_put(struct sdma_state *ss)
234f48ad614SDennis Dalessandro {
235f48ad614SDennis Dalessandro kref_put(&ss->kref, sdma_complete);
236f48ad614SDennis Dalessandro }
237f48ad614SDennis Dalessandro
sdma_finalput(struct sdma_state * ss)238f48ad614SDennis Dalessandro static void sdma_finalput(struct sdma_state *ss)
239f48ad614SDennis Dalessandro {
240f48ad614SDennis Dalessandro sdma_put(ss);
241f48ad614SDennis Dalessandro wait_for_completion(&ss->comp);
242f48ad614SDennis Dalessandro }
243f48ad614SDennis Dalessandro
write_sde_csr(struct sdma_engine * sde,u32 offset0,u64 value)244f48ad614SDennis Dalessandro static inline void write_sde_csr(
245f48ad614SDennis Dalessandro struct sdma_engine *sde,
246f48ad614SDennis Dalessandro u32 offset0,
247f48ad614SDennis Dalessandro u64 value)
248f48ad614SDennis Dalessandro {
249f48ad614SDennis Dalessandro write_kctxt_csr(sde->dd, sde->this_idx, offset0, value);
250f48ad614SDennis Dalessandro }
251f48ad614SDennis Dalessandro
read_sde_csr(struct sdma_engine * sde,u32 offset0)252f48ad614SDennis Dalessandro static inline u64 read_sde_csr(
253f48ad614SDennis Dalessandro struct sdma_engine *sde,
254f48ad614SDennis Dalessandro u32 offset0)
255f48ad614SDennis Dalessandro {
256f48ad614SDennis Dalessandro return read_kctxt_csr(sde->dd, sde->this_idx, offset0);
257f48ad614SDennis Dalessandro }
258f48ad614SDennis Dalessandro
259f48ad614SDennis Dalessandro /*
260f48ad614SDennis Dalessandro * sdma_wait_for_packet_egress() - wait for the VL FIFO occupancy for
261f48ad614SDennis Dalessandro * sdma engine 'sde' to drop to 0.
262f48ad614SDennis Dalessandro */
sdma_wait_for_packet_egress(struct sdma_engine * sde,int pause)263f48ad614SDennis Dalessandro static void sdma_wait_for_packet_egress(struct sdma_engine *sde,
264f48ad614SDennis Dalessandro int pause)
265f48ad614SDennis Dalessandro {
266f48ad614SDennis Dalessandro u64 off = 8 * sde->this_idx;
267f48ad614SDennis Dalessandro struct hfi1_devdata *dd = sde->dd;
268f48ad614SDennis Dalessandro int lcnt = 0;
269f48ad614SDennis Dalessandro u64 reg_prev;
270f48ad614SDennis Dalessandro u64 reg = 0;
271f48ad614SDennis Dalessandro
272f48ad614SDennis Dalessandro while (1) {
273f48ad614SDennis Dalessandro reg_prev = reg;
274f48ad614SDennis Dalessandro reg = read_csr(dd, off + SEND_EGRESS_SEND_DMA_STATUS);
275f48ad614SDennis Dalessandro
276f48ad614SDennis Dalessandro reg &= SDMA_EGRESS_PACKET_OCCUPANCY_SMASK;
277f48ad614SDennis Dalessandro reg >>= SDMA_EGRESS_PACKET_OCCUPANCY_SHIFT;
278f48ad614SDennis Dalessandro if (reg == 0)
279f48ad614SDennis Dalessandro break;
280f48ad614SDennis Dalessandro /* counter is reest if accupancy count changes */
281f48ad614SDennis Dalessandro if (reg != reg_prev)
282f48ad614SDennis Dalessandro lcnt = 0;
283f48ad614SDennis Dalessandro if (lcnt++ > 500) {
284f48ad614SDennis Dalessandro /* timed out - bounce the link */
285f48ad614SDennis Dalessandro dd_dev_err(dd, "%s: engine %u timeout waiting for packets to egress, remaining count %u, bouncing link\n",
286f48ad614SDennis Dalessandro __func__, sde->this_idx, (u32)reg);
28771d47008SSebastian Sanchez queue_work(dd->pport->link_wq,
288f48ad614SDennis Dalessandro &dd->pport->link_bounce_work);
289f48ad614SDennis Dalessandro break;
290f48ad614SDennis Dalessandro }
291f48ad614SDennis Dalessandro udelay(1);
292f48ad614SDennis Dalessandro }
293f48ad614SDennis Dalessandro }
294f48ad614SDennis Dalessandro
295f48ad614SDennis Dalessandro /*
296f48ad614SDennis Dalessandro * sdma_wait() - wait for packet egress to complete for all SDMA engines,
297f48ad614SDennis Dalessandro * and pause for credit return.
298f48ad614SDennis Dalessandro */
sdma_wait(struct hfi1_devdata * dd)299f48ad614SDennis Dalessandro void sdma_wait(struct hfi1_devdata *dd)
300f48ad614SDennis Dalessandro {
301f48ad614SDennis Dalessandro int i;
302f48ad614SDennis Dalessandro
303f48ad614SDennis Dalessandro for (i = 0; i < dd->num_sdma; i++) {
304f48ad614SDennis Dalessandro struct sdma_engine *sde = &dd->per_sdma[i];
305f48ad614SDennis Dalessandro
306f48ad614SDennis Dalessandro sdma_wait_for_packet_egress(sde, 0);
307f48ad614SDennis Dalessandro }
308f48ad614SDennis Dalessandro }
309f48ad614SDennis Dalessandro
sdma_set_desc_cnt(struct sdma_engine * sde,unsigned cnt)310f48ad614SDennis Dalessandro static inline void sdma_set_desc_cnt(struct sdma_engine *sde, unsigned cnt)
311f48ad614SDennis Dalessandro {
312f48ad614SDennis Dalessandro u64 reg;
313f48ad614SDennis Dalessandro
314f48ad614SDennis Dalessandro if (!(sde->dd->flags & HFI1_HAS_SDMA_TIMEOUT))
315f48ad614SDennis Dalessandro return;
316f48ad614SDennis Dalessandro reg = cnt;
317f48ad614SDennis Dalessandro reg &= SD(DESC_CNT_CNT_MASK);
318f48ad614SDennis Dalessandro reg <<= SD(DESC_CNT_CNT_SHIFT);
319f48ad614SDennis Dalessandro write_sde_csr(sde, SD(DESC_CNT), reg);
320f48ad614SDennis Dalessandro }
321f48ad614SDennis Dalessandro
complete_tx(struct sdma_engine * sde,struct sdma_txreq * tx,int res)322f48ad614SDennis Dalessandro static inline void complete_tx(struct sdma_engine *sde,
323f48ad614SDennis Dalessandro struct sdma_txreq *tx,
324f48ad614SDennis Dalessandro int res)
325f48ad614SDennis Dalessandro {
326f48ad614SDennis Dalessandro /* protect against complete modifying */
327f48ad614SDennis Dalessandro struct iowait *wait = tx->wait;
328f48ad614SDennis Dalessandro callback_t complete = tx->complete;
329f48ad614SDennis Dalessandro
330f48ad614SDennis Dalessandro #ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
331f48ad614SDennis Dalessandro trace_hfi1_sdma_out_sn(sde, tx->sn);
332f48ad614SDennis Dalessandro if (WARN_ON_ONCE(sde->head_sn != tx->sn))
333f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "expected %llu got %llu\n",
334f48ad614SDennis Dalessandro sde->head_sn, tx->sn);
335f48ad614SDennis Dalessandro sde->head_sn++;
336f48ad614SDennis Dalessandro #endif
33763df8e09SMike Marciniszyn __sdma_txclean(sde->dd, tx);
338f48ad614SDennis Dalessandro if (complete)
339f48ad614SDennis Dalessandro (*complete)(tx, res);
3405da0fc9dSDennis Dalessandro if (iowait_sdma_dec(wait))
341f48ad614SDennis Dalessandro iowait_drain_wakeup(wait);
342f48ad614SDennis Dalessandro }
343f48ad614SDennis Dalessandro
344f48ad614SDennis Dalessandro /*
345f48ad614SDennis Dalessandro * Complete all the sdma requests with a SDMA_TXREQ_S_ABORTED status
346f48ad614SDennis Dalessandro *
347f48ad614SDennis Dalessandro * Depending on timing there can be txreqs in two places:
348f48ad614SDennis Dalessandro * - in the descq ring
349f48ad614SDennis Dalessandro * - in the flush list
350f48ad614SDennis Dalessandro *
351f48ad614SDennis Dalessandro * To avoid ordering issues the descq ring needs to be flushed
352f48ad614SDennis Dalessandro * first followed by the flush list.
353f48ad614SDennis Dalessandro *
354f48ad614SDennis Dalessandro * This routine is called from two places
355f48ad614SDennis Dalessandro * - From a work queue item
356f48ad614SDennis Dalessandro * - Directly from the state machine just before setting the
357f48ad614SDennis Dalessandro * state to running
358f48ad614SDennis Dalessandro *
359f48ad614SDennis Dalessandro * Must be called with head_lock held
360f48ad614SDennis Dalessandro *
361f48ad614SDennis Dalessandro */
sdma_flush(struct sdma_engine * sde)362f48ad614SDennis Dalessandro static void sdma_flush(struct sdma_engine *sde)
363f48ad614SDennis Dalessandro {
364f48ad614SDennis Dalessandro struct sdma_txreq *txp, *txp_next;
365f48ad614SDennis Dalessandro LIST_HEAD(flushlist);
366f48ad614SDennis Dalessandro unsigned long flags;
367f972775bSMike Marciniszyn uint seq;
368f48ad614SDennis Dalessandro
369f48ad614SDennis Dalessandro /* flush from head to tail */
370f48ad614SDennis Dalessandro sdma_flush_descq(sde);
371f48ad614SDennis Dalessandro spin_lock_irqsave(&sde->flushlist_lock, flags);
372f48ad614SDennis Dalessandro /* copy flush list */
373cf131a81SMike Marciniszyn list_splice_init(&sde->flushlist, &flushlist);
374f48ad614SDennis Dalessandro spin_unlock_irqrestore(&sde->flushlist_lock, flags);
375f48ad614SDennis Dalessandro /* flush from flush list */
376f48ad614SDennis Dalessandro list_for_each_entry_safe(txp, txp_next, &flushlist, list)
377f48ad614SDennis Dalessandro complete_tx(sde, txp, SDMA_TXREQ_S_ABORTED);
378f972775bSMike Marciniszyn /* wakeup QPs orphaned on the dmawait list */
379f972775bSMike Marciniszyn do {
380f972775bSMike Marciniszyn struct iowait *w, *nw;
381f972775bSMike Marciniszyn
382f972775bSMike Marciniszyn seq = read_seqbegin(&sde->waitlock);
383f972775bSMike Marciniszyn if (!list_empty(&sde->dmawait)) {
384f972775bSMike Marciniszyn write_seqlock(&sde->waitlock);
385f972775bSMike Marciniszyn list_for_each_entry_safe(w, nw, &sde->dmawait, list) {
386f972775bSMike Marciniszyn if (w->wakeup) {
387f972775bSMike Marciniszyn w->wakeup(w, SDMA_AVAIL_REASON);
388f972775bSMike Marciniszyn list_del_init(&w->list);
389f972775bSMike Marciniszyn }
390f972775bSMike Marciniszyn }
391f972775bSMike Marciniszyn write_sequnlock(&sde->waitlock);
392f972775bSMike Marciniszyn }
393f972775bSMike Marciniszyn } while (read_seqretry(&sde->waitlock, seq));
394f48ad614SDennis Dalessandro }
395f48ad614SDennis Dalessandro
396f48ad614SDennis Dalessandro /*
397f48ad614SDennis Dalessandro * Fields a work request for flushing the descq ring
398f48ad614SDennis Dalessandro * and the flush list
399f48ad614SDennis Dalessandro *
400f48ad614SDennis Dalessandro * If the engine has been brought to running during
401f48ad614SDennis Dalessandro * the scheduling delay, the flush is ignored, assuming
402f48ad614SDennis Dalessandro * that the process of bringing the engine to running
403f48ad614SDennis Dalessandro * would have done this flush prior to going to running.
404f48ad614SDennis Dalessandro *
405f48ad614SDennis Dalessandro */
sdma_field_flush(struct work_struct * work)406f48ad614SDennis Dalessandro static void sdma_field_flush(struct work_struct *work)
407f48ad614SDennis Dalessandro {
408f48ad614SDennis Dalessandro unsigned long flags;
409f48ad614SDennis Dalessandro struct sdma_engine *sde =
410f48ad614SDennis Dalessandro container_of(work, struct sdma_engine, flush_worker);
411f48ad614SDennis Dalessandro
412f48ad614SDennis Dalessandro write_seqlock_irqsave(&sde->head_lock, flags);
413f48ad614SDennis Dalessandro if (!__sdma_running(sde))
414f48ad614SDennis Dalessandro sdma_flush(sde);
415f48ad614SDennis Dalessandro write_sequnlock_irqrestore(&sde->head_lock, flags);
416f48ad614SDennis Dalessandro }
417f48ad614SDennis Dalessandro
sdma_err_halt_wait(struct work_struct * work)418f48ad614SDennis Dalessandro static void sdma_err_halt_wait(struct work_struct *work)
419f48ad614SDennis Dalessandro {
420f48ad614SDennis Dalessandro struct sdma_engine *sde = container_of(work, struct sdma_engine,
421f48ad614SDennis Dalessandro err_halt_worker);
422f48ad614SDennis Dalessandro u64 statuscsr;
423f48ad614SDennis Dalessandro unsigned long timeout;
424f48ad614SDennis Dalessandro
425f48ad614SDennis Dalessandro timeout = jiffies + msecs_to_jiffies(SDMA_ERR_HALT_TIMEOUT);
426f48ad614SDennis Dalessandro while (1) {
427f48ad614SDennis Dalessandro statuscsr = read_sde_csr(sde, SD(STATUS));
428f48ad614SDennis Dalessandro statuscsr &= SD(STATUS_ENG_HALTED_SMASK);
429f48ad614SDennis Dalessandro if (statuscsr)
430f48ad614SDennis Dalessandro break;
431f48ad614SDennis Dalessandro if (time_after(jiffies, timeout)) {
432f48ad614SDennis Dalessandro dd_dev_err(sde->dd,
433f48ad614SDennis Dalessandro "SDMA engine %d - timeout waiting for engine to halt\n",
434f48ad614SDennis Dalessandro sde->this_idx);
435f48ad614SDennis Dalessandro /*
436f48ad614SDennis Dalessandro * Continue anyway. This could happen if there was
437f48ad614SDennis Dalessandro * an uncorrectable error in the wrong spot.
438f48ad614SDennis Dalessandro */
439f48ad614SDennis Dalessandro break;
440f48ad614SDennis Dalessandro }
441f48ad614SDennis Dalessandro usleep_range(80, 120);
442f48ad614SDennis Dalessandro }
443f48ad614SDennis Dalessandro
444f48ad614SDennis Dalessandro sdma_process_event(sde, sdma_event_e15_hw_halt_done);
445f48ad614SDennis Dalessandro }
446f48ad614SDennis Dalessandro
sdma_err_progress_check_schedule(struct sdma_engine * sde)447f48ad614SDennis Dalessandro static void sdma_err_progress_check_schedule(struct sdma_engine *sde)
448f48ad614SDennis Dalessandro {
449f48ad614SDennis Dalessandro if (!is_bx(sde->dd) && HFI1_CAP_IS_KSET(SDMA_AHG)) {
450f48ad614SDennis Dalessandro unsigned index;
451f48ad614SDennis Dalessandro struct hfi1_devdata *dd = sde->dd;
452f48ad614SDennis Dalessandro
453f48ad614SDennis Dalessandro for (index = 0; index < dd->num_sdma; index++) {
454f48ad614SDennis Dalessandro struct sdma_engine *curr_sdma = &dd->per_sdma[index];
455f48ad614SDennis Dalessandro
456f48ad614SDennis Dalessandro if (curr_sdma != sde)
457f48ad614SDennis Dalessandro curr_sdma->progress_check_head =
458f48ad614SDennis Dalessandro curr_sdma->descq_head;
459f48ad614SDennis Dalessandro }
460f48ad614SDennis Dalessandro dd_dev_err(sde->dd,
461f48ad614SDennis Dalessandro "SDMA engine %d - check scheduled\n",
462f48ad614SDennis Dalessandro sde->this_idx);
463f48ad614SDennis Dalessandro mod_timer(&sde->err_progress_check_timer, jiffies + 10);
464f48ad614SDennis Dalessandro }
465f48ad614SDennis Dalessandro }
466f48ad614SDennis Dalessandro
sdma_err_progress_check(struct timer_list * t)4678064135eSKees Cook static void sdma_err_progress_check(struct timer_list *t)
468f48ad614SDennis Dalessandro {
469f48ad614SDennis Dalessandro unsigned index;
4708064135eSKees Cook struct sdma_engine *sde = from_timer(sde, t, err_progress_check_timer);
471f48ad614SDennis Dalessandro
472f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "SDE progress check event\n");
473f48ad614SDennis Dalessandro for (index = 0; index < sde->dd->num_sdma; index++) {
474f48ad614SDennis Dalessandro struct sdma_engine *curr_sde = &sde->dd->per_sdma[index];
475f48ad614SDennis Dalessandro unsigned long flags;
476f48ad614SDennis Dalessandro
477f48ad614SDennis Dalessandro /* check progress on each engine except the current one */
478f48ad614SDennis Dalessandro if (curr_sde == sde)
479f48ad614SDennis Dalessandro continue;
480f48ad614SDennis Dalessandro /*
481f48ad614SDennis Dalessandro * We must lock interrupts when acquiring sde->lock,
482f48ad614SDennis Dalessandro * to avoid a deadlock if interrupt triggers and spins on
483f48ad614SDennis Dalessandro * the same lock on same CPU
484f48ad614SDennis Dalessandro */
485f48ad614SDennis Dalessandro spin_lock_irqsave(&curr_sde->tail_lock, flags);
486f48ad614SDennis Dalessandro write_seqlock(&curr_sde->head_lock);
487f48ad614SDennis Dalessandro
488f48ad614SDennis Dalessandro /* skip non-running queues */
489f48ad614SDennis Dalessandro if (curr_sde->state.current_state != sdma_state_s99_running) {
490f48ad614SDennis Dalessandro write_sequnlock(&curr_sde->head_lock);
491f48ad614SDennis Dalessandro spin_unlock_irqrestore(&curr_sde->tail_lock, flags);
492f48ad614SDennis Dalessandro continue;
493f48ad614SDennis Dalessandro }
494f48ad614SDennis Dalessandro
495f48ad614SDennis Dalessandro if ((curr_sde->descq_head != curr_sde->descq_tail) &&
496f48ad614SDennis Dalessandro (curr_sde->descq_head ==
497f48ad614SDennis Dalessandro curr_sde->progress_check_head))
498f48ad614SDennis Dalessandro __sdma_process_event(curr_sde,
499f48ad614SDennis Dalessandro sdma_event_e90_sw_halted);
500f48ad614SDennis Dalessandro write_sequnlock(&curr_sde->head_lock);
501f48ad614SDennis Dalessandro spin_unlock_irqrestore(&curr_sde->tail_lock, flags);
502f48ad614SDennis Dalessandro }
503f48ad614SDennis Dalessandro schedule_work(&sde->err_halt_worker);
504f48ad614SDennis Dalessandro }
505f48ad614SDennis Dalessandro
sdma_hw_clean_up_task(struct tasklet_struct * t)50655db47d0SAllen Pais static void sdma_hw_clean_up_task(struct tasklet_struct *t)
507f48ad614SDennis Dalessandro {
50855db47d0SAllen Pais struct sdma_engine *sde = from_tasklet(sde, t,
50955db47d0SAllen Pais sdma_hw_clean_up_task);
510f48ad614SDennis Dalessandro u64 statuscsr;
511f48ad614SDennis Dalessandro
512f48ad614SDennis Dalessandro while (1) {
513f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
514f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n",
515f48ad614SDennis Dalessandro sde->this_idx, slashstrip(__FILE__), __LINE__,
516f48ad614SDennis Dalessandro __func__);
517f48ad614SDennis Dalessandro #endif
518f48ad614SDennis Dalessandro statuscsr = read_sde_csr(sde, SD(STATUS));
519f48ad614SDennis Dalessandro statuscsr &= SD(STATUS_ENG_CLEANED_UP_SMASK);
520f48ad614SDennis Dalessandro if (statuscsr)
521f48ad614SDennis Dalessandro break;
522f48ad614SDennis Dalessandro udelay(10);
523f48ad614SDennis Dalessandro }
524f48ad614SDennis Dalessandro
525f48ad614SDennis Dalessandro sdma_process_event(sde, sdma_event_e25_hw_clean_up_done);
526f48ad614SDennis Dalessandro }
527f48ad614SDennis Dalessandro
get_txhead(struct sdma_engine * sde)528f48ad614SDennis Dalessandro static inline struct sdma_txreq *get_txhead(struct sdma_engine *sde)
529f48ad614SDennis Dalessandro {
530f48ad614SDennis Dalessandro return sde->tx_ring[sde->tx_head & sde->sdma_mask];
531f48ad614SDennis Dalessandro }
532f48ad614SDennis Dalessandro
533f48ad614SDennis Dalessandro /*
534f48ad614SDennis Dalessandro * flush ring for recovery
535f48ad614SDennis Dalessandro */
sdma_flush_descq(struct sdma_engine * sde)536f48ad614SDennis Dalessandro static void sdma_flush_descq(struct sdma_engine *sde)
537f48ad614SDennis Dalessandro {
538f48ad614SDennis Dalessandro u16 head, tail;
539f48ad614SDennis Dalessandro int progress = 0;
540f48ad614SDennis Dalessandro struct sdma_txreq *txp = get_txhead(sde);
541f48ad614SDennis Dalessandro
542f48ad614SDennis Dalessandro /* The reason for some of the complexity of this code is that
543f48ad614SDennis Dalessandro * not all descriptors have corresponding txps. So, we have to
544f48ad614SDennis Dalessandro * be able to skip over descs until we wander into the range of
545f48ad614SDennis Dalessandro * the next txp on the list.
546f48ad614SDennis Dalessandro */
547f48ad614SDennis Dalessandro head = sde->descq_head & sde->sdma_mask;
548f48ad614SDennis Dalessandro tail = sde->descq_tail & sde->sdma_mask;
549f48ad614SDennis Dalessandro while (head != tail) {
550f48ad614SDennis Dalessandro /* advance head, wrap if needed */
551f48ad614SDennis Dalessandro head = ++sde->descq_head & sde->sdma_mask;
552f48ad614SDennis Dalessandro /* if now past this txp's descs, do the callback */
553f48ad614SDennis Dalessandro if (txp && txp->next_descq_idx == head) {
554f48ad614SDennis Dalessandro /* remove from list */
555f48ad614SDennis Dalessandro sde->tx_ring[sde->tx_head++ & sde->sdma_mask] = NULL;
556f48ad614SDennis Dalessandro complete_tx(sde, txp, SDMA_TXREQ_S_ABORTED);
557f48ad614SDennis Dalessandro trace_hfi1_sdma_progress(sde, head, tail, txp);
558f48ad614SDennis Dalessandro txp = get_txhead(sde);
559f48ad614SDennis Dalessandro }
560f48ad614SDennis Dalessandro progress++;
561f48ad614SDennis Dalessandro }
562f48ad614SDennis Dalessandro if (progress)
563f48ad614SDennis Dalessandro sdma_desc_avail(sde, sdma_descq_freecnt(sde));
564f48ad614SDennis Dalessandro }
565f48ad614SDennis Dalessandro
sdma_sw_clean_up_task(struct tasklet_struct * t)56655db47d0SAllen Pais static void sdma_sw_clean_up_task(struct tasklet_struct *t)
567f48ad614SDennis Dalessandro {
56855db47d0SAllen Pais struct sdma_engine *sde = from_tasklet(sde, t, sdma_sw_clean_up_task);
569f48ad614SDennis Dalessandro unsigned long flags;
570f48ad614SDennis Dalessandro
571f48ad614SDennis Dalessandro spin_lock_irqsave(&sde->tail_lock, flags);
572f48ad614SDennis Dalessandro write_seqlock(&sde->head_lock);
573f48ad614SDennis Dalessandro
574f48ad614SDennis Dalessandro /*
575f48ad614SDennis Dalessandro * At this point, the following should always be true:
576f48ad614SDennis Dalessandro * - We are halted, so no more descriptors are getting retired.
577f48ad614SDennis Dalessandro * - We are not running, so no one is submitting new work.
578f48ad614SDennis Dalessandro * - Only we can send the e40_sw_cleaned, so we can't start
579f48ad614SDennis Dalessandro * running again until we say so. So, the active list and
580f48ad614SDennis Dalessandro * descq are ours to play with.
581f48ad614SDennis Dalessandro */
582f48ad614SDennis Dalessandro
583f48ad614SDennis Dalessandro /*
584f48ad614SDennis Dalessandro * In the error clean up sequence, software clean must be called
585f48ad614SDennis Dalessandro * before the hardware clean so we can use the hardware head in
586f48ad614SDennis Dalessandro * the progress routine. A hardware clean or SPC unfreeze will
587f48ad614SDennis Dalessandro * reset the hardware head.
588f48ad614SDennis Dalessandro *
589f48ad614SDennis Dalessandro * Process all retired requests. The progress routine will use the
590f48ad614SDennis Dalessandro * latest physical hardware head - we are not running so speed does
591f48ad614SDennis Dalessandro * not matter.
592f48ad614SDennis Dalessandro */
593f48ad614SDennis Dalessandro sdma_make_progress(sde, 0);
594f48ad614SDennis Dalessandro
595f48ad614SDennis Dalessandro sdma_flush(sde);
596f48ad614SDennis Dalessandro
597f48ad614SDennis Dalessandro /*
598f48ad614SDennis Dalessandro * Reset our notion of head and tail.
599f48ad614SDennis Dalessandro * Note that the HW registers have been reset via an earlier
600f48ad614SDennis Dalessandro * clean up.
601f48ad614SDennis Dalessandro */
602f48ad614SDennis Dalessandro sde->descq_tail = 0;
603f48ad614SDennis Dalessandro sde->descq_head = 0;
604f48ad614SDennis Dalessandro sde->desc_avail = sdma_descq_freecnt(sde);
605f48ad614SDennis Dalessandro *sde->head_dma = 0;
606f48ad614SDennis Dalessandro
607f48ad614SDennis Dalessandro __sdma_process_event(sde, sdma_event_e40_sw_cleaned);
608f48ad614SDennis Dalessandro
609f48ad614SDennis Dalessandro write_sequnlock(&sde->head_lock);
610f48ad614SDennis Dalessandro spin_unlock_irqrestore(&sde->tail_lock, flags);
611f48ad614SDennis Dalessandro }
612f48ad614SDennis Dalessandro
sdma_sw_tear_down(struct sdma_engine * sde)613f48ad614SDennis Dalessandro static void sdma_sw_tear_down(struct sdma_engine *sde)
614f48ad614SDennis Dalessandro {
615f48ad614SDennis Dalessandro struct sdma_state *ss = &sde->state;
616f48ad614SDennis Dalessandro
617f48ad614SDennis Dalessandro /* Releasing this reference means the state machine has stopped. */
618f48ad614SDennis Dalessandro sdma_put(ss);
619f48ad614SDennis Dalessandro
620f48ad614SDennis Dalessandro /* stop waiting for all unfreeze events to complete */
621f48ad614SDennis Dalessandro atomic_set(&sde->dd->sdma_unfreeze_count, -1);
622f48ad614SDennis Dalessandro wake_up_interruptible(&sde->dd->sdma_unfreeze_wq);
623f48ad614SDennis Dalessandro }
624f48ad614SDennis Dalessandro
sdma_start_hw_clean_up(struct sdma_engine * sde)625f48ad614SDennis Dalessandro static void sdma_start_hw_clean_up(struct sdma_engine *sde)
626f48ad614SDennis Dalessandro {
627f48ad614SDennis Dalessandro tasklet_hi_schedule(&sde->sdma_hw_clean_up_task);
628f48ad614SDennis Dalessandro }
629f48ad614SDennis Dalessandro
sdma_set_state(struct sdma_engine * sde,enum sdma_states next_state)630f48ad614SDennis Dalessandro static void sdma_set_state(struct sdma_engine *sde,
631f48ad614SDennis Dalessandro enum sdma_states next_state)
632f48ad614SDennis Dalessandro {
633f48ad614SDennis Dalessandro struct sdma_state *ss = &sde->state;
634f48ad614SDennis Dalessandro const struct sdma_set_state_action *action = sdma_action_table;
635f48ad614SDennis Dalessandro unsigned op = 0;
636f48ad614SDennis Dalessandro
637f48ad614SDennis Dalessandro trace_hfi1_sdma_state(
638f48ad614SDennis Dalessandro sde,
639f48ad614SDennis Dalessandro sdma_state_names[ss->current_state],
640f48ad614SDennis Dalessandro sdma_state_names[next_state]);
641f48ad614SDennis Dalessandro
642f48ad614SDennis Dalessandro /* debugging bookkeeping */
643f48ad614SDennis Dalessandro ss->previous_state = ss->current_state;
644f48ad614SDennis Dalessandro ss->previous_op = ss->current_op;
645f48ad614SDennis Dalessandro ss->current_state = next_state;
646f48ad614SDennis Dalessandro
647f48ad614SDennis Dalessandro if (ss->previous_state != sdma_state_s99_running &&
648f48ad614SDennis Dalessandro next_state == sdma_state_s99_running)
649f48ad614SDennis Dalessandro sdma_flush(sde);
650f48ad614SDennis Dalessandro
651f48ad614SDennis Dalessandro if (action[next_state].op_enable)
652f48ad614SDennis Dalessandro op |= SDMA_SENDCTRL_OP_ENABLE;
653f48ad614SDennis Dalessandro
654f48ad614SDennis Dalessandro if (action[next_state].op_intenable)
655f48ad614SDennis Dalessandro op |= SDMA_SENDCTRL_OP_INTENABLE;
656f48ad614SDennis Dalessandro
657f48ad614SDennis Dalessandro if (action[next_state].op_halt)
658f48ad614SDennis Dalessandro op |= SDMA_SENDCTRL_OP_HALT;
659f48ad614SDennis Dalessandro
660f48ad614SDennis Dalessandro if (action[next_state].op_cleanup)
661f48ad614SDennis Dalessandro op |= SDMA_SENDCTRL_OP_CLEANUP;
662f48ad614SDennis Dalessandro
663f48ad614SDennis Dalessandro if (action[next_state].go_s99_running_tofalse)
664f48ad614SDennis Dalessandro ss->go_s99_running = 0;
665f48ad614SDennis Dalessandro
666f48ad614SDennis Dalessandro if (action[next_state].go_s99_running_totrue)
667f48ad614SDennis Dalessandro ss->go_s99_running = 1;
668f48ad614SDennis Dalessandro
669f48ad614SDennis Dalessandro ss->current_op = op;
670f48ad614SDennis Dalessandro sdma_sendctrl(sde, ss->current_op);
671f48ad614SDennis Dalessandro }
672f48ad614SDennis Dalessandro
673f48ad614SDennis Dalessandro /**
674f48ad614SDennis Dalessandro * sdma_get_descq_cnt() - called when device probed
675f48ad614SDennis Dalessandro *
676f48ad614SDennis Dalessandro * Return a validated descq count.
677f48ad614SDennis Dalessandro *
678f48ad614SDennis Dalessandro * This is currently only used in the verbs initialization to build the tx
679f48ad614SDennis Dalessandro * list.
680f48ad614SDennis Dalessandro *
681f48ad614SDennis Dalessandro * This will probably be deleted in favor of a more scalable approach to
682f48ad614SDennis Dalessandro * alloc tx's.
683f48ad614SDennis Dalessandro *
684f48ad614SDennis Dalessandro */
sdma_get_descq_cnt(void)685f48ad614SDennis Dalessandro u16 sdma_get_descq_cnt(void)
686f48ad614SDennis Dalessandro {
687f48ad614SDennis Dalessandro u16 count = sdma_descq_cnt;
688f48ad614SDennis Dalessandro
689f48ad614SDennis Dalessandro if (!count)
690f48ad614SDennis Dalessandro return SDMA_DESCQ_CNT;
691f48ad614SDennis Dalessandro /* count must be a power of 2 greater than 64 and less than
692f48ad614SDennis Dalessandro * 32768. Otherwise return default.
693f48ad614SDennis Dalessandro */
694f48ad614SDennis Dalessandro if (!is_power_of_2(count))
695f48ad614SDennis Dalessandro return SDMA_DESCQ_CNT;
696f48ad614SDennis Dalessandro if (count < 64 || count > 32768)
697f48ad614SDennis Dalessandro return SDMA_DESCQ_CNT;
698f48ad614SDennis Dalessandro return count;
699f48ad614SDennis Dalessandro }
700f48ad614SDennis Dalessandro
701f48ad614SDennis Dalessandro /**
7020cb2aa69STadeusz Struk * sdma_engine_get_vl() - return vl for a given sdma engine
7030cb2aa69STadeusz Struk * @sde: sdma engine
7040cb2aa69STadeusz Struk *
7050cb2aa69STadeusz Struk * This function returns the vl mapped to a given engine, or an error if
7060cb2aa69STadeusz Struk * the mapping can't be found. The mapping fields are protected by RCU.
7070cb2aa69STadeusz Struk */
sdma_engine_get_vl(struct sdma_engine * sde)7080cb2aa69STadeusz Struk int sdma_engine_get_vl(struct sdma_engine *sde)
7090cb2aa69STadeusz Struk {
7100cb2aa69STadeusz Struk struct hfi1_devdata *dd = sde->dd;
7110cb2aa69STadeusz Struk struct sdma_vl_map *m;
7120cb2aa69STadeusz Struk u8 vl;
7130cb2aa69STadeusz Struk
7140cb2aa69STadeusz Struk if (sde->this_idx >= TXE_NUM_SDMA_ENGINES)
7150cb2aa69STadeusz Struk return -EINVAL;
7160cb2aa69STadeusz Struk
7170cb2aa69STadeusz Struk rcu_read_lock();
7180cb2aa69STadeusz Struk m = rcu_dereference(dd->sdma_map);
7190cb2aa69STadeusz Struk if (unlikely(!m)) {
7200cb2aa69STadeusz Struk rcu_read_unlock();
7210cb2aa69STadeusz Struk return -EINVAL;
7220cb2aa69STadeusz Struk }
7230cb2aa69STadeusz Struk vl = m->engine_to_vl[sde->this_idx];
7240cb2aa69STadeusz Struk rcu_read_unlock();
7250cb2aa69STadeusz Struk
7260cb2aa69STadeusz Struk return vl;
7270cb2aa69STadeusz Struk }
7280cb2aa69STadeusz Struk
7290cb2aa69STadeusz Struk /**
730f48ad614SDennis Dalessandro * sdma_select_engine_vl() - select sdma engine
731f48ad614SDennis Dalessandro * @dd: devdata
732f48ad614SDennis Dalessandro * @selector: a spreading factor
733f48ad614SDennis Dalessandro * @vl: this vl
734f48ad614SDennis Dalessandro *
735f48ad614SDennis Dalessandro *
736f48ad614SDennis Dalessandro * This function returns an engine based on the selector and a vl. The
737f48ad614SDennis Dalessandro * mapping fields are protected by RCU.
738f48ad614SDennis Dalessandro */
sdma_select_engine_vl(struct hfi1_devdata * dd,u32 selector,u8 vl)739f48ad614SDennis Dalessandro struct sdma_engine *sdma_select_engine_vl(
740f48ad614SDennis Dalessandro struct hfi1_devdata *dd,
741f48ad614SDennis Dalessandro u32 selector,
742f48ad614SDennis Dalessandro u8 vl)
743f48ad614SDennis Dalessandro {
744f48ad614SDennis Dalessandro struct sdma_vl_map *m;
745f48ad614SDennis Dalessandro struct sdma_map_elem *e;
746f48ad614SDennis Dalessandro struct sdma_engine *rval;
747f48ad614SDennis Dalessandro
748f48ad614SDennis Dalessandro /* NOTE This should only happen if SC->VL changed after the initial
749f48ad614SDennis Dalessandro * checks on the QP/AH
750f48ad614SDennis Dalessandro * Default will return engine 0 below
751f48ad614SDennis Dalessandro */
752f48ad614SDennis Dalessandro if (vl >= num_vls) {
753f48ad614SDennis Dalessandro rval = NULL;
754f48ad614SDennis Dalessandro goto done;
755f48ad614SDennis Dalessandro }
756f48ad614SDennis Dalessandro
757f48ad614SDennis Dalessandro rcu_read_lock();
758f48ad614SDennis Dalessandro m = rcu_dereference(dd->sdma_map);
759f48ad614SDennis Dalessandro if (unlikely(!m)) {
760f48ad614SDennis Dalessandro rcu_read_unlock();
761f48ad614SDennis Dalessandro return &dd->per_sdma[0];
762f48ad614SDennis Dalessandro }
763f48ad614SDennis Dalessandro e = m->map[vl & m->mask];
764f48ad614SDennis Dalessandro rval = e->sde[selector & e->mask];
765f48ad614SDennis Dalessandro rcu_read_unlock();
766f48ad614SDennis Dalessandro
767f48ad614SDennis Dalessandro done:
768f48ad614SDennis Dalessandro rval = !rval ? &dd->per_sdma[0] : rval;
769f48ad614SDennis Dalessandro trace_hfi1_sdma_engine_select(dd, selector, vl, rval->this_idx);
770f48ad614SDennis Dalessandro return rval;
771f48ad614SDennis Dalessandro }
772f48ad614SDennis Dalessandro
773f48ad614SDennis Dalessandro /**
774f48ad614SDennis Dalessandro * sdma_select_engine_sc() - select sdma engine
775f48ad614SDennis Dalessandro * @dd: devdata
776f48ad614SDennis Dalessandro * @selector: a spreading factor
777f48ad614SDennis Dalessandro * @sc5: the 5 bit sc
778f48ad614SDennis Dalessandro *
779f48ad614SDennis Dalessandro *
780f48ad614SDennis Dalessandro * This function returns an engine based on the selector and an sc.
781f48ad614SDennis Dalessandro */
sdma_select_engine_sc(struct hfi1_devdata * dd,u32 selector,u8 sc5)782f48ad614SDennis Dalessandro struct sdma_engine *sdma_select_engine_sc(
783f48ad614SDennis Dalessandro struct hfi1_devdata *dd,
784f48ad614SDennis Dalessandro u32 selector,
785f48ad614SDennis Dalessandro u8 sc5)
786f48ad614SDennis Dalessandro {
787f48ad614SDennis Dalessandro u8 vl = sc_to_vlt(dd, sc5);
788f48ad614SDennis Dalessandro
789f48ad614SDennis Dalessandro return sdma_select_engine_vl(dd, selector, vl);
790f48ad614SDennis Dalessandro }
791f48ad614SDennis Dalessandro
7920cb2aa69STadeusz Struk struct sdma_rht_map_elem {
7930cb2aa69STadeusz Struk u32 mask;
7940cb2aa69STadeusz Struk u8 ctr;
7955b361328SGustavo A. R. Silva struct sdma_engine *sde[];
7960cb2aa69STadeusz Struk };
7970cb2aa69STadeusz Struk
7980cb2aa69STadeusz Struk struct sdma_rht_node {
7990cb2aa69STadeusz Struk unsigned long cpu_id;
8000cb2aa69STadeusz Struk struct sdma_rht_map_elem *map[HFI1_MAX_VLS_SUPPORTED];
8010cb2aa69STadeusz Struk struct rhash_head node;
8020cb2aa69STadeusz Struk };
8030cb2aa69STadeusz Struk
8040cb2aa69STadeusz Struk #define NR_CPUS_HINT 192
8050cb2aa69STadeusz Struk
8060cb2aa69STadeusz Struk static const struct rhashtable_params sdma_rht_params = {
8070cb2aa69STadeusz Struk .nelem_hint = NR_CPUS_HINT,
8080cb2aa69STadeusz Struk .head_offset = offsetof(struct sdma_rht_node, node),
8090cb2aa69STadeusz Struk .key_offset = offsetof(struct sdma_rht_node, cpu_id),
810c593642cSPankaj Bharadiya .key_len = sizeof_field(struct sdma_rht_node, cpu_id),
8110cb2aa69STadeusz Struk .max_size = NR_CPUS,
8120cb2aa69STadeusz Struk .min_size = 8,
8130cb2aa69STadeusz Struk .automatic_shrinking = true,
8140cb2aa69STadeusz Struk };
8150cb2aa69STadeusz Struk
8160cb2aa69STadeusz Struk /*
8170cb2aa69STadeusz Struk * sdma_select_user_engine() - select sdma engine based on user setup
8180cb2aa69STadeusz Struk * @dd: devdata
8190cb2aa69STadeusz Struk * @selector: a spreading factor
8200cb2aa69STadeusz Struk * @vl: this vl
8210cb2aa69STadeusz Struk *
8220cb2aa69STadeusz Struk * This function returns an sdma engine for a user sdma request.
8230cb2aa69STadeusz Struk * User defined sdma engine affinity setting is honored when applicable,
8240cb2aa69STadeusz Struk * otherwise system default sdma engine mapping is used. To ensure correct
8250cb2aa69STadeusz Struk * ordering, the mapping from <selector, vl> to sde must remain unchanged.
8260cb2aa69STadeusz Struk */
sdma_select_user_engine(struct hfi1_devdata * dd,u32 selector,u8 vl)8270cb2aa69STadeusz Struk struct sdma_engine *sdma_select_user_engine(struct hfi1_devdata *dd,
8280cb2aa69STadeusz Struk u32 selector, u8 vl)
8290cb2aa69STadeusz Struk {
8300cb2aa69STadeusz Struk struct sdma_rht_node *rht_node;
8310cb2aa69STadeusz Struk struct sdma_engine *sde = NULL;
8320cb2aa69STadeusz Struk unsigned long cpu_id;
8330cb2aa69STadeusz Struk
8340cb2aa69STadeusz Struk /*
8350cb2aa69STadeusz Struk * To ensure that always the same sdma engine(s) will be
8360cb2aa69STadeusz Struk * selected make sure the process is pinned to this CPU only.
8370cb2aa69STadeusz Struk */
8383bd37062SSebastian Andrzej Siewior if (current->nr_cpus_allowed != 1)
8390cb2aa69STadeusz Struk goto out;
8400cb2aa69STadeusz Struk
8410cb2aa69STadeusz Struk rcu_read_lock();
842b6d57e24SMike Marciniszyn cpu_id = smp_processor_id();
843ab818362STaehee Yoo rht_node = rhashtable_lookup(dd->sdma_rht, &cpu_id,
8440cb2aa69STadeusz Struk sdma_rht_params);
8450cb2aa69STadeusz Struk
8460cb2aa69STadeusz Struk if (rht_node && rht_node->map[vl]) {
8470cb2aa69STadeusz Struk struct sdma_rht_map_elem *map = rht_node->map[vl];
8480cb2aa69STadeusz Struk
8490cb2aa69STadeusz Struk sde = map->sde[selector & map->mask];
8500cb2aa69STadeusz Struk }
8510cb2aa69STadeusz Struk rcu_read_unlock();
8520cb2aa69STadeusz Struk
8530cb2aa69STadeusz Struk if (sde)
8540cb2aa69STadeusz Struk return sde;
8550cb2aa69STadeusz Struk
8560cb2aa69STadeusz Struk out:
8570cb2aa69STadeusz Struk return sdma_select_engine_vl(dd, selector, vl);
8580cb2aa69STadeusz Struk }
8590cb2aa69STadeusz Struk
sdma_populate_sde_map(struct sdma_rht_map_elem * map)8600cb2aa69STadeusz Struk static void sdma_populate_sde_map(struct sdma_rht_map_elem *map)
8610cb2aa69STadeusz Struk {
8620cb2aa69STadeusz Struk int i;
8630cb2aa69STadeusz Struk
8640cb2aa69STadeusz Struk for (i = 0; i < roundup_pow_of_two(map->ctr ? : 1) - map->ctr; i++)
8650cb2aa69STadeusz Struk map->sde[map->ctr + i] = map->sde[i];
8660cb2aa69STadeusz Struk }
8670cb2aa69STadeusz Struk
sdma_cleanup_sde_map(struct sdma_rht_map_elem * map,struct sdma_engine * sde)8680cb2aa69STadeusz Struk static void sdma_cleanup_sde_map(struct sdma_rht_map_elem *map,
8690cb2aa69STadeusz Struk struct sdma_engine *sde)
8700cb2aa69STadeusz Struk {
8710cb2aa69STadeusz Struk unsigned int i, pow;
8720cb2aa69STadeusz Struk
8730cb2aa69STadeusz Struk /* only need to check the first ctr entries for a match */
8740cb2aa69STadeusz Struk for (i = 0; i < map->ctr; i++) {
8750cb2aa69STadeusz Struk if (map->sde[i] == sde) {
8760cb2aa69STadeusz Struk memmove(&map->sde[i], &map->sde[i + 1],
8770cb2aa69STadeusz Struk (map->ctr - i - 1) * sizeof(map->sde[0]));
8780cb2aa69STadeusz Struk map->ctr--;
8790cb2aa69STadeusz Struk pow = roundup_pow_of_two(map->ctr ? : 1);
8800cb2aa69STadeusz Struk map->mask = pow - 1;
8810cb2aa69STadeusz Struk sdma_populate_sde_map(map);
8820cb2aa69STadeusz Struk break;
8830cb2aa69STadeusz Struk }
8840cb2aa69STadeusz Struk }
8850cb2aa69STadeusz Struk }
8860cb2aa69STadeusz Struk
8870cb2aa69STadeusz Struk /*
8880cb2aa69STadeusz Struk * Prevents concurrent reads and writes of the sdma engine cpu_mask
8890cb2aa69STadeusz Struk */
8900cb2aa69STadeusz Struk static DEFINE_MUTEX(process_to_sde_mutex);
8910cb2aa69STadeusz Struk
sdma_set_cpu_to_sde_map(struct sdma_engine * sde,const char * buf,size_t count)8920cb2aa69STadeusz Struk ssize_t sdma_set_cpu_to_sde_map(struct sdma_engine *sde, const char *buf,
8930cb2aa69STadeusz Struk size_t count)
8940cb2aa69STadeusz Struk {
8950cb2aa69STadeusz Struk struct hfi1_devdata *dd = sde->dd;
8960cb2aa69STadeusz Struk cpumask_var_t mask, new_mask;
8970cb2aa69STadeusz Struk unsigned long cpu;
8980cb2aa69STadeusz Struk int ret, vl, sz;
899f9458bc2SKaike Wan struct sdma_rht_node *rht_node;
9000cb2aa69STadeusz Struk
9010cb2aa69STadeusz Struk vl = sdma_engine_get_vl(sde);
902f9458bc2SKaike Wan if (unlikely(vl < 0 || vl >= ARRAY_SIZE(rht_node->map)))
9030cb2aa69STadeusz Struk return -EINVAL;
9040cb2aa69STadeusz Struk
9050cb2aa69STadeusz Struk ret = zalloc_cpumask_var(&mask, GFP_KERNEL);
9060cb2aa69STadeusz Struk if (!ret)
9070cb2aa69STadeusz Struk return -ENOMEM;
9080cb2aa69STadeusz Struk
9090cb2aa69STadeusz Struk ret = zalloc_cpumask_var(&new_mask, GFP_KERNEL);
9100cb2aa69STadeusz Struk if (!ret) {
9110cb2aa69STadeusz Struk free_cpumask_var(mask);
9120cb2aa69STadeusz Struk return -ENOMEM;
9130cb2aa69STadeusz Struk }
9140cb2aa69STadeusz Struk ret = cpulist_parse(buf, mask);
9150cb2aa69STadeusz Struk if (ret)
9160cb2aa69STadeusz Struk goto out_free;
9170cb2aa69STadeusz Struk
9180cb2aa69STadeusz Struk if (!cpumask_subset(mask, cpu_online_mask)) {
9190cb2aa69STadeusz Struk dd_dev_warn(sde->dd, "Invalid CPU mask\n");
9200cb2aa69STadeusz Struk ret = -EINVAL;
9210cb2aa69STadeusz Struk goto out_free;
9220cb2aa69STadeusz Struk }
9230cb2aa69STadeusz Struk
9240cb2aa69STadeusz Struk sz = sizeof(struct sdma_rht_map_elem) +
9250cb2aa69STadeusz Struk (TXE_NUM_SDMA_ENGINES * sizeof(struct sdma_engine *));
9260cb2aa69STadeusz Struk
9270cb2aa69STadeusz Struk mutex_lock(&process_to_sde_mutex);
9280cb2aa69STadeusz Struk
9290cb2aa69STadeusz Struk for_each_cpu(cpu, mask) {
9300cb2aa69STadeusz Struk /* Check if we have this already mapped */
9310cb2aa69STadeusz Struk if (cpumask_test_cpu(cpu, &sde->cpu_mask)) {
9320cb2aa69STadeusz Struk cpumask_set_cpu(cpu, new_mask);
9330cb2aa69STadeusz Struk continue;
9340cb2aa69STadeusz Struk }
9350cb2aa69STadeusz Struk
9365a52a7acSSebastian Sanchez rht_node = rhashtable_lookup_fast(dd->sdma_rht, &cpu,
9370cb2aa69STadeusz Struk sdma_rht_params);
9380cb2aa69STadeusz Struk if (!rht_node) {
9390cb2aa69STadeusz Struk rht_node = kzalloc(sizeof(*rht_node), GFP_KERNEL);
9400cb2aa69STadeusz Struk if (!rht_node) {
9410cb2aa69STadeusz Struk ret = -ENOMEM;
9420cb2aa69STadeusz Struk goto out;
9430cb2aa69STadeusz Struk }
9440cb2aa69STadeusz Struk
9450cb2aa69STadeusz Struk rht_node->map[vl] = kzalloc(sz, GFP_KERNEL);
9460cb2aa69STadeusz Struk if (!rht_node->map[vl]) {
9470cb2aa69STadeusz Struk kfree(rht_node);
9480cb2aa69STadeusz Struk ret = -ENOMEM;
9490cb2aa69STadeusz Struk goto out;
9500cb2aa69STadeusz Struk }
9510cb2aa69STadeusz Struk rht_node->cpu_id = cpu;
9520cb2aa69STadeusz Struk rht_node->map[vl]->mask = 0;
9530cb2aa69STadeusz Struk rht_node->map[vl]->ctr = 1;
9540cb2aa69STadeusz Struk rht_node->map[vl]->sde[0] = sde;
9550cb2aa69STadeusz Struk
9565a52a7acSSebastian Sanchez ret = rhashtable_insert_fast(dd->sdma_rht,
9570cb2aa69STadeusz Struk &rht_node->node,
9580cb2aa69STadeusz Struk sdma_rht_params);
9590cb2aa69STadeusz Struk if (ret) {
9600cb2aa69STadeusz Struk kfree(rht_node->map[vl]);
9610cb2aa69STadeusz Struk kfree(rht_node);
9620cb2aa69STadeusz Struk dd_dev_err(sde->dd, "Failed to set process to sde affinity for cpu %lu\n",
9630cb2aa69STadeusz Struk cpu);
9640cb2aa69STadeusz Struk goto out;
9650cb2aa69STadeusz Struk }
9660cb2aa69STadeusz Struk
9670cb2aa69STadeusz Struk } else {
9680cb2aa69STadeusz Struk int ctr, pow;
9690cb2aa69STadeusz Struk
9700cb2aa69STadeusz Struk /* Add new user mappings */
9710cb2aa69STadeusz Struk if (!rht_node->map[vl])
9720cb2aa69STadeusz Struk rht_node->map[vl] = kzalloc(sz, GFP_KERNEL);
9730cb2aa69STadeusz Struk
9740cb2aa69STadeusz Struk if (!rht_node->map[vl]) {
9750cb2aa69STadeusz Struk ret = -ENOMEM;
9760cb2aa69STadeusz Struk goto out;
9770cb2aa69STadeusz Struk }
9780cb2aa69STadeusz Struk
9790cb2aa69STadeusz Struk rht_node->map[vl]->ctr++;
9800cb2aa69STadeusz Struk ctr = rht_node->map[vl]->ctr;
9810cb2aa69STadeusz Struk rht_node->map[vl]->sde[ctr - 1] = sde;
9820cb2aa69STadeusz Struk pow = roundup_pow_of_two(ctr);
9830cb2aa69STadeusz Struk rht_node->map[vl]->mask = pow - 1;
9840cb2aa69STadeusz Struk
9850cb2aa69STadeusz Struk /* Populate the sde map table */
9860cb2aa69STadeusz Struk sdma_populate_sde_map(rht_node->map[vl]);
9870cb2aa69STadeusz Struk }
9880cb2aa69STadeusz Struk cpumask_set_cpu(cpu, new_mask);
9890cb2aa69STadeusz Struk }
9900cb2aa69STadeusz Struk
9910cb2aa69STadeusz Struk /* Clean up old mappings */
9920cb2aa69STadeusz Struk for_each_cpu(cpu, cpu_online_mask) {
9930cb2aa69STadeusz Struk struct sdma_rht_node *rht_node;
9940cb2aa69STadeusz Struk
9950cb2aa69STadeusz Struk /* Don't cleanup sdes that are set in the new mask */
9960cb2aa69STadeusz Struk if (cpumask_test_cpu(cpu, mask))
9970cb2aa69STadeusz Struk continue;
9980cb2aa69STadeusz Struk
9995a52a7acSSebastian Sanchez rht_node = rhashtable_lookup_fast(dd->sdma_rht, &cpu,
10000cb2aa69STadeusz Struk sdma_rht_params);
10010cb2aa69STadeusz Struk if (rht_node) {
10020cb2aa69STadeusz Struk bool empty = true;
10030cb2aa69STadeusz Struk int i;
10040cb2aa69STadeusz Struk
10050cb2aa69STadeusz Struk /* Remove mappings for old sde */
10060cb2aa69STadeusz Struk for (i = 0; i < HFI1_MAX_VLS_SUPPORTED; i++)
10070cb2aa69STadeusz Struk if (rht_node->map[i])
10080cb2aa69STadeusz Struk sdma_cleanup_sde_map(rht_node->map[i],
10090cb2aa69STadeusz Struk sde);
10100cb2aa69STadeusz Struk
10110cb2aa69STadeusz Struk /* Free empty hash table entries */
10120cb2aa69STadeusz Struk for (i = 0; i < HFI1_MAX_VLS_SUPPORTED; i++) {
10130cb2aa69STadeusz Struk if (!rht_node->map[i])
10140cb2aa69STadeusz Struk continue;
10150cb2aa69STadeusz Struk
10160cb2aa69STadeusz Struk if (rht_node->map[i]->ctr) {
10170cb2aa69STadeusz Struk empty = false;
10180cb2aa69STadeusz Struk break;
10190cb2aa69STadeusz Struk }
10200cb2aa69STadeusz Struk }
10210cb2aa69STadeusz Struk
10220cb2aa69STadeusz Struk if (empty) {
10235a52a7acSSebastian Sanchez ret = rhashtable_remove_fast(dd->sdma_rht,
10240cb2aa69STadeusz Struk &rht_node->node,
10250cb2aa69STadeusz Struk sdma_rht_params);
10260cb2aa69STadeusz Struk WARN_ON(ret);
10270cb2aa69STadeusz Struk
10280cb2aa69STadeusz Struk for (i = 0; i < HFI1_MAX_VLS_SUPPORTED; i++)
10290cb2aa69STadeusz Struk kfree(rht_node->map[i]);
10300cb2aa69STadeusz Struk
10310cb2aa69STadeusz Struk kfree(rht_node);
10320cb2aa69STadeusz Struk }
10330cb2aa69STadeusz Struk }
10340cb2aa69STadeusz Struk }
10350cb2aa69STadeusz Struk
10360cb2aa69STadeusz Struk cpumask_copy(&sde->cpu_mask, new_mask);
10370cb2aa69STadeusz Struk out:
10380cb2aa69STadeusz Struk mutex_unlock(&process_to_sde_mutex);
10390cb2aa69STadeusz Struk out_free:
10400cb2aa69STadeusz Struk free_cpumask_var(mask);
10410cb2aa69STadeusz Struk free_cpumask_var(new_mask);
10420cb2aa69STadeusz Struk return ret ? : strnlen(buf, PAGE_SIZE);
10430cb2aa69STadeusz Struk }
10440cb2aa69STadeusz Struk
sdma_get_cpu_to_sde_map(struct sdma_engine * sde,char * buf)10450cb2aa69STadeusz Struk ssize_t sdma_get_cpu_to_sde_map(struct sdma_engine *sde, char *buf)
10460cb2aa69STadeusz Struk {
10470cb2aa69STadeusz Struk mutex_lock(&process_to_sde_mutex);
10480cb2aa69STadeusz Struk if (cpumask_empty(&sde->cpu_mask))
10490cb2aa69STadeusz Struk snprintf(buf, PAGE_SIZE, "%s\n", "empty");
10500cb2aa69STadeusz Struk else
10510cb2aa69STadeusz Struk cpumap_print_to_pagebuf(true, buf, &sde->cpu_mask);
10520cb2aa69STadeusz Struk mutex_unlock(&process_to_sde_mutex);
10530cb2aa69STadeusz Struk return strnlen(buf, PAGE_SIZE);
10540cb2aa69STadeusz Struk }
10550cb2aa69STadeusz Struk
sdma_rht_free(void * ptr,void * arg)10560cb2aa69STadeusz Struk static void sdma_rht_free(void *ptr, void *arg)
10570cb2aa69STadeusz Struk {
10580cb2aa69STadeusz Struk struct sdma_rht_node *rht_node = ptr;
10590cb2aa69STadeusz Struk int i;
10600cb2aa69STadeusz Struk
10610cb2aa69STadeusz Struk for (i = 0; i < HFI1_MAX_VLS_SUPPORTED; i++)
10620cb2aa69STadeusz Struk kfree(rht_node->map[i]);
10630cb2aa69STadeusz Struk
10640cb2aa69STadeusz Struk kfree(rht_node);
10650cb2aa69STadeusz Struk }
10660cb2aa69STadeusz Struk
1067af3674d6STadeusz Struk /**
1068af3674d6STadeusz Struk * sdma_seqfile_dump_cpu_list() - debugfs dump the cpu to sdma mappings
1069af3674d6STadeusz Struk * @s: seq file
1070af3674d6STadeusz Struk * @dd: hfi1_devdata
1071af3674d6STadeusz Struk * @cpuid: cpu id
1072af3674d6STadeusz Struk *
1073af3674d6STadeusz Struk * This routine dumps the process to sde mappings per cpu
1074af3674d6STadeusz Struk */
sdma_seqfile_dump_cpu_list(struct seq_file * s,struct hfi1_devdata * dd,unsigned long cpuid)1075af3674d6STadeusz Struk void sdma_seqfile_dump_cpu_list(struct seq_file *s,
1076af3674d6STadeusz Struk struct hfi1_devdata *dd,
1077af3674d6STadeusz Struk unsigned long cpuid)
1078af3674d6STadeusz Struk {
1079af3674d6STadeusz Struk struct sdma_rht_node *rht_node;
1080af3674d6STadeusz Struk int i, j;
1081af3674d6STadeusz Struk
10825a52a7acSSebastian Sanchez rht_node = rhashtable_lookup_fast(dd->sdma_rht, &cpuid,
1083af3674d6STadeusz Struk sdma_rht_params);
1084af3674d6STadeusz Struk if (!rht_node)
1085af3674d6STadeusz Struk return;
1086af3674d6STadeusz Struk
1087af3674d6STadeusz Struk seq_printf(s, "cpu%3lu: ", cpuid);
1088af3674d6STadeusz Struk for (i = 0; i < HFI1_MAX_VLS_SUPPORTED; i++) {
1089af3674d6STadeusz Struk if (!rht_node->map[i] || !rht_node->map[i]->ctr)
1090af3674d6STadeusz Struk continue;
1091af3674d6STadeusz Struk
1092af3674d6STadeusz Struk seq_printf(s, " vl%d: [", i);
1093af3674d6STadeusz Struk
1094af3674d6STadeusz Struk for (j = 0; j < rht_node->map[i]->ctr; j++) {
1095af3674d6STadeusz Struk if (!rht_node->map[i]->sde[j])
1096af3674d6STadeusz Struk continue;
1097af3674d6STadeusz Struk
1098af3674d6STadeusz Struk if (j > 0)
1099af3674d6STadeusz Struk seq_puts(s, ",");
1100af3674d6STadeusz Struk
1101af3674d6STadeusz Struk seq_printf(s, " sdma%2d",
1102af3674d6STadeusz Struk rht_node->map[i]->sde[j]->this_idx);
1103af3674d6STadeusz Struk }
1104af3674d6STadeusz Struk seq_puts(s, " ]");
1105af3674d6STadeusz Struk }
1106af3674d6STadeusz Struk
1107af3674d6STadeusz Struk seq_puts(s, "\n");
1108af3674d6STadeusz Struk }
1109af3674d6STadeusz Struk
1110f48ad614SDennis Dalessandro /*
1111f48ad614SDennis Dalessandro * Free the indicated map struct
1112f48ad614SDennis Dalessandro */
sdma_map_free(struct sdma_vl_map * m)1113f48ad614SDennis Dalessandro static void sdma_map_free(struct sdma_vl_map *m)
1114f48ad614SDennis Dalessandro {
1115f48ad614SDennis Dalessandro int i;
1116f48ad614SDennis Dalessandro
1117f48ad614SDennis Dalessandro for (i = 0; m && i < m->actual_vls; i++)
1118f48ad614SDennis Dalessandro kfree(m->map[i]);
1119f48ad614SDennis Dalessandro kfree(m);
1120f48ad614SDennis Dalessandro }
1121f48ad614SDennis Dalessandro
1122f48ad614SDennis Dalessandro /*
1123f48ad614SDennis Dalessandro * Handle RCU callback
1124f48ad614SDennis Dalessandro */
sdma_map_rcu_callback(struct rcu_head * list)1125f48ad614SDennis Dalessandro static void sdma_map_rcu_callback(struct rcu_head *list)
1126f48ad614SDennis Dalessandro {
1127f48ad614SDennis Dalessandro struct sdma_vl_map *m = container_of(list, struct sdma_vl_map, list);
1128f48ad614SDennis Dalessandro
1129f48ad614SDennis Dalessandro sdma_map_free(m);
1130f48ad614SDennis Dalessandro }
1131f48ad614SDennis Dalessandro
1132f48ad614SDennis Dalessandro /**
1133f48ad614SDennis Dalessandro * sdma_map_init - called when # vls change
1134f48ad614SDennis Dalessandro * @dd: hfi1_devdata
1135f48ad614SDennis Dalessandro * @port: port number
1136f48ad614SDennis Dalessandro * @num_vls: number of vls
1137f48ad614SDennis Dalessandro * @vl_engines: per vl engine mapping (optional)
1138f48ad614SDennis Dalessandro *
1139f48ad614SDennis Dalessandro * This routine changes the mapping based on the number of vls.
1140f48ad614SDennis Dalessandro *
1141f48ad614SDennis Dalessandro * vl_engines is used to specify a non-uniform vl/engine loading. NULL
1142f48ad614SDennis Dalessandro * implies auto computing the loading and giving each VLs a uniform
1143f48ad614SDennis Dalessandro * distribution of engines per VL.
1144f48ad614SDennis Dalessandro *
1145f48ad614SDennis Dalessandro * The auto algorithm computes the sde_per_vl and the number of extra
1146f48ad614SDennis Dalessandro * engines. Any extra engines are added from the last VL on down.
1147f48ad614SDennis Dalessandro *
1148f48ad614SDennis Dalessandro * rcu locking is used here to control access to the mapping fields.
1149f48ad614SDennis Dalessandro *
1150f48ad614SDennis Dalessandro * If either the num_vls or num_sdma are non-power of 2, the array sizes
1151f48ad614SDennis Dalessandro * in the struct sdma_vl_map and the struct sdma_map_elem are rounded
1152f48ad614SDennis Dalessandro * up to the next highest power of 2 and the first entry is reused
1153f48ad614SDennis Dalessandro * in a round robin fashion.
1154f48ad614SDennis Dalessandro *
1155f48ad614SDennis Dalessandro * If an error occurs the map change is not done and the mapping is
1156f48ad614SDennis Dalessandro * not changed.
1157f48ad614SDennis Dalessandro *
1158f48ad614SDennis Dalessandro */
sdma_map_init(struct hfi1_devdata * dd,u8 port,u8 num_vls,u8 * vl_engines)1159f48ad614SDennis Dalessandro int sdma_map_init(struct hfi1_devdata *dd, u8 port, u8 num_vls, u8 *vl_engines)
1160f48ad614SDennis Dalessandro {
1161f48ad614SDennis Dalessandro int i, j;
1162f48ad614SDennis Dalessandro int extra, sde_per_vl;
1163f48ad614SDennis Dalessandro int engine = 0;
1164f48ad614SDennis Dalessandro u8 lvl_engines[OPA_MAX_VLS];
1165f48ad614SDennis Dalessandro struct sdma_vl_map *oldmap, *newmap;
1166f48ad614SDennis Dalessandro
1167f48ad614SDennis Dalessandro if (!(dd->flags & HFI1_HAS_SEND_DMA))
1168f48ad614SDennis Dalessandro return 0;
1169f48ad614SDennis Dalessandro
1170f48ad614SDennis Dalessandro if (!vl_engines) {
1171f48ad614SDennis Dalessandro /* truncate divide */
1172f48ad614SDennis Dalessandro sde_per_vl = dd->num_sdma / num_vls;
1173f48ad614SDennis Dalessandro /* extras */
1174f48ad614SDennis Dalessandro extra = dd->num_sdma % num_vls;
1175f48ad614SDennis Dalessandro vl_engines = lvl_engines;
1176f48ad614SDennis Dalessandro /* add extras from last vl down */
1177f48ad614SDennis Dalessandro for (i = num_vls - 1; i >= 0; i--, extra--)
1178f48ad614SDennis Dalessandro vl_engines[i] = sde_per_vl + (extra > 0 ? 1 : 0);
1179f48ad614SDennis Dalessandro }
1180f48ad614SDennis Dalessandro /* build new map */
1181f48ad614SDennis Dalessandro newmap = kzalloc(
1182f48ad614SDennis Dalessandro sizeof(struct sdma_vl_map) +
1183f48ad614SDennis Dalessandro roundup_pow_of_two(num_vls) *
1184f48ad614SDennis Dalessandro sizeof(struct sdma_map_elem *),
1185f48ad614SDennis Dalessandro GFP_KERNEL);
1186f48ad614SDennis Dalessandro if (!newmap)
1187f48ad614SDennis Dalessandro goto bail;
1188f48ad614SDennis Dalessandro newmap->actual_vls = num_vls;
1189f48ad614SDennis Dalessandro newmap->vls = roundup_pow_of_two(num_vls);
1190f48ad614SDennis Dalessandro newmap->mask = (1 << ilog2(newmap->vls)) - 1;
1191f48ad614SDennis Dalessandro /* initialize back-map */
1192f48ad614SDennis Dalessandro for (i = 0; i < TXE_NUM_SDMA_ENGINES; i++)
1193f48ad614SDennis Dalessandro newmap->engine_to_vl[i] = -1;
1194f48ad614SDennis Dalessandro for (i = 0; i < newmap->vls; i++) {
1195f48ad614SDennis Dalessandro /* save for wrap around */
1196f48ad614SDennis Dalessandro int first_engine = engine;
1197f48ad614SDennis Dalessandro
1198f48ad614SDennis Dalessandro if (i < newmap->actual_vls) {
1199f48ad614SDennis Dalessandro int sz = roundup_pow_of_two(vl_engines[i]);
1200f48ad614SDennis Dalessandro
1201f48ad614SDennis Dalessandro /* only allocate once */
1202f48ad614SDennis Dalessandro newmap->map[i] = kzalloc(
1203f48ad614SDennis Dalessandro sizeof(struct sdma_map_elem) +
1204f48ad614SDennis Dalessandro sz * sizeof(struct sdma_engine *),
1205f48ad614SDennis Dalessandro GFP_KERNEL);
1206f48ad614SDennis Dalessandro if (!newmap->map[i])
1207f48ad614SDennis Dalessandro goto bail;
1208f48ad614SDennis Dalessandro newmap->map[i]->mask = (1 << ilog2(sz)) - 1;
1209f48ad614SDennis Dalessandro /* assign engines */
1210f48ad614SDennis Dalessandro for (j = 0; j < sz; j++) {
1211f48ad614SDennis Dalessandro newmap->map[i]->sde[j] =
1212f48ad614SDennis Dalessandro &dd->per_sdma[engine];
1213f48ad614SDennis Dalessandro if (++engine >= first_engine + vl_engines[i])
1214f48ad614SDennis Dalessandro /* wrap back to first engine */
1215f48ad614SDennis Dalessandro engine = first_engine;
1216f48ad614SDennis Dalessandro }
1217f48ad614SDennis Dalessandro /* assign back-map */
1218f48ad614SDennis Dalessandro for (j = 0; j < vl_engines[i]; j++)
1219f48ad614SDennis Dalessandro newmap->engine_to_vl[first_engine + j] = i;
1220f48ad614SDennis Dalessandro } else {
1221f48ad614SDennis Dalessandro /* just re-use entry without allocating */
1222f48ad614SDennis Dalessandro newmap->map[i] = newmap->map[i % num_vls];
1223f48ad614SDennis Dalessandro }
1224f48ad614SDennis Dalessandro engine = first_engine + vl_engines[i];
1225f48ad614SDennis Dalessandro }
1226f48ad614SDennis Dalessandro /* newmap in hand, save old map */
1227f48ad614SDennis Dalessandro spin_lock_irq(&dd->sde_map_lock);
1228f48ad614SDennis Dalessandro oldmap = rcu_dereference_protected(dd->sdma_map,
1229f48ad614SDennis Dalessandro lockdep_is_held(&dd->sde_map_lock));
1230f48ad614SDennis Dalessandro
1231f48ad614SDennis Dalessandro /* publish newmap */
1232f48ad614SDennis Dalessandro rcu_assign_pointer(dd->sdma_map, newmap);
1233f48ad614SDennis Dalessandro
1234f48ad614SDennis Dalessandro spin_unlock_irq(&dd->sde_map_lock);
1235f48ad614SDennis Dalessandro /* success, free any old map after grace period */
1236f48ad614SDennis Dalessandro if (oldmap)
1237f48ad614SDennis Dalessandro call_rcu(&oldmap->list, sdma_map_rcu_callback);
1238f48ad614SDennis Dalessandro return 0;
1239f48ad614SDennis Dalessandro bail:
1240f48ad614SDennis Dalessandro /* free any partial allocation */
1241f48ad614SDennis Dalessandro sdma_map_free(newmap);
1242f48ad614SDennis Dalessandro return -ENOMEM;
1243f48ad614SDennis Dalessandro }
1244f48ad614SDennis Dalessandro
1245473291b3SAlex Estrin /**
1246ae360f41SLeon Romanovsky * sdma_clean - Clean up allocated memory
1247473291b3SAlex Estrin * @dd: struct hfi1_devdata
1248473291b3SAlex Estrin * @num_engines: num sdma engines
1249f48ad614SDennis Dalessandro *
1250473291b3SAlex Estrin * This routine can be called regardless of the success of
1251473291b3SAlex Estrin * sdma_init()
1252f48ad614SDennis Dalessandro */
sdma_clean(struct hfi1_devdata * dd,size_t num_engines)1253473291b3SAlex Estrin void sdma_clean(struct hfi1_devdata *dd, size_t num_engines)
1254f48ad614SDennis Dalessandro {
1255f48ad614SDennis Dalessandro size_t i;
1256f48ad614SDennis Dalessandro struct sdma_engine *sde;
1257f48ad614SDennis Dalessandro
1258f48ad614SDennis Dalessandro if (dd->sdma_pad_dma) {
125922bb1365SMike Marciniszyn dma_free_coherent(&dd->pcidev->dev, SDMA_PAD,
1260f48ad614SDennis Dalessandro (void *)dd->sdma_pad_dma,
1261f48ad614SDennis Dalessandro dd->sdma_pad_phys);
1262f48ad614SDennis Dalessandro dd->sdma_pad_dma = NULL;
1263f48ad614SDennis Dalessandro dd->sdma_pad_phys = 0;
1264f48ad614SDennis Dalessandro }
1265f48ad614SDennis Dalessandro if (dd->sdma_heads_dma) {
1266f48ad614SDennis Dalessandro dma_free_coherent(&dd->pcidev->dev, dd->sdma_heads_size,
1267f48ad614SDennis Dalessandro (void *)dd->sdma_heads_dma,
1268f48ad614SDennis Dalessandro dd->sdma_heads_phys);
1269f48ad614SDennis Dalessandro dd->sdma_heads_dma = NULL;
1270f48ad614SDennis Dalessandro dd->sdma_heads_phys = 0;
1271f48ad614SDennis Dalessandro }
1272f48ad614SDennis Dalessandro for (i = 0; dd->per_sdma && i < num_engines; ++i) {
1273f48ad614SDennis Dalessandro sde = &dd->per_sdma[i];
1274f48ad614SDennis Dalessandro
1275f48ad614SDennis Dalessandro sde->head_dma = NULL;
1276f48ad614SDennis Dalessandro sde->head_phys = 0;
1277f48ad614SDennis Dalessandro
1278f48ad614SDennis Dalessandro if (sde->descq) {
1279f48ad614SDennis Dalessandro dma_free_coherent(
1280f48ad614SDennis Dalessandro &dd->pcidev->dev,
1281f48ad614SDennis Dalessandro sde->descq_cnt * sizeof(u64[2]),
1282f48ad614SDennis Dalessandro sde->descq,
1283f48ad614SDennis Dalessandro sde->descq_phys
1284f48ad614SDennis Dalessandro );
1285f48ad614SDennis Dalessandro sde->descq = NULL;
1286f48ad614SDennis Dalessandro sde->descq_phys = 0;
1287f48ad614SDennis Dalessandro }
1288f48ad614SDennis Dalessandro kvfree(sde->tx_ring);
1289f48ad614SDennis Dalessandro sde->tx_ring = NULL;
1290f48ad614SDennis Dalessandro }
129105c03dfdSDouglas Miller if (rcu_access_pointer(dd->sdma_map)) {
1292f48ad614SDennis Dalessandro spin_lock_irq(&dd->sde_map_lock);
1293f48ad614SDennis Dalessandro sdma_map_free(rcu_access_pointer(dd->sdma_map));
1294f48ad614SDennis Dalessandro RCU_INIT_POINTER(dd->sdma_map, NULL);
1295f48ad614SDennis Dalessandro spin_unlock_irq(&dd->sde_map_lock);
1296f48ad614SDennis Dalessandro synchronize_rcu();
129705c03dfdSDouglas Miller }
1298f48ad614SDennis Dalessandro kfree(dd->per_sdma);
1299f48ad614SDennis Dalessandro dd->per_sdma = NULL;
13005a52a7acSSebastian Sanchez
13015a52a7acSSebastian Sanchez if (dd->sdma_rht) {
13025a52a7acSSebastian Sanchez rhashtable_free_and_destroy(dd->sdma_rht, sdma_rht_free, NULL);
13035a52a7acSSebastian Sanchez kfree(dd->sdma_rht);
13045a52a7acSSebastian Sanchez dd->sdma_rht = NULL;
13055a52a7acSSebastian Sanchez }
1306f48ad614SDennis Dalessandro }
1307f48ad614SDennis Dalessandro
1308f48ad614SDennis Dalessandro /**
1309f48ad614SDennis Dalessandro * sdma_init() - called when device probed
1310f48ad614SDennis Dalessandro * @dd: hfi1_devdata
1311f48ad614SDennis Dalessandro * @port: port number (currently only zero)
1312f48ad614SDennis Dalessandro *
131390dba23eSIra Weiny * Initializes each sde and its csrs.
131490dba23eSIra Weiny * Interrupts are not required to be enabled.
1315f48ad614SDennis Dalessandro *
1316f48ad614SDennis Dalessandro * Returns:
1317f48ad614SDennis Dalessandro * 0 - success, -errno on failure
1318f48ad614SDennis Dalessandro */
sdma_init(struct hfi1_devdata * dd,u8 port)1319f48ad614SDennis Dalessandro int sdma_init(struct hfi1_devdata *dd, u8 port)
1320f48ad614SDennis Dalessandro {
1321f48ad614SDennis Dalessandro unsigned this_idx;
1322f48ad614SDennis Dalessandro struct sdma_engine *sde;
13235a52a7acSSebastian Sanchez struct rhashtable *tmp_sdma_rht;
1324f48ad614SDennis Dalessandro u16 descq_cnt;
1325f48ad614SDennis Dalessandro void *curr_head;
1326f48ad614SDennis Dalessandro struct hfi1_pportdata *ppd = dd->pport + port;
1327f48ad614SDennis Dalessandro u32 per_sdma_credits;
1328f48ad614SDennis Dalessandro uint idle_cnt = sdma_idle_cnt;
132906e81e3eSMike Marciniszyn size_t num_engines = chip_sdma_engines(dd);
13305a52a7acSSebastian Sanchez int ret = -ENOMEM;
1331f48ad614SDennis Dalessandro
1332f48ad614SDennis Dalessandro if (!HFI1_CAP_IS_KSET(SDMA)) {
1333f48ad614SDennis Dalessandro HFI1_CAP_CLEAR(SDMA_AHG);
1334f48ad614SDennis Dalessandro return 0;
1335f48ad614SDennis Dalessandro }
1336f48ad614SDennis Dalessandro if (mod_num_sdma &&
1337f48ad614SDennis Dalessandro /* can't exceed chip support */
133806e81e3eSMike Marciniszyn mod_num_sdma <= chip_sdma_engines(dd) &&
1339f48ad614SDennis Dalessandro /* count must be >= vls */
1340f48ad614SDennis Dalessandro mod_num_sdma >= num_vls)
1341f48ad614SDennis Dalessandro num_engines = mod_num_sdma;
1342f48ad614SDennis Dalessandro
1343f48ad614SDennis Dalessandro dd_dev_info(dd, "SDMA mod_num_sdma: %u\n", mod_num_sdma);
134406e81e3eSMike Marciniszyn dd_dev_info(dd, "SDMA chip_sdma_engines: %u\n", chip_sdma_engines(dd));
1345f48ad614SDennis Dalessandro dd_dev_info(dd, "SDMA chip_sdma_mem_size: %u\n",
134606e81e3eSMike Marciniszyn chip_sdma_mem_size(dd));
1347f48ad614SDennis Dalessandro
1348f48ad614SDennis Dalessandro per_sdma_credits =
134906e81e3eSMike Marciniszyn chip_sdma_mem_size(dd) / (num_engines * SDMA_BLOCK_SIZE);
1350f48ad614SDennis Dalessandro
1351f48ad614SDennis Dalessandro /* set up freeze waitqueue */
1352f48ad614SDennis Dalessandro init_waitqueue_head(&dd->sdma_unfreeze_wq);
1353f48ad614SDennis Dalessandro atomic_set(&dd->sdma_unfreeze_count, 0);
1354f48ad614SDennis Dalessandro
1355f48ad614SDennis Dalessandro descq_cnt = sdma_get_descq_cnt();
1356f48ad614SDennis Dalessandro dd_dev_info(dd, "SDMA engines %zu descq_cnt %u\n",
1357f48ad614SDennis Dalessandro num_engines, descq_cnt);
1358f48ad614SDennis Dalessandro
1359f48ad614SDennis Dalessandro /* alloc memory for array of send engines */
1360953a9cebSKamenee Arumugam dd->per_sdma = kcalloc_node(num_engines, sizeof(*dd->per_sdma),
1361953a9cebSKamenee Arumugam GFP_KERNEL, dd->node);
1362f48ad614SDennis Dalessandro if (!dd->per_sdma)
13635a52a7acSSebastian Sanchez return ret;
1364f48ad614SDennis Dalessandro
1365f48ad614SDennis Dalessandro idle_cnt = ns_to_cclock(dd, idle_cnt);
1366aadd7020SIra Weiny if (idle_cnt)
1367aadd7020SIra Weiny dd->default_desc1 =
1368aadd7020SIra Weiny SDMA_DESC1_HEAD_TO_HOST_FLAG;
1369aadd7020SIra Weiny else
1370aadd7020SIra Weiny dd->default_desc1 =
1371aadd7020SIra Weiny SDMA_DESC1_INT_REQ_FLAG;
1372aadd7020SIra Weiny
1373f48ad614SDennis Dalessandro if (!sdma_desct_intr)
1374f48ad614SDennis Dalessandro sdma_desct_intr = SDMA_DESC_INTR;
1375f48ad614SDennis Dalessandro
1376f48ad614SDennis Dalessandro /* Allocate memory for SendDMA descriptor FIFOs */
1377f48ad614SDennis Dalessandro for (this_idx = 0; this_idx < num_engines; ++this_idx) {
1378f48ad614SDennis Dalessandro sde = &dd->per_sdma[this_idx];
1379f48ad614SDennis Dalessandro sde->dd = dd;
1380f48ad614SDennis Dalessandro sde->ppd = ppd;
1381f48ad614SDennis Dalessandro sde->this_idx = this_idx;
1382f48ad614SDennis Dalessandro sde->descq_cnt = descq_cnt;
1383f48ad614SDennis Dalessandro sde->desc_avail = sdma_descq_freecnt(sde);
1384f48ad614SDennis Dalessandro sde->sdma_shift = ilog2(descq_cnt);
1385f48ad614SDennis Dalessandro sde->sdma_mask = (1 << sde->sdma_shift) - 1;
1386f48ad614SDennis Dalessandro
1387f48ad614SDennis Dalessandro /* Create a mask specifically for each interrupt source */
1388f48ad614SDennis Dalessandro sde->int_mask = (u64)1 << (0 * TXE_NUM_SDMA_ENGINES +
1389f48ad614SDennis Dalessandro this_idx);
1390f48ad614SDennis Dalessandro sde->progress_mask = (u64)1 << (1 * TXE_NUM_SDMA_ENGINES +
1391f48ad614SDennis Dalessandro this_idx);
1392f48ad614SDennis Dalessandro sde->idle_mask = (u64)1 << (2 * TXE_NUM_SDMA_ENGINES +
1393f48ad614SDennis Dalessandro this_idx);
1394f48ad614SDennis Dalessandro /* Create a combined mask to cover all 3 interrupt sources */
1395f48ad614SDennis Dalessandro sde->imask = sde->int_mask | sde->progress_mask |
1396f48ad614SDennis Dalessandro sde->idle_mask;
1397f48ad614SDennis Dalessandro
1398f48ad614SDennis Dalessandro spin_lock_init(&sde->tail_lock);
1399f48ad614SDennis Dalessandro seqlock_init(&sde->head_lock);
1400f48ad614SDennis Dalessandro spin_lock_init(&sde->senddmactrl_lock);
1401f48ad614SDennis Dalessandro spin_lock_init(&sde->flushlist_lock);
14029aefcabeSMike Marciniszyn seqlock_init(&sde->waitlock);
1403f48ad614SDennis Dalessandro /* insure there is always a zero bit */
1404f48ad614SDennis Dalessandro sde->ahg_bits = 0xfffffffe00000000ULL;
1405f48ad614SDennis Dalessandro
1406f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s00_hw_down);
1407f48ad614SDennis Dalessandro
1408f48ad614SDennis Dalessandro /* set up reference counting */
1409f48ad614SDennis Dalessandro kref_init(&sde->state.kref);
1410f48ad614SDennis Dalessandro init_completion(&sde->state.comp);
1411f48ad614SDennis Dalessandro
1412f48ad614SDennis Dalessandro INIT_LIST_HEAD(&sde->flushlist);
1413f48ad614SDennis Dalessandro INIT_LIST_HEAD(&sde->dmawait);
1414f48ad614SDennis Dalessandro
1415f48ad614SDennis Dalessandro sde->tail_csr =
1416f48ad614SDennis Dalessandro get_kctxt_csr_addr(dd, this_idx, SD(TAIL));
1417f48ad614SDennis Dalessandro
141855db47d0SAllen Pais tasklet_setup(&sde->sdma_hw_clean_up_task,
141955db47d0SAllen Pais sdma_hw_clean_up_task);
142055db47d0SAllen Pais tasklet_setup(&sde->sdma_sw_clean_up_task,
142155db47d0SAllen Pais sdma_sw_clean_up_task);
1422f48ad614SDennis Dalessandro INIT_WORK(&sde->err_halt_worker, sdma_err_halt_wait);
1423f48ad614SDennis Dalessandro INIT_WORK(&sde->flush_worker, sdma_field_flush);
1424f48ad614SDennis Dalessandro
1425f48ad614SDennis Dalessandro sde->progress_check_head = 0;
1426f48ad614SDennis Dalessandro
14278064135eSKees Cook timer_setup(&sde->err_progress_check_timer,
14288064135eSKees Cook sdma_err_progress_check, 0);
1429f48ad614SDennis Dalessandro
1430750afb08SLuis Chamberlain sde->descq = dma_alloc_coherent(&dd->pcidev->dev,
1431f48ad614SDennis Dalessandro descq_cnt * sizeof(u64[2]),
1432750afb08SLuis Chamberlain &sde->descq_phys, GFP_KERNEL);
1433f48ad614SDennis Dalessandro if (!sde->descq)
1434f48ad614SDennis Dalessandro goto bail;
1435f48ad614SDennis Dalessandro sde->tx_ring =
143684ca176bSKees Cook kvzalloc_node(array_size(descq_cnt,
143784ca176bSKees Cook sizeof(struct sdma_txreq *)),
143831acd18bSMike Marciniszyn GFP_KERNEL, dd->node);
1439f48ad614SDennis Dalessandro if (!sde->tx_ring)
1440f48ad614SDennis Dalessandro goto bail;
1441f48ad614SDennis Dalessandro }
1442f48ad614SDennis Dalessandro
1443f48ad614SDennis Dalessandro dd->sdma_heads_size = L1_CACHE_BYTES * num_engines;
1444f48ad614SDennis Dalessandro /* Allocate memory for DMA of head registers to memory */
1445750afb08SLuis Chamberlain dd->sdma_heads_dma = dma_alloc_coherent(&dd->pcidev->dev,
1446f48ad614SDennis Dalessandro dd->sdma_heads_size,
1447f48ad614SDennis Dalessandro &dd->sdma_heads_phys,
1448750afb08SLuis Chamberlain GFP_KERNEL);
1449f48ad614SDennis Dalessandro if (!dd->sdma_heads_dma) {
1450f48ad614SDennis Dalessandro dd_dev_err(dd, "failed to allocate SendDMA head memory\n");
1451f48ad614SDennis Dalessandro goto bail;
1452f48ad614SDennis Dalessandro }
1453f48ad614SDennis Dalessandro
1454f48ad614SDennis Dalessandro /* Allocate memory for pad */
145522bb1365SMike Marciniszyn dd->sdma_pad_dma = dma_alloc_coherent(&dd->pcidev->dev, SDMA_PAD,
1456750afb08SLuis Chamberlain &dd->sdma_pad_phys, GFP_KERNEL);
1457f48ad614SDennis Dalessandro if (!dd->sdma_pad_dma) {
1458f48ad614SDennis Dalessandro dd_dev_err(dd, "failed to allocate SendDMA pad memory\n");
1459f48ad614SDennis Dalessandro goto bail;
1460f48ad614SDennis Dalessandro }
1461f48ad614SDennis Dalessandro
1462f48ad614SDennis Dalessandro /* assign each engine to different cacheline and init registers */
1463f48ad614SDennis Dalessandro curr_head = (void *)dd->sdma_heads_dma;
1464f48ad614SDennis Dalessandro for (this_idx = 0; this_idx < num_engines; ++this_idx) {
1465f48ad614SDennis Dalessandro unsigned long phys_offset;
1466f48ad614SDennis Dalessandro
1467f48ad614SDennis Dalessandro sde = &dd->per_sdma[this_idx];
1468f48ad614SDennis Dalessandro
1469f48ad614SDennis Dalessandro sde->head_dma = curr_head;
1470f48ad614SDennis Dalessandro curr_head += L1_CACHE_BYTES;
1471f48ad614SDennis Dalessandro phys_offset = (unsigned long)sde->head_dma -
1472f48ad614SDennis Dalessandro (unsigned long)dd->sdma_heads_dma;
1473f48ad614SDennis Dalessandro sde->head_phys = dd->sdma_heads_phys + phys_offset;
1474f48ad614SDennis Dalessandro init_sdma_regs(sde, per_sdma_credits, idle_cnt);
1475f48ad614SDennis Dalessandro }
1476f48ad614SDennis Dalessandro dd->flags |= HFI1_HAS_SEND_DMA;
1477f48ad614SDennis Dalessandro dd->flags |= idle_cnt ? HFI1_HAS_SDMA_TIMEOUT : 0;
1478f48ad614SDennis Dalessandro dd->num_sdma = num_engines;
14795a52a7acSSebastian Sanchez ret = sdma_map_init(dd, port, ppd->vls_operational, NULL);
14805a52a7acSSebastian Sanchez if (ret < 0)
1481f48ad614SDennis Dalessandro goto bail;
14820cb2aa69STadeusz Struk
14835a52a7acSSebastian Sanchez tmp_sdma_rht = kzalloc(sizeof(*tmp_sdma_rht), GFP_KERNEL);
14845a52a7acSSebastian Sanchez if (!tmp_sdma_rht) {
14855a52a7acSSebastian Sanchez ret = -ENOMEM;
14860cb2aa69STadeusz Struk goto bail;
14875a52a7acSSebastian Sanchez }
14885a52a7acSSebastian Sanchez
14895a52a7acSSebastian Sanchez ret = rhashtable_init(tmp_sdma_rht, &sdma_rht_params);
149034b3be18SNavid Emamdoost if (ret < 0) {
149134b3be18SNavid Emamdoost kfree(tmp_sdma_rht);
14925a52a7acSSebastian Sanchez goto bail;
149334b3be18SNavid Emamdoost }
149434b3be18SNavid Emamdoost
14955a52a7acSSebastian Sanchez dd->sdma_rht = tmp_sdma_rht;
14960cb2aa69STadeusz Struk
1497f48ad614SDennis Dalessandro dd_dev_info(dd, "SDMA num_sdma: %u\n", dd->num_sdma);
1498f48ad614SDennis Dalessandro return 0;
1499f48ad614SDennis Dalessandro
1500f48ad614SDennis Dalessandro bail:
1501f48ad614SDennis Dalessandro sdma_clean(dd, num_engines);
15025a52a7acSSebastian Sanchez return ret;
1503f48ad614SDennis Dalessandro }
1504f48ad614SDennis Dalessandro
1505f48ad614SDennis Dalessandro /**
1506f48ad614SDennis Dalessandro * sdma_all_running() - called when the link goes up
1507f48ad614SDennis Dalessandro * @dd: hfi1_devdata
1508f48ad614SDennis Dalessandro *
1509f48ad614SDennis Dalessandro * This routine moves all engines to the running state.
1510f48ad614SDennis Dalessandro */
sdma_all_running(struct hfi1_devdata * dd)1511f48ad614SDennis Dalessandro void sdma_all_running(struct hfi1_devdata *dd)
1512f48ad614SDennis Dalessandro {
1513f48ad614SDennis Dalessandro struct sdma_engine *sde;
1514f48ad614SDennis Dalessandro unsigned int i;
1515f48ad614SDennis Dalessandro
1516f48ad614SDennis Dalessandro /* move all engines to running */
1517f48ad614SDennis Dalessandro for (i = 0; i < dd->num_sdma; ++i) {
1518f48ad614SDennis Dalessandro sde = &dd->per_sdma[i];
1519f48ad614SDennis Dalessandro sdma_process_event(sde, sdma_event_e30_go_running);
1520f48ad614SDennis Dalessandro }
1521f48ad614SDennis Dalessandro }
1522f48ad614SDennis Dalessandro
1523f48ad614SDennis Dalessandro /**
1524f48ad614SDennis Dalessandro * sdma_all_idle() - called when the link goes down
1525f48ad614SDennis Dalessandro * @dd: hfi1_devdata
1526f48ad614SDennis Dalessandro *
1527f48ad614SDennis Dalessandro * This routine moves all engines to the idle state.
1528f48ad614SDennis Dalessandro */
sdma_all_idle(struct hfi1_devdata * dd)1529f48ad614SDennis Dalessandro void sdma_all_idle(struct hfi1_devdata *dd)
1530f48ad614SDennis Dalessandro {
1531f48ad614SDennis Dalessandro struct sdma_engine *sde;
1532f48ad614SDennis Dalessandro unsigned int i;
1533f48ad614SDennis Dalessandro
1534f48ad614SDennis Dalessandro /* idle all engines */
1535f48ad614SDennis Dalessandro for (i = 0; i < dd->num_sdma; ++i) {
1536f48ad614SDennis Dalessandro sde = &dd->per_sdma[i];
1537f48ad614SDennis Dalessandro sdma_process_event(sde, sdma_event_e70_go_idle);
1538f48ad614SDennis Dalessandro }
1539f48ad614SDennis Dalessandro }
1540f48ad614SDennis Dalessandro
1541f48ad614SDennis Dalessandro /**
1542f48ad614SDennis Dalessandro * sdma_start() - called to kick off state processing for all engines
1543f48ad614SDennis Dalessandro * @dd: hfi1_devdata
1544f48ad614SDennis Dalessandro *
1545f48ad614SDennis Dalessandro * This routine is for kicking off the state processing for all required
1546f48ad614SDennis Dalessandro * sdma engines. Interrupts need to be working at this point.
1547f48ad614SDennis Dalessandro *
1548f48ad614SDennis Dalessandro */
sdma_start(struct hfi1_devdata * dd)1549f48ad614SDennis Dalessandro void sdma_start(struct hfi1_devdata *dd)
1550f48ad614SDennis Dalessandro {
1551f48ad614SDennis Dalessandro unsigned i;
1552f48ad614SDennis Dalessandro struct sdma_engine *sde;
1553f48ad614SDennis Dalessandro
1554f48ad614SDennis Dalessandro /* kick off the engines state processing */
1555f48ad614SDennis Dalessandro for (i = 0; i < dd->num_sdma; ++i) {
1556f48ad614SDennis Dalessandro sde = &dd->per_sdma[i];
1557f48ad614SDennis Dalessandro sdma_process_event(sde, sdma_event_e10_go_hw_start);
1558f48ad614SDennis Dalessandro }
1559f48ad614SDennis Dalessandro }
1560f48ad614SDennis Dalessandro
1561f48ad614SDennis Dalessandro /**
1562f48ad614SDennis Dalessandro * sdma_exit() - used when module is removed
1563f48ad614SDennis Dalessandro * @dd: hfi1_devdata
1564f48ad614SDennis Dalessandro */
sdma_exit(struct hfi1_devdata * dd)1565f48ad614SDennis Dalessandro void sdma_exit(struct hfi1_devdata *dd)
1566f48ad614SDennis Dalessandro {
1567f48ad614SDennis Dalessandro unsigned this_idx;
1568f48ad614SDennis Dalessandro struct sdma_engine *sde;
1569f48ad614SDennis Dalessandro
1570f48ad614SDennis Dalessandro for (this_idx = 0; dd->per_sdma && this_idx < dd->num_sdma;
1571f48ad614SDennis Dalessandro ++this_idx) {
1572f48ad614SDennis Dalessandro sde = &dd->per_sdma[this_idx];
1573f48ad614SDennis Dalessandro if (!list_empty(&sde->dmawait))
1574f48ad614SDennis Dalessandro dd_dev_err(dd, "sde %u: dmawait list not empty!\n",
1575f48ad614SDennis Dalessandro sde->this_idx);
1576f48ad614SDennis Dalessandro sdma_process_event(sde, sdma_event_e00_go_hw_down);
1577f48ad614SDennis Dalessandro
1578f48ad614SDennis Dalessandro del_timer_sync(&sde->err_progress_check_timer);
1579f48ad614SDennis Dalessandro
1580f48ad614SDennis Dalessandro /*
1581f48ad614SDennis Dalessandro * This waits for the state machine to exit so it is not
1582f48ad614SDennis Dalessandro * necessary to kill the sdma_sw_clean_up_task to make sure
1583f48ad614SDennis Dalessandro * it is not running.
1584f48ad614SDennis Dalessandro */
1585f48ad614SDennis Dalessandro sdma_finalput(&sde->state);
1586f48ad614SDennis Dalessandro }
1587f48ad614SDennis Dalessandro }
1588f48ad614SDennis Dalessandro
1589f48ad614SDennis Dalessandro /*
1590f48ad614SDennis Dalessandro * unmap the indicated descriptor
1591f48ad614SDennis Dalessandro */
sdma_unmap_desc(struct hfi1_devdata * dd,struct sdma_desc * descp)1592f48ad614SDennis Dalessandro static inline void sdma_unmap_desc(
1593f48ad614SDennis Dalessandro struct hfi1_devdata *dd,
1594f48ad614SDennis Dalessandro struct sdma_desc *descp)
1595f48ad614SDennis Dalessandro {
1596c9358de1SBrendan Cunningham switch (sdma_mapping_type(descp)) {
1597c9358de1SBrendan Cunningham case SDMA_MAP_SINGLE:
1598c9358de1SBrendan Cunningham dma_unmap_single(&dd->pcidev->dev, sdma_mapping_addr(descp),
1599c9358de1SBrendan Cunningham sdma_mapping_len(descp), DMA_TO_DEVICE);
1600c9358de1SBrendan Cunningham break;
1601c9358de1SBrendan Cunningham case SDMA_MAP_PAGE:
1602c9358de1SBrendan Cunningham dma_unmap_page(&dd->pcidev->dev, sdma_mapping_addr(descp),
1603c9358de1SBrendan Cunningham sdma_mapping_len(descp), DMA_TO_DEVICE);
1604c9358de1SBrendan Cunningham break;
1605c9358de1SBrendan Cunningham }
1606c9358de1SBrendan Cunningham
1607c9358de1SBrendan Cunningham if (descp->pinning_ctx && descp->ctx_put)
1608c9358de1SBrendan Cunningham descp->ctx_put(descp->pinning_ctx);
1609c9358de1SBrendan Cunningham descp->pinning_ctx = NULL;
1610f48ad614SDennis Dalessandro }
1611f48ad614SDennis Dalessandro
1612f48ad614SDennis Dalessandro /*
1613f48ad614SDennis Dalessandro * return the mode as indicated by the first
1614f48ad614SDennis Dalessandro * descriptor in the tx.
1615f48ad614SDennis Dalessandro */
ahg_mode(struct sdma_txreq * tx)1616f48ad614SDennis Dalessandro static inline u8 ahg_mode(struct sdma_txreq *tx)
1617f48ad614SDennis Dalessandro {
1618f48ad614SDennis Dalessandro return (tx->descp[0].qw[1] & SDMA_DESC1_HEADER_MODE_SMASK)
1619f48ad614SDennis Dalessandro >> SDMA_DESC1_HEADER_MODE_SHIFT;
1620f48ad614SDennis Dalessandro }
1621f48ad614SDennis Dalessandro
1622f48ad614SDennis Dalessandro /**
162363df8e09SMike Marciniszyn * __sdma_txclean() - clean tx of mappings, descp *kmalloc's
1624f48ad614SDennis Dalessandro * @dd: hfi1_devdata for unmapping
1625f48ad614SDennis Dalessandro * @tx: tx request to clean
1626f48ad614SDennis Dalessandro *
1627f48ad614SDennis Dalessandro * This is used in the progress routine to clean the tx or
1628f48ad614SDennis Dalessandro * by the ULP to toss an in-process tx build.
1629f48ad614SDennis Dalessandro *
1630f48ad614SDennis Dalessandro * The code can be called multiple times without issue.
1631f48ad614SDennis Dalessandro *
1632f48ad614SDennis Dalessandro */
__sdma_txclean(struct hfi1_devdata * dd,struct sdma_txreq * tx)163363df8e09SMike Marciniszyn void __sdma_txclean(
1634f48ad614SDennis Dalessandro struct hfi1_devdata *dd,
1635f48ad614SDennis Dalessandro struct sdma_txreq *tx)
1636f48ad614SDennis Dalessandro {
1637f48ad614SDennis Dalessandro u16 i;
1638f48ad614SDennis Dalessandro
1639f48ad614SDennis Dalessandro if (tx->num_desc) {
1640f48ad614SDennis Dalessandro u8 skip = 0, mode = ahg_mode(tx);
1641f48ad614SDennis Dalessandro
1642f48ad614SDennis Dalessandro /* unmap first */
1643f48ad614SDennis Dalessandro sdma_unmap_desc(dd, &tx->descp[0]);
1644f48ad614SDennis Dalessandro /* determine number of AHG descriptors to skip */
1645f48ad614SDennis Dalessandro if (mode > SDMA_AHG_APPLY_UPDATE1)
1646f48ad614SDennis Dalessandro skip = mode >> 1;
1647f48ad614SDennis Dalessandro for (i = 1 + skip; i < tx->num_desc; i++)
1648f48ad614SDennis Dalessandro sdma_unmap_desc(dd, &tx->descp[i]);
1649f48ad614SDennis Dalessandro tx->num_desc = 0;
1650f48ad614SDennis Dalessandro }
1651f48ad614SDennis Dalessandro kfree(tx->coalesce_buf);
1652f48ad614SDennis Dalessandro tx->coalesce_buf = NULL;
1653f48ad614SDennis Dalessandro /* kmalloc'ed descp */
1654f48ad614SDennis Dalessandro if (unlikely(tx->desc_limit > ARRAY_SIZE(tx->descs))) {
1655f48ad614SDennis Dalessandro tx->desc_limit = ARRAY_SIZE(tx->descs);
1656f48ad614SDennis Dalessandro kfree(tx->descp);
1657f48ad614SDennis Dalessandro }
1658f48ad614SDennis Dalessandro }
1659f48ad614SDennis Dalessandro
sdma_gethead(struct sdma_engine * sde)1660f48ad614SDennis Dalessandro static inline u16 sdma_gethead(struct sdma_engine *sde)
1661f48ad614SDennis Dalessandro {
1662f48ad614SDennis Dalessandro struct hfi1_devdata *dd = sde->dd;
1663f48ad614SDennis Dalessandro int use_dmahead;
1664f48ad614SDennis Dalessandro u16 hwhead;
1665f48ad614SDennis Dalessandro
1666f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
1667f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n",
1668f48ad614SDennis Dalessandro sde->this_idx, slashstrip(__FILE__), __LINE__, __func__);
1669f48ad614SDennis Dalessandro #endif
1670f48ad614SDennis Dalessandro
1671f48ad614SDennis Dalessandro retry:
1672f48ad614SDennis Dalessandro use_dmahead = HFI1_CAP_IS_KSET(USE_SDMA_HEAD) && __sdma_running(sde) &&
1673f48ad614SDennis Dalessandro (dd->flags & HFI1_HAS_SDMA_TIMEOUT);
1674f48ad614SDennis Dalessandro hwhead = use_dmahead ?
1675f48ad614SDennis Dalessandro (u16)le64_to_cpu(*sde->head_dma) :
1676f48ad614SDennis Dalessandro (u16)read_sde_csr(sde, SD(HEAD));
1677f48ad614SDennis Dalessandro
1678f48ad614SDennis Dalessandro if (unlikely(HFI1_CAP_IS_KSET(SDMA_HEAD_CHECK))) {
1679f48ad614SDennis Dalessandro u16 cnt;
1680f48ad614SDennis Dalessandro u16 swtail;
1681f48ad614SDennis Dalessandro u16 swhead;
1682f48ad614SDennis Dalessandro int sane;
1683f48ad614SDennis Dalessandro
1684f48ad614SDennis Dalessandro swhead = sde->descq_head & sde->sdma_mask;
1685f48ad614SDennis Dalessandro /* this code is really bad for cache line trading */
16866aa7de05SMark Rutland swtail = READ_ONCE(sde->descq_tail) & sde->sdma_mask;
1687f48ad614SDennis Dalessandro cnt = sde->descq_cnt;
1688f48ad614SDennis Dalessandro
1689f48ad614SDennis Dalessandro if (swhead < swtail)
1690f48ad614SDennis Dalessandro /* not wrapped */
1691f48ad614SDennis Dalessandro sane = (hwhead >= swhead) & (hwhead <= swtail);
1692f48ad614SDennis Dalessandro else if (swhead > swtail)
1693f48ad614SDennis Dalessandro /* wrapped around */
1694f48ad614SDennis Dalessandro sane = ((hwhead >= swhead) && (hwhead < cnt)) ||
1695f48ad614SDennis Dalessandro (hwhead <= swtail);
1696f48ad614SDennis Dalessandro else
1697f48ad614SDennis Dalessandro /* empty */
1698f48ad614SDennis Dalessandro sane = (hwhead == swhead);
1699f48ad614SDennis Dalessandro
1700f48ad614SDennis Dalessandro if (unlikely(!sane)) {
1701fe91b236STom Rix dd_dev_err(dd, "SDMA(%u) bad head (%s) hwhd=%u swhd=%u swtl=%u cnt=%u\n",
1702f48ad614SDennis Dalessandro sde->this_idx,
1703f48ad614SDennis Dalessandro use_dmahead ? "dma" : "kreg",
1704f48ad614SDennis Dalessandro hwhead, swhead, swtail, cnt);
1705f48ad614SDennis Dalessandro if (use_dmahead) {
1706f48ad614SDennis Dalessandro /* try one more time, using csr */
1707f48ad614SDennis Dalessandro use_dmahead = 0;
1708f48ad614SDennis Dalessandro goto retry;
1709f48ad614SDennis Dalessandro }
1710f48ad614SDennis Dalessandro /* proceed as if no progress */
1711f48ad614SDennis Dalessandro hwhead = swhead;
1712f48ad614SDennis Dalessandro }
1713f48ad614SDennis Dalessandro }
1714f48ad614SDennis Dalessandro return hwhead;
1715f48ad614SDennis Dalessandro }
1716f48ad614SDennis Dalessandro
1717f48ad614SDennis Dalessandro /*
1718f48ad614SDennis Dalessandro * This is called when there are send DMA descriptors that might be
1719f48ad614SDennis Dalessandro * available.
1720f48ad614SDennis Dalessandro *
1721f48ad614SDennis Dalessandro * This is called with head_lock held.
1722f48ad614SDennis Dalessandro */
sdma_desc_avail(struct sdma_engine * sde,uint avail)1723bcad2913SKaike Wan static void sdma_desc_avail(struct sdma_engine *sde, uint avail)
1724f48ad614SDennis Dalessandro {
172534025fb0SKaike Wan struct iowait *wait, *nw, *twait;
1726f48ad614SDennis Dalessandro struct iowait *waits[SDMA_WAIT_BATCH_SIZE];
172734025fb0SKaike Wan uint i, n = 0, seq, tidx = 0;
1728f48ad614SDennis Dalessandro
1729f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
1730f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n", sde->this_idx,
1731f48ad614SDennis Dalessandro slashstrip(__FILE__), __LINE__, __func__);
1732f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "avail: %u\n", avail);
1733f48ad614SDennis Dalessandro #endif
1734f48ad614SDennis Dalessandro
1735f48ad614SDennis Dalessandro do {
17369aefcabeSMike Marciniszyn seq = read_seqbegin(&sde->waitlock);
1737f48ad614SDennis Dalessandro if (!list_empty(&sde->dmawait)) {
1738f48ad614SDennis Dalessandro /* at least one item */
17399aefcabeSMike Marciniszyn write_seqlock(&sde->waitlock);
1740f48ad614SDennis Dalessandro /* Harvest waiters wanting DMA descriptors */
1741f48ad614SDennis Dalessandro list_for_each_entry_safe(
1742f48ad614SDennis Dalessandro wait,
1743f48ad614SDennis Dalessandro nw,
1744f48ad614SDennis Dalessandro &sde->dmawait,
1745f48ad614SDennis Dalessandro list) {
17465da0fc9dSDennis Dalessandro u32 num_desc;
1747f48ad614SDennis Dalessandro
1748f48ad614SDennis Dalessandro if (!wait->wakeup)
1749f48ad614SDennis Dalessandro continue;
1750f48ad614SDennis Dalessandro if (n == ARRAY_SIZE(waits))
1751f48ad614SDennis Dalessandro break;
175234025fb0SKaike Wan iowait_init_priority(wait);
17535da0fc9dSDennis Dalessandro num_desc = iowait_get_all_desc(wait);
1754f48ad614SDennis Dalessandro if (num_desc > avail)
1755f48ad614SDennis Dalessandro break;
1756f48ad614SDennis Dalessandro avail -= num_desc;
175734025fb0SKaike Wan /* Find the top-priority wait memeber */
175834025fb0SKaike Wan if (n) {
175934025fb0SKaike Wan twait = waits[tidx];
176034025fb0SKaike Wan tidx =
176134025fb0SKaike Wan iowait_priority_update_top(wait,
176234025fb0SKaike Wan twait,
176334025fb0SKaike Wan n,
176434025fb0SKaike Wan tidx);
176534025fb0SKaike Wan }
1766f48ad614SDennis Dalessandro list_del_init(&wait->list);
1767f48ad614SDennis Dalessandro waits[n++] = wait;
1768f48ad614SDennis Dalessandro }
17699aefcabeSMike Marciniszyn write_sequnlock(&sde->waitlock);
1770f48ad614SDennis Dalessandro break;
1771f48ad614SDennis Dalessandro }
17729aefcabeSMike Marciniszyn } while (read_seqretry(&sde->waitlock, seq));
1773f48ad614SDennis Dalessandro
177434025fb0SKaike Wan /* Schedule the top-priority entry first */
1775bcad2913SKaike Wan if (n)
177634025fb0SKaike Wan waits[tidx]->wakeup(waits[tidx], SDMA_AVAIL_REASON);
1777bcad2913SKaike Wan
1778f48ad614SDennis Dalessandro for (i = 0; i < n; i++)
177934025fb0SKaike Wan if (i != tidx)
1780f48ad614SDennis Dalessandro waits[i]->wakeup(waits[i], SDMA_AVAIL_REASON);
1781f48ad614SDennis Dalessandro }
1782f48ad614SDennis Dalessandro
1783f48ad614SDennis Dalessandro /* head_lock must be held */
sdma_make_progress(struct sdma_engine * sde,u64 status)1784f48ad614SDennis Dalessandro static void sdma_make_progress(struct sdma_engine *sde, u64 status)
1785f48ad614SDennis Dalessandro {
1786f48ad614SDennis Dalessandro struct sdma_txreq *txp = NULL;
1787f48ad614SDennis Dalessandro int progress = 0;
1788f48ad614SDennis Dalessandro u16 hwhead, swhead;
1789f48ad614SDennis Dalessandro int idle_check_done = 0;
1790f48ad614SDennis Dalessandro
1791f48ad614SDennis Dalessandro hwhead = sdma_gethead(sde);
1792f48ad614SDennis Dalessandro
1793f48ad614SDennis Dalessandro /* The reason for some of the complexity of this code is that
1794f48ad614SDennis Dalessandro * not all descriptors have corresponding txps. So, we have to
1795f48ad614SDennis Dalessandro * be able to skip over descs until we wander into the range of
1796f48ad614SDennis Dalessandro * the next txp on the list.
1797f48ad614SDennis Dalessandro */
1798f48ad614SDennis Dalessandro
1799f48ad614SDennis Dalessandro retry:
1800f48ad614SDennis Dalessandro txp = get_txhead(sde);
1801f48ad614SDennis Dalessandro swhead = sde->descq_head & sde->sdma_mask;
1802f48ad614SDennis Dalessandro trace_hfi1_sdma_progress(sde, hwhead, swhead, txp);
1803f48ad614SDennis Dalessandro while (swhead != hwhead) {
1804f48ad614SDennis Dalessandro /* advance head, wrap if needed */
1805f48ad614SDennis Dalessandro swhead = ++sde->descq_head & sde->sdma_mask;
1806f48ad614SDennis Dalessandro
1807f48ad614SDennis Dalessandro /* if now past this txp's descs, do the callback */
1808f48ad614SDennis Dalessandro if (txp && txp->next_descq_idx == swhead) {
1809f48ad614SDennis Dalessandro /* remove from list */
1810f48ad614SDennis Dalessandro sde->tx_ring[sde->tx_head++ & sde->sdma_mask] = NULL;
1811f48ad614SDennis Dalessandro complete_tx(sde, txp, SDMA_TXREQ_S_OK);
1812f48ad614SDennis Dalessandro /* see if there is another txp */
1813f48ad614SDennis Dalessandro txp = get_txhead(sde);
1814f48ad614SDennis Dalessandro }
1815f48ad614SDennis Dalessandro trace_hfi1_sdma_progress(sde, hwhead, swhead, txp);
1816f48ad614SDennis Dalessandro progress++;
1817f48ad614SDennis Dalessandro }
1818f48ad614SDennis Dalessandro
1819f48ad614SDennis Dalessandro /*
1820f48ad614SDennis Dalessandro * The SDMA idle interrupt is not guaranteed to be ordered with respect
1821991c4274SCai Huoqing * to updates to the dma_head location in host memory. The head
1822f48ad614SDennis Dalessandro * value read might not be fully up to date. If there are pending
1823f48ad614SDennis Dalessandro * descriptors and the SDMA idle interrupt fired then read from the
1824f48ad614SDennis Dalessandro * CSR SDMA head instead to get the latest value from the hardware.
1825f48ad614SDennis Dalessandro * The hardware SDMA head should be read at most once in this invocation
1826f48ad614SDennis Dalessandro * of sdma_make_progress(..) which is ensured by idle_check_done flag
1827f48ad614SDennis Dalessandro */
1828f48ad614SDennis Dalessandro if ((status & sde->idle_mask) && !idle_check_done) {
1829f48ad614SDennis Dalessandro u16 swtail;
1830f48ad614SDennis Dalessandro
18316aa7de05SMark Rutland swtail = READ_ONCE(sde->descq_tail) & sde->sdma_mask;
1832f48ad614SDennis Dalessandro if (swtail != hwhead) {
1833f48ad614SDennis Dalessandro hwhead = (u16)read_sde_csr(sde, SD(HEAD));
1834f48ad614SDennis Dalessandro idle_check_done = 1;
1835f48ad614SDennis Dalessandro goto retry;
1836f48ad614SDennis Dalessandro }
1837f48ad614SDennis Dalessandro }
1838f48ad614SDennis Dalessandro
1839f48ad614SDennis Dalessandro sde->last_status = status;
1840f48ad614SDennis Dalessandro if (progress)
1841f48ad614SDennis Dalessandro sdma_desc_avail(sde, sdma_descq_freecnt(sde));
1842f48ad614SDennis Dalessandro }
1843f48ad614SDennis Dalessandro
1844f48ad614SDennis Dalessandro /*
1845f48ad614SDennis Dalessandro * sdma_engine_interrupt() - interrupt handler for engine
1846f48ad614SDennis Dalessandro * @sde: sdma engine
1847f48ad614SDennis Dalessandro * @status: sdma interrupt reason
1848f48ad614SDennis Dalessandro *
1849f48ad614SDennis Dalessandro * Status is a mask of the 3 possible interrupts for this engine. It will
1850f48ad614SDennis Dalessandro * contain bits _only_ for this SDMA engine. It will contain at least one
1851f48ad614SDennis Dalessandro * bit, it may contain more.
1852f48ad614SDennis Dalessandro */
sdma_engine_interrupt(struct sdma_engine * sde,u64 status)1853f48ad614SDennis Dalessandro void sdma_engine_interrupt(struct sdma_engine *sde, u64 status)
1854f48ad614SDennis Dalessandro {
1855f48ad614SDennis Dalessandro trace_hfi1_sdma_engine_interrupt(sde, status);
1856f48ad614SDennis Dalessandro write_seqlock(&sde->head_lock);
1857f48ad614SDennis Dalessandro sdma_set_desc_cnt(sde, sdma_desct_intr);
1858f48ad614SDennis Dalessandro if (status & sde->idle_mask)
1859f48ad614SDennis Dalessandro sde->idle_int_cnt++;
1860f48ad614SDennis Dalessandro else if (status & sde->progress_mask)
1861f48ad614SDennis Dalessandro sde->progress_int_cnt++;
1862f48ad614SDennis Dalessandro else if (status & sde->int_mask)
1863f48ad614SDennis Dalessandro sde->sdma_int_cnt++;
1864f48ad614SDennis Dalessandro sdma_make_progress(sde, status);
1865f48ad614SDennis Dalessandro write_sequnlock(&sde->head_lock);
1866f48ad614SDennis Dalessandro }
1867f48ad614SDennis Dalessandro
1868f48ad614SDennis Dalessandro /**
1869f48ad614SDennis Dalessandro * sdma_engine_error() - error handler for engine
1870f48ad614SDennis Dalessandro * @sde: sdma engine
1871f48ad614SDennis Dalessandro * @status: sdma interrupt reason
1872f48ad614SDennis Dalessandro */
sdma_engine_error(struct sdma_engine * sde,u64 status)1873f48ad614SDennis Dalessandro void sdma_engine_error(struct sdma_engine *sde, u64 status)
1874f48ad614SDennis Dalessandro {
1875f48ad614SDennis Dalessandro unsigned long flags;
1876f48ad614SDennis Dalessandro
1877f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
1878f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "CONFIG SDMA(%u) error status 0x%llx state %s\n",
1879f48ad614SDennis Dalessandro sde->this_idx,
1880f48ad614SDennis Dalessandro (unsigned long long)status,
1881f48ad614SDennis Dalessandro sdma_state_names[sde->state.current_state]);
1882f48ad614SDennis Dalessandro #endif
1883f48ad614SDennis Dalessandro spin_lock_irqsave(&sde->tail_lock, flags);
1884f48ad614SDennis Dalessandro write_seqlock(&sde->head_lock);
1885f48ad614SDennis Dalessandro if (status & ALL_SDMA_ENG_HALT_ERRS)
1886f48ad614SDennis Dalessandro __sdma_process_event(sde, sdma_event_e60_hw_halted);
1887f48ad614SDennis Dalessandro if (status & ~SD(ENG_ERR_STATUS_SDMA_HALT_ERR_SMASK)) {
1888f48ad614SDennis Dalessandro dd_dev_err(sde->dd,
1889f48ad614SDennis Dalessandro "SDMA (%u) engine error: 0x%llx state %s\n",
1890f48ad614SDennis Dalessandro sde->this_idx,
1891f48ad614SDennis Dalessandro (unsigned long long)status,
1892f48ad614SDennis Dalessandro sdma_state_names[sde->state.current_state]);
1893f48ad614SDennis Dalessandro dump_sdma_state(sde);
1894f48ad614SDennis Dalessandro }
1895f48ad614SDennis Dalessandro write_sequnlock(&sde->head_lock);
1896f48ad614SDennis Dalessandro spin_unlock_irqrestore(&sde->tail_lock, flags);
1897f48ad614SDennis Dalessandro }
1898f48ad614SDennis Dalessandro
sdma_sendctrl(struct sdma_engine * sde,unsigned op)1899f48ad614SDennis Dalessandro static void sdma_sendctrl(struct sdma_engine *sde, unsigned op)
1900f48ad614SDennis Dalessandro {
1901f48ad614SDennis Dalessandro u64 set_senddmactrl = 0;
1902f48ad614SDennis Dalessandro u64 clr_senddmactrl = 0;
1903f48ad614SDennis Dalessandro unsigned long flags;
1904f48ad614SDennis Dalessandro
1905f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
1906f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "CONFIG SDMA(%u) senddmactrl E=%d I=%d H=%d C=%d\n",
1907f48ad614SDennis Dalessandro sde->this_idx,
1908f48ad614SDennis Dalessandro (op & SDMA_SENDCTRL_OP_ENABLE) ? 1 : 0,
1909f48ad614SDennis Dalessandro (op & SDMA_SENDCTRL_OP_INTENABLE) ? 1 : 0,
1910f48ad614SDennis Dalessandro (op & SDMA_SENDCTRL_OP_HALT) ? 1 : 0,
1911f48ad614SDennis Dalessandro (op & SDMA_SENDCTRL_OP_CLEANUP) ? 1 : 0);
1912f48ad614SDennis Dalessandro #endif
1913f48ad614SDennis Dalessandro
1914f48ad614SDennis Dalessandro if (op & SDMA_SENDCTRL_OP_ENABLE)
1915f48ad614SDennis Dalessandro set_senddmactrl |= SD(CTRL_SDMA_ENABLE_SMASK);
1916f48ad614SDennis Dalessandro else
1917f48ad614SDennis Dalessandro clr_senddmactrl |= SD(CTRL_SDMA_ENABLE_SMASK);
1918f48ad614SDennis Dalessandro
1919f48ad614SDennis Dalessandro if (op & SDMA_SENDCTRL_OP_INTENABLE)
1920f48ad614SDennis Dalessandro set_senddmactrl |= SD(CTRL_SDMA_INT_ENABLE_SMASK);
1921f48ad614SDennis Dalessandro else
1922f48ad614SDennis Dalessandro clr_senddmactrl |= SD(CTRL_SDMA_INT_ENABLE_SMASK);
1923f48ad614SDennis Dalessandro
1924f48ad614SDennis Dalessandro if (op & SDMA_SENDCTRL_OP_HALT)
1925f48ad614SDennis Dalessandro set_senddmactrl |= SD(CTRL_SDMA_HALT_SMASK);
1926f48ad614SDennis Dalessandro else
1927f48ad614SDennis Dalessandro clr_senddmactrl |= SD(CTRL_SDMA_HALT_SMASK);
1928f48ad614SDennis Dalessandro
1929f48ad614SDennis Dalessandro spin_lock_irqsave(&sde->senddmactrl_lock, flags);
1930f48ad614SDennis Dalessandro
1931f48ad614SDennis Dalessandro sde->p_senddmactrl |= set_senddmactrl;
1932f48ad614SDennis Dalessandro sde->p_senddmactrl &= ~clr_senddmactrl;
1933f48ad614SDennis Dalessandro
1934f48ad614SDennis Dalessandro if (op & SDMA_SENDCTRL_OP_CLEANUP)
1935f48ad614SDennis Dalessandro write_sde_csr(sde, SD(CTRL),
1936f48ad614SDennis Dalessandro sde->p_senddmactrl |
1937f48ad614SDennis Dalessandro SD(CTRL_SDMA_CLEANUP_SMASK));
1938f48ad614SDennis Dalessandro else
1939f48ad614SDennis Dalessandro write_sde_csr(sde, SD(CTRL), sde->p_senddmactrl);
1940f48ad614SDennis Dalessandro
1941f48ad614SDennis Dalessandro spin_unlock_irqrestore(&sde->senddmactrl_lock, flags);
1942f48ad614SDennis Dalessandro
1943f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
1944f48ad614SDennis Dalessandro sdma_dumpstate(sde);
1945f48ad614SDennis Dalessandro #endif
1946f48ad614SDennis Dalessandro }
1947f48ad614SDennis Dalessandro
sdma_setlengen(struct sdma_engine * sde)1948f48ad614SDennis Dalessandro static void sdma_setlengen(struct sdma_engine *sde)
1949f48ad614SDennis Dalessandro {
1950f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
1951f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n",
1952f48ad614SDennis Dalessandro sde->this_idx, slashstrip(__FILE__), __LINE__, __func__);
1953f48ad614SDennis Dalessandro #endif
1954f48ad614SDennis Dalessandro
1955f48ad614SDennis Dalessandro /*
1956f48ad614SDennis Dalessandro * Set SendDmaLenGen and clear-then-set the MSB of the generation
1957f48ad614SDennis Dalessandro * count to enable generation checking and load the internal
1958f48ad614SDennis Dalessandro * generation counter.
1959f48ad614SDennis Dalessandro */
1960f48ad614SDennis Dalessandro write_sde_csr(sde, SD(LEN_GEN),
1961f48ad614SDennis Dalessandro (sde->descq_cnt / 64) << SD(LEN_GEN_LENGTH_SHIFT));
1962f48ad614SDennis Dalessandro write_sde_csr(sde, SD(LEN_GEN),
1963f48ad614SDennis Dalessandro ((sde->descq_cnt / 64) << SD(LEN_GEN_LENGTH_SHIFT)) |
1964f48ad614SDennis Dalessandro (4ULL << SD(LEN_GEN_GENERATION_SHIFT)));
1965f48ad614SDennis Dalessandro }
1966f48ad614SDennis Dalessandro
sdma_update_tail(struct sdma_engine * sde,u16 tail)1967f48ad614SDennis Dalessandro static inline void sdma_update_tail(struct sdma_engine *sde, u16 tail)
1968f48ad614SDennis Dalessandro {
1969f48ad614SDennis Dalessandro /* Commit writes to memory and advance the tail on the chip */
1970f48ad614SDennis Dalessandro smp_wmb(); /* see get_txhead() */
1971f48ad614SDennis Dalessandro writeq(tail, sde->tail_csr);
1972f48ad614SDennis Dalessandro }
1973f48ad614SDennis Dalessandro
1974f48ad614SDennis Dalessandro /*
1975f48ad614SDennis Dalessandro * This is called when changing to state s10_hw_start_up_halt_wait as
1976f48ad614SDennis Dalessandro * a result of send buffer errors or send DMA descriptor errors.
1977f48ad614SDennis Dalessandro */
sdma_hw_start_up(struct sdma_engine * sde)1978f48ad614SDennis Dalessandro static void sdma_hw_start_up(struct sdma_engine *sde)
1979f48ad614SDennis Dalessandro {
1980f48ad614SDennis Dalessandro u64 reg;
1981f48ad614SDennis Dalessandro
1982f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
1983f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n",
1984f48ad614SDennis Dalessandro sde->this_idx, slashstrip(__FILE__), __LINE__, __func__);
1985f48ad614SDennis Dalessandro #endif
1986f48ad614SDennis Dalessandro
1987f48ad614SDennis Dalessandro sdma_setlengen(sde);
1988f48ad614SDennis Dalessandro sdma_update_tail(sde, 0); /* Set SendDmaTail */
1989f48ad614SDennis Dalessandro *sde->head_dma = 0;
1990f48ad614SDennis Dalessandro
1991f48ad614SDennis Dalessandro reg = SD(ENG_ERR_CLEAR_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_MASK) <<
1992f48ad614SDennis Dalessandro SD(ENG_ERR_CLEAR_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_SHIFT);
1993f48ad614SDennis Dalessandro write_sde_csr(sde, SD(ENG_ERR_CLEAR), reg);
1994f48ad614SDennis Dalessandro }
1995f48ad614SDennis Dalessandro
1996f48ad614SDennis Dalessandro /*
1997f48ad614SDennis Dalessandro * set_sdma_integrity
1998f48ad614SDennis Dalessandro *
1999f48ad614SDennis Dalessandro * Set the SEND_DMA_CHECK_ENABLE register for send DMA engine 'sde'.
2000f48ad614SDennis Dalessandro */
set_sdma_integrity(struct sdma_engine * sde)2001f48ad614SDennis Dalessandro static void set_sdma_integrity(struct sdma_engine *sde)
2002f48ad614SDennis Dalessandro {
2003f48ad614SDennis Dalessandro struct hfi1_devdata *dd = sde->dd;
2004f48ad614SDennis Dalessandro
2005d9ac4555SJakub Pawlak write_sde_csr(sde, SD(CHECK_ENABLE),
2006d9ac4555SJakub Pawlak hfi1_pkt_base_sdma_integrity(dd));
2007f48ad614SDennis Dalessandro }
2008f48ad614SDennis Dalessandro
init_sdma_regs(struct sdma_engine * sde,u32 credits,uint idle_cnt)2009f48ad614SDennis Dalessandro static void init_sdma_regs(
2010f48ad614SDennis Dalessandro struct sdma_engine *sde,
2011f48ad614SDennis Dalessandro u32 credits,
2012f48ad614SDennis Dalessandro uint idle_cnt)
2013f48ad614SDennis Dalessandro {
2014f48ad614SDennis Dalessandro u8 opval, opmask;
2015f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
2016f48ad614SDennis Dalessandro struct hfi1_devdata *dd = sde->dd;
2017f48ad614SDennis Dalessandro
2018f48ad614SDennis Dalessandro dd_dev_err(dd, "CONFIG SDMA(%u) %s:%d %s()\n",
2019f48ad614SDennis Dalessandro sde->this_idx, slashstrip(__FILE__), __LINE__, __func__);
2020f48ad614SDennis Dalessandro #endif
2021f48ad614SDennis Dalessandro
2022f48ad614SDennis Dalessandro write_sde_csr(sde, SD(BASE_ADDR), sde->descq_phys);
2023f48ad614SDennis Dalessandro sdma_setlengen(sde);
2024f48ad614SDennis Dalessandro sdma_update_tail(sde, 0); /* Set SendDmaTail */
2025f48ad614SDennis Dalessandro write_sde_csr(sde, SD(RELOAD_CNT), idle_cnt);
2026f48ad614SDennis Dalessandro write_sde_csr(sde, SD(DESC_CNT), 0);
2027f48ad614SDennis Dalessandro write_sde_csr(sde, SD(HEAD_ADDR), sde->head_phys);
2028f48ad614SDennis Dalessandro write_sde_csr(sde, SD(MEMORY),
2029f48ad614SDennis Dalessandro ((u64)credits << SD(MEMORY_SDMA_MEMORY_CNT_SHIFT)) |
2030f48ad614SDennis Dalessandro ((u64)(credits * sde->this_idx) <<
2031f48ad614SDennis Dalessandro SD(MEMORY_SDMA_MEMORY_INDEX_SHIFT)));
2032f48ad614SDennis Dalessandro write_sde_csr(sde, SD(ENG_ERR_MASK), ~0ull);
2033f48ad614SDennis Dalessandro set_sdma_integrity(sde);
2034f48ad614SDennis Dalessandro opmask = OPCODE_CHECK_MASK_DISABLED;
2035f48ad614SDennis Dalessandro opval = OPCODE_CHECK_VAL_DISABLED;
2036f48ad614SDennis Dalessandro write_sde_csr(sde, SD(CHECK_OPCODE),
2037f48ad614SDennis Dalessandro (opmask << SEND_CTXT_CHECK_OPCODE_MASK_SHIFT) |
2038f48ad614SDennis Dalessandro (opval << SEND_CTXT_CHECK_OPCODE_VALUE_SHIFT));
2039f48ad614SDennis Dalessandro }
2040f48ad614SDennis Dalessandro
2041f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
2042f48ad614SDennis Dalessandro
2043f48ad614SDennis Dalessandro #define sdma_dumpstate_helper0(reg) do { \
2044f48ad614SDennis Dalessandro csr = read_csr(sde->dd, reg); \
2045f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "%36s 0x%016llx\n", #reg, csr); \
2046f48ad614SDennis Dalessandro } while (0)
2047f48ad614SDennis Dalessandro
2048f48ad614SDennis Dalessandro #define sdma_dumpstate_helper(reg) do { \
2049f48ad614SDennis Dalessandro csr = read_sde_csr(sde, reg); \
2050f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "%36s[%02u] 0x%016llx\n", \
2051f48ad614SDennis Dalessandro #reg, sde->this_idx, csr); \
2052f48ad614SDennis Dalessandro } while (0)
2053f48ad614SDennis Dalessandro
2054f48ad614SDennis Dalessandro #define sdma_dumpstate_helper2(reg) do { \
2055f48ad614SDennis Dalessandro csr = read_csr(sde->dd, reg + (8 * i)); \
2056f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "%33s_%02u 0x%016llx\n", \
2057f48ad614SDennis Dalessandro #reg, i, csr); \
2058f48ad614SDennis Dalessandro } while (0)
2059f48ad614SDennis Dalessandro
sdma_dumpstate(struct sdma_engine * sde)2060f48ad614SDennis Dalessandro void sdma_dumpstate(struct sdma_engine *sde)
2061f48ad614SDennis Dalessandro {
2062f48ad614SDennis Dalessandro u64 csr;
2063f48ad614SDennis Dalessandro unsigned i;
2064f48ad614SDennis Dalessandro
2065f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(CTRL));
2066f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(STATUS));
2067f48ad614SDennis Dalessandro sdma_dumpstate_helper0(SD(ERR_STATUS));
2068f48ad614SDennis Dalessandro sdma_dumpstate_helper0(SD(ERR_MASK));
2069f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(ENG_ERR_STATUS));
2070f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(ENG_ERR_MASK));
2071f48ad614SDennis Dalessandro
2072f48ad614SDennis Dalessandro for (i = 0; i < CCE_NUM_INT_CSRS; ++i) {
2073f48ad614SDennis Dalessandro sdma_dumpstate_helper2(CCE_INT_STATUS);
2074f48ad614SDennis Dalessandro sdma_dumpstate_helper2(CCE_INT_MASK);
2075f48ad614SDennis Dalessandro sdma_dumpstate_helper2(CCE_INT_BLOCKED);
2076f48ad614SDennis Dalessandro }
2077f48ad614SDennis Dalessandro
2078f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(TAIL));
2079f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(HEAD));
2080f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(PRIORITY_THLD));
2081f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(IDLE_CNT));
2082f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(RELOAD_CNT));
2083f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(DESC_CNT));
2084f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(DESC_FETCHED_CNT));
2085f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(MEMORY));
2086f48ad614SDennis Dalessandro sdma_dumpstate_helper0(SD(ENGINES));
2087f48ad614SDennis Dalessandro sdma_dumpstate_helper0(SD(MEM_SIZE));
2088f48ad614SDennis Dalessandro /* sdma_dumpstate_helper(SEND_EGRESS_SEND_DMA_STATUS); */
2089f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(BASE_ADDR));
2090f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(LEN_GEN));
2091f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(HEAD_ADDR));
2092f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(CHECK_ENABLE));
2093f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(CHECK_VL));
2094f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(CHECK_JOB_KEY));
2095f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(CHECK_PARTITION_KEY));
2096f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(CHECK_SLID));
2097f48ad614SDennis Dalessandro sdma_dumpstate_helper(SD(CHECK_OPCODE));
2098f48ad614SDennis Dalessandro }
2099f48ad614SDennis Dalessandro #endif
2100f48ad614SDennis Dalessandro
dump_sdma_state(struct sdma_engine * sde)2101f48ad614SDennis Dalessandro static void dump_sdma_state(struct sdma_engine *sde)
2102f48ad614SDennis Dalessandro {
2103f48ad614SDennis Dalessandro struct hw_sdma_desc *descqp;
2104f48ad614SDennis Dalessandro u64 desc[2];
2105f48ad614SDennis Dalessandro u64 addr;
2106f48ad614SDennis Dalessandro u8 gen;
2107f48ad614SDennis Dalessandro u16 len;
2108f48ad614SDennis Dalessandro u16 head, tail, cnt;
2109f48ad614SDennis Dalessandro
2110f48ad614SDennis Dalessandro head = sde->descq_head & sde->sdma_mask;
2111f48ad614SDennis Dalessandro tail = sde->descq_tail & sde->sdma_mask;
2112f48ad614SDennis Dalessandro cnt = sdma_descq_freecnt(sde);
2113f48ad614SDennis Dalessandro
2114f48ad614SDennis Dalessandro dd_dev_err(sde->dd,
2115f48ad614SDennis Dalessandro "SDMA (%u) descq_head: %u descq_tail: %u freecnt: %u FLE %d\n",
2116f48ad614SDennis Dalessandro sde->this_idx, head, tail, cnt,
2117f48ad614SDennis Dalessandro !list_empty(&sde->flushlist));
2118f48ad614SDennis Dalessandro
2119f48ad614SDennis Dalessandro /* print info for each entry in the descriptor queue */
2120f48ad614SDennis Dalessandro while (head != tail) {
2121f48ad614SDennis Dalessandro char flags[6] = { 'x', 'x', 'x', 'x', 0 };
2122f48ad614SDennis Dalessandro
2123f48ad614SDennis Dalessandro descqp = &sde->descq[head];
2124f48ad614SDennis Dalessandro desc[0] = le64_to_cpu(descqp->qw[0]);
2125f48ad614SDennis Dalessandro desc[1] = le64_to_cpu(descqp->qw[1]);
2126f48ad614SDennis Dalessandro flags[0] = (desc[1] & SDMA_DESC1_INT_REQ_FLAG) ? 'I' : '-';
2127f48ad614SDennis Dalessandro flags[1] = (desc[1] & SDMA_DESC1_HEAD_TO_HOST_FLAG) ?
2128f48ad614SDennis Dalessandro 'H' : '-';
2129f48ad614SDennis Dalessandro flags[2] = (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG) ? 'F' : '-';
2130f48ad614SDennis Dalessandro flags[3] = (desc[0] & SDMA_DESC0_LAST_DESC_FLAG) ? 'L' : '-';
2131f48ad614SDennis Dalessandro addr = (desc[0] >> SDMA_DESC0_PHY_ADDR_SHIFT)
2132f48ad614SDennis Dalessandro & SDMA_DESC0_PHY_ADDR_MASK;
2133f48ad614SDennis Dalessandro gen = (desc[1] >> SDMA_DESC1_GENERATION_SHIFT)
2134f48ad614SDennis Dalessandro & SDMA_DESC1_GENERATION_MASK;
2135f48ad614SDennis Dalessandro len = (desc[0] >> SDMA_DESC0_BYTE_COUNT_SHIFT)
2136f48ad614SDennis Dalessandro & SDMA_DESC0_BYTE_COUNT_MASK;
2137f48ad614SDennis Dalessandro dd_dev_err(sde->dd,
2138f48ad614SDennis Dalessandro "SDMA sdmadesc[%u]: flags:%s addr:0x%016llx gen:%u len:%u bytes\n",
2139f48ad614SDennis Dalessandro head, flags, addr, gen, len);
2140f48ad614SDennis Dalessandro dd_dev_err(sde->dd,
2141f48ad614SDennis Dalessandro "\tdesc0:0x%016llx desc1 0x%016llx\n",
2142f48ad614SDennis Dalessandro desc[0], desc[1]);
2143f48ad614SDennis Dalessandro if (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG)
2144f48ad614SDennis Dalessandro dd_dev_err(sde->dd,
2145f48ad614SDennis Dalessandro "\taidx: %u amode: %u alen: %u\n",
2146f48ad614SDennis Dalessandro (u8)((desc[1] &
2147f48ad614SDennis Dalessandro SDMA_DESC1_HEADER_INDEX_SMASK) >>
2148f48ad614SDennis Dalessandro SDMA_DESC1_HEADER_INDEX_SHIFT),
2149f48ad614SDennis Dalessandro (u8)((desc[1] &
2150f48ad614SDennis Dalessandro SDMA_DESC1_HEADER_MODE_SMASK) >>
2151f48ad614SDennis Dalessandro SDMA_DESC1_HEADER_MODE_SHIFT),
2152f48ad614SDennis Dalessandro (u8)((desc[1] &
2153f48ad614SDennis Dalessandro SDMA_DESC1_HEADER_DWS_SMASK) >>
2154f48ad614SDennis Dalessandro SDMA_DESC1_HEADER_DWS_SHIFT));
2155f48ad614SDennis Dalessandro head++;
2156f48ad614SDennis Dalessandro head &= sde->sdma_mask;
2157f48ad614SDennis Dalessandro }
2158f48ad614SDennis Dalessandro }
2159f48ad614SDennis Dalessandro
2160f48ad614SDennis Dalessandro #define SDE_FMT \
2161f48ad614SDennis Dalessandro "SDE %u CPU %d STE %s C 0x%llx S 0x%016llx E 0x%llx T(HW) 0x%llx T(SW) 0x%x H(HW) 0x%llx H(SW) 0x%x H(D) 0x%llx DM 0x%llx GL 0x%llx R 0x%llx LIS 0x%llx AHGI 0x%llx TXT %u TXH %u DT %u DH %u FLNE %d DQF %u SLC 0x%llx\n"
2162f48ad614SDennis Dalessandro /**
2163f48ad614SDennis Dalessandro * sdma_seqfile_dump_sde() - debugfs dump of sde
2164f48ad614SDennis Dalessandro * @s: seq file
2165f48ad614SDennis Dalessandro * @sde: send dma engine to dump
2166f48ad614SDennis Dalessandro *
2167f48ad614SDennis Dalessandro * This routine dumps the sde to the indicated seq file.
2168f48ad614SDennis Dalessandro */
sdma_seqfile_dump_sde(struct seq_file * s,struct sdma_engine * sde)2169f48ad614SDennis Dalessandro void sdma_seqfile_dump_sde(struct seq_file *s, struct sdma_engine *sde)
2170f48ad614SDennis Dalessandro {
2171f48ad614SDennis Dalessandro u16 head, tail;
2172f48ad614SDennis Dalessandro struct hw_sdma_desc *descqp;
2173f48ad614SDennis Dalessandro u64 desc[2];
2174f48ad614SDennis Dalessandro u64 addr;
2175f48ad614SDennis Dalessandro u8 gen;
2176f48ad614SDennis Dalessandro u16 len;
2177f48ad614SDennis Dalessandro
2178f48ad614SDennis Dalessandro head = sde->descq_head & sde->sdma_mask;
21796aa7de05SMark Rutland tail = READ_ONCE(sde->descq_tail) & sde->sdma_mask;
2180f48ad614SDennis Dalessandro seq_printf(s, SDE_FMT, sde->this_idx,
2181f48ad614SDennis Dalessandro sde->cpu,
2182f48ad614SDennis Dalessandro sdma_state_name(sde->state.current_state),
2183f48ad614SDennis Dalessandro (unsigned long long)read_sde_csr(sde, SD(CTRL)),
2184f48ad614SDennis Dalessandro (unsigned long long)read_sde_csr(sde, SD(STATUS)),
2185f48ad614SDennis Dalessandro (unsigned long long)read_sde_csr(sde, SD(ENG_ERR_STATUS)),
2186f48ad614SDennis Dalessandro (unsigned long long)read_sde_csr(sde, SD(TAIL)), tail,
2187f48ad614SDennis Dalessandro (unsigned long long)read_sde_csr(sde, SD(HEAD)), head,
2188f48ad614SDennis Dalessandro (unsigned long long)le64_to_cpu(*sde->head_dma),
2189f48ad614SDennis Dalessandro (unsigned long long)read_sde_csr(sde, SD(MEMORY)),
2190f48ad614SDennis Dalessandro (unsigned long long)read_sde_csr(sde, SD(LEN_GEN)),
2191f48ad614SDennis Dalessandro (unsigned long long)read_sde_csr(sde, SD(RELOAD_CNT)),
2192f48ad614SDennis Dalessandro (unsigned long long)sde->last_status,
2193f48ad614SDennis Dalessandro (unsigned long long)sde->ahg_bits,
2194f48ad614SDennis Dalessandro sde->tx_tail,
2195f48ad614SDennis Dalessandro sde->tx_head,
2196f48ad614SDennis Dalessandro sde->descq_tail,
2197f48ad614SDennis Dalessandro sde->descq_head,
2198f48ad614SDennis Dalessandro !list_empty(&sde->flushlist),
2199f48ad614SDennis Dalessandro sde->descq_full_count,
2200f48ad614SDennis Dalessandro (unsigned long long)read_sde_csr(sde, SEND_DMA_CHECK_SLID));
2201f48ad614SDennis Dalessandro
2202f48ad614SDennis Dalessandro /* print info for each entry in the descriptor queue */
2203f48ad614SDennis Dalessandro while (head != tail) {
2204f48ad614SDennis Dalessandro char flags[6] = { 'x', 'x', 'x', 'x', 0 };
2205f48ad614SDennis Dalessandro
2206f48ad614SDennis Dalessandro descqp = &sde->descq[head];
2207f48ad614SDennis Dalessandro desc[0] = le64_to_cpu(descqp->qw[0]);
2208f48ad614SDennis Dalessandro desc[1] = le64_to_cpu(descqp->qw[1]);
2209f48ad614SDennis Dalessandro flags[0] = (desc[1] & SDMA_DESC1_INT_REQ_FLAG) ? 'I' : '-';
2210f48ad614SDennis Dalessandro flags[1] = (desc[1] & SDMA_DESC1_HEAD_TO_HOST_FLAG) ?
2211f48ad614SDennis Dalessandro 'H' : '-';
2212f48ad614SDennis Dalessandro flags[2] = (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG) ? 'F' : '-';
2213f48ad614SDennis Dalessandro flags[3] = (desc[0] & SDMA_DESC0_LAST_DESC_FLAG) ? 'L' : '-';
2214f48ad614SDennis Dalessandro addr = (desc[0] >> SDMA_DESC0_PHY_ADDR_SHIFT)
2215f48ad614SDennis Dalessandro & SDMA_DESC0_PHY_ADDR_MASK;
2216f48ad614SDennis Dalessandro gen = (desc[1] >> SDMA_DESC1_GENERATION_SHIFT)
2217f48ad614SDennis Dalessandro & SDMA_DESC1_GENERATION_MASK;
2218f48ad614SDennis Dalessandro len = (desc[0] >> SDMA_DESC0_BYTE_COUNT_SHIFT)
2219f48ad614SDennis Dalessandro & SDMA_DESC0_BYTE_COUNT_MASK;
2220f48ad614SDennis Dalessandro seq_printf(s,
2221f48ad614SDennis Dalessandro "\tdesc[%u]: flags:%s addr:0x%016llx gen:%u len:%u bytes\n",
2222f48ad614SDennis Dalessandro head, flags, addr, gen, len);
2223f48ad614SDennis Dalessandro if (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG)
2224f48ad614SDennis Dalessandro seq_printf(s, "\t\tahgidx: %u ahgmode: %u\n",
2225f48ad614SDennis Dalessandro (u8)((desc[1] &
2226f48ad614SDennis Dalessandro SDMA_DESC1_HEADER_INDEX_SMASK) >>
2227f48ad614SDennis Dalessandro SDMA_DESC1_HEADER_INDEX_SHIFT),
2228f48ad614SDennis Dalessandro (u8)((desc[1] &
2229f48ad614SDennis Dalessandro SDMA_DESC1_HEADER_MODE_SMASK) >>
2230f48ad614SDennis Dalessandro SDMA_DESC1_HEADER_MODE_SHIFT));
2231f48ad614SDennis Dalessandro head = (head + 1) & sde->sdma_mask;
2232f48ad614SDennis Dalessandro }
2233f48ad614SDennis Dalessandro }
2234f48ad614SDennis Dalessandro
2235f48ad614SDennis Dalessandro /*
2236f48ad614SDennis Dalessandro * add the generation number into
2237f48ad614SDennis Dalessandro * the qw1 and return
2238f48ad614SDennis Dalessandro */
add_gen(struct sdma_engine * sde,u64 qw1)2239f48ad614SDennis Dalessandro static inline u64 add_gen(struct sdma_engine *sde, u64 qw1)
2240f48ad614SDennis Dalessandro {
2241f48ad614SDennis Dalessandro u8 generation = (sde->descq_tail >> sde->sdma_shift) & 3;
2242f48ad614SDennis Dalessandro
2243f48ad614SDennis Dalessandro qw1 &= ~SDMA_DESC1_GENERATION_SMASK;
2244f48ad614SDennis Dalessandro qw1 |= ((u64)generation & SDMA_DESC1_GENERATION_MASK)
2245f48ad614SDennis Dalessandro << SDMA_DESC1_GENERATION_SHIFT;
2246f48ad614SDennis Dalessandro return qw1;
2247f48ad614SDennis Dalessandro }
2248f48ad614SDennis Dalessandro
2249f48ad614SDennis Dalessandro /*
2250f48ad614SDennis Dalessandro * This routine submits the indicated tx
2251f48ad614SDennis Dalessandro *
2252f48ad614SDennis Dalessandro * Space has already been guaranteed and
2253f48ad614SDennis Dalessandro * tail side of ring is locked.
2254f48ad614SDennis Dalessandro *
2255f48ad614SDennis Dalessandro * The hardware tail update is done
2256f48ad614SDennis Dalessandro * in the caller and that is facilitated
2257f48ad614SDennis Dalessandro * by returning the new tail.
2258f48ad614SDennis Dalessandro *
2259f48ad614SDennis Dalessandro * There is special case logic for ahg
2260f48ad614SDennis Dalessandro * to not add the generation number for
2261f48ad614SDennis Dalessandro * up to 2 descriptors that follow the
2262f48ad614SDennis Dalessandro * first descriptor.
2263f48ad614SDennis Dalessandro *
2264f48ad614SDennis Dalessandro */
submit_tx(struct sdma_engine * sde,struct sdma_txreq * tx)2265f48ad614SDennis Dalessandro static inline u16 submit_tx(struct sdma_engine *sde, struct sdma_txreq *tx)
2266f48ad614SDennis Dalessandro {
2267f48ad614SDennis Dalessandro int i;
2268f48ad614SDennis Dalessandro u16 tail;
2269f48ad614SDennis Dalessandro struct sdma_desc *descp = tx->descp;
2270f48ad614SDennis Dalessandro u8 skip = 0, mode = ahg_mode(tx);
2271f48ad614SDennis Dalessandro
2272f48ad614SDennis Dalessandro tail = sde->descq_tail & sde->sdma_mask;
2273f48ad614SDennis Dalessandro sde->descq[tail].qw[0] = cpu_to_le64(descp->qw[0]);
2274f48ad614SDennis Dalessandro sde->descq[tail].qw[1] = cpu_to_le64(add_gen(sde, descp->qw[1]));
2275f48ad614SDennis Dalessandro trace_hfi1_sdma_descriptor(sde, descp->qw[0], descp->qw[1],
2276f48ad614SDennis Dalessandro tail, &sde->descq[tail]);
2277f48ad614SDennis Dalessandro tail = ++sde->descq_tail & sde->sdma_mask;
2278f48ad614SDennis Dalessandro descp++;
2279f48ad614SDennis Dalessandro if (mode > SDMA_AHG_APPLY_UPDATE1)
2280f48ad614SDennis Dalessandro skip = mode >> 1;
2281f48ad614SDennis Dalessandro for (i = 1; i < tx->num_desc; i++, descp++) {
2282f48ad614SDennis Dalessandro u64 qw1;
2283f48ad614SDennis Dalessandro
2284f48ad614SDennis Dalessandro sde->descq[tail].qw[0] = cpu_to_le64(descp->qw[0]);
2285f48ad614SDennis Dalessandro if (skip) {
2286f48ad614SDennis Dalessandro /* edits don't have generation */
2287f48ad614SDennis Dalessandro qw1 = descp->qw[1];
2288f48ad614SDennis Dalessandro skip--;
2289f48ad614SDennis Dalessandro } else {
2290f48ad614SDennis Dalessandro /* replace generation with real one for non-edits */
2291f48ad614SDennis Dalessandro qw1 = add_gen(sde, descp->qw[1]);
2292f48ad614SDennis Dalessandro }
2293f48ad614SDennis Dalessandro sde->descq[tail].qw[1] = cpu_to_le64(qw1);
2294f48ad614SDennis Dalessandro trace_hfi1_sdma_descriptor(sde, descp->qw[0], qw1,
2295f48ad614SDennis Dalessandro tail, &sde->descq[tail]);
2296f48ad614SDennis Dalessandro tail = ++sde->descq_tail & sde->sdma_mask;
2297f48ad614SDennis Dalessandro }
2298f48ad614SDennis Dalessandro tx->next_descq_idx = tail;
2299f48ad614SDennis Dalessandro #ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
2300f48ad614SDennis Dalessandro tx->sn = sde->tail_sn++;
2301f48ad614SDennis Dalessandro trace_hfi1_sdma_in_sn(sde, tx->sn);
2302f48ad614SDennis Dalessandro WARN_ON_ONCE(sde->tx_ring[sde->tx_tail & sde->sdma_mask]);
2303f48ad614SDennis Dalessandro #endif
2304f48ad614SDennis Dalessandro sde->tx_ring[sde->tx_tail++ & sde->sdma_mask] = tx;
2305f48ad614SDennis Dalessandro sde->desc_avail -= tx->num_desc;
2306f48ad614SDennis Dalessandro return tail;
2307f48ad614SDennis Dalessandro }
2308f48ad614SDennis Dalessandro
2309f48ad614SDennis Dalessandro /*
2310f48ad614SDennis Dalessandro * Check for progress
2311f48ad614SDennis Dalessandro */
sdma_check_progress(struct sdma_engine * sde,struct iowait_work * wait,struct sdma_txreq * tx,bool pkts_sent)2312f48ad614SDennis Dalessandro static int sdma_check_progress(
2313f48ad614SDennis Dalessandro struct sdma_engine *sde,
23145da0fc9dSDennis Dalessandro struct iowait_work *wait,
2315bcad2913SKaike Wan struct sdma_txreq *tx,
2316bcad2913SKaike Wan bool pkts_sent)
2317f48ad614SDennis Dalessandro {
2318f48ad614SDennis Dalessandro int ret;
2319f48ad614SDennis Dalessandro
2320f48ad614SDennis Dalessandro sde->desc_avail = sdma_descq_freecnt(sde);
2321f48ad614SDennis Dalessandro if (tx->num_desc <= sde->desc_avail)
2322f48ad614SDennis Dalessandro return -EAGAIN;
2323f48ad614SDennis Dalessandro /* pulse the head_lock */
23245da0fc9dSDennis Dalessandro if (wait && iowait_ioww_to_iow(wait)->sleep) {
2325f48ad614SDennis Dalessandro unsigned seq;
2326f48ad614SDennis Dalessandro
2327f48ad614SDennis Dalessandro seq = raw_seqcount_begin(
2328f48ad614SDennis Dalessandro (const seqcount_t *)&sde->head_lock.seqcount);
23295da0fc9dSDennis Dalessandro ret = wait->iow->sleep(sde, wait, tx, seq, pkts_sent);
2330f48ad614SDennis Dalessandro if (ret == -EAGAIN)
2331f48ad614SDennis Dalessandro sde->desc_avail = sdma_descq_freecnt(sde);
2332f48ad614SDennis Dalessandro } else {
2333f48ad614SDennis Dalessandro ret = -EBUSY;
2334f48ad614SDennis Dalessandro }
2335f48ad614SDennis Dalessandro return ret;
2336f48ad614SDennis Dalessandro }
2337f48ad614SDennis Dalessandro
2338f48ad614SDennis Dalessandro /**
2339f48ad614SDennis Dalessandro * sdma_send_txreq() - submit a tx req to ring
2340f48ad614SDennis Dalessandro * @sde: sdma engine to use
23415da0fc9dSDennis Dalessandro * @wait: SE wait structure to use when full (may be NULL)
2342f48ad614SDennis Dalessandro * @tx: sdma_txreq to submit
2343bcad2913SKaike Wan * @pkts_sent: has any packet been sent yet?
2344f48ad614SDennis Dalessandro *
2345f48ad614SDennis Dalessandro * The call submits the tx into the ring. If a iowait structure is non-NULL
2346f48ad614SDennis Dalessandro * the packet will be queued to the list in wait.
2347f48ad614SDennis Dalessandro *
2348f48ad614SDennis Dalessandro * Return:
2349f48ad614SDennis Dalessandro * 0 - Success, -EINVAL - sdma_txreq incomplete, -EBUSY - no space in
2350f48ad614SDennis Dalessandro * ring (wait == NULL)
2351f48ad614SDennis Dalessandro * -EIOCBQUEUED - tx queued to iowait, -ECOMM bad sdma state
2352f48ad614SDennis Dalessandro */
sdma_send_txreq(struct sdma_engine * sde,struct iowait_work * wait,struct sdma_txreq * tx,bool pkts_sent)2353f48ad614SDennis Dalessandro int sdma_send_txreq(struct sdma_engine *sde,
23545da0fc9dSDennis Dalessandro struct iowait_work *wait,
2355bcad2913SKaike Wan struct sdma_txreq *tx,
2356bcad2913SKaike Wan bool pkts_sent)
2357f48ad614SDennis Dalessandro {
2358f48ad614SDennis Dalessandro int ret = 0;
2359f48ad614SDennis Dalessandro u16 tail;
2360f48ad614SDennis Dalessandro unsigned long flags;
2361f48ad614SDennis Dalessandro
2362f48ad614SDennis Dalessandro /* user should have supplied entire packet */
2363f48ad614SDennis Dalessandro if (unlikely(tx->tlen))
2364f48ad614SDennis Dalessandro return -EINVAL;
23655da0fc9dSDennis Dalessandro tx->wait = iowait_ioww_to_iow(wait);
2366f48ad614SDennis Dalessandro spin_lock_irqsave(&sde->tail_lock, flags);
2367f48ad614SDennis Dalessandro retry:
2368f48ad614SDennis Dalessandro if (unlikely(!__sdma_running(sde)))
2369f48ad614SDennis Dalessandro goto unlock_noconn;
2370f48ad614SDennis Dalessandro if (unlikely(tx->num_desc > sde->desc_avail))
2371f48ad614SDennis Dalessandro goto nodesc;
2372f48ad614SDennis Dalessandro tail = submit_tx(sde, tx);
2373f48ad614SDennis Dalessandro if (wait)
23745da0fc9dSDennis Dalessandro iowait_sdma_inc(iowait_ioww_to_iow(wait));
2375f48ad614SDennis Dalessandro sdma_update_tail(sde, tail);
2376f48ad614SDennis Dalessandro unlock:
2377f48ad614SDennis Dalessandro spin_unlock_irqrestore(&sde->tail_lock, flags);
2378f48ad614SDennis Dalessandro return ret;
2379f48ad614SDennis Dalessandro unlock_noconn:
2380f48ad614SDennis Dalessandro if (wait)
23815da0fc9dSDennis Dalessandro iowait_sdma_inc(iowait_ioww_to_iow(wait));
2382f48ad614SDennis Dalessandro tx->next_descq_idx = 0;
2383f48ad614SDennis Dalessandro #ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
2384f48ad614SDennis Dalessandro tx->sn = sde->tail_sn++;
2385f48ad614SDennis Dalessandro trace_hfi1_sdma_in_sn(sde, tx->sn);
2386f48ad614SDennis Dalessandro #endif
2387f48ad614SDennis Dalessandro spin_lock(&sde->flushlist_lock);
2388f48ad614SDennis Dalessandro list_add_tail(&tx->list, &sde->flushlist);
2389f48ad614SDennis Dalessandro spin_unlock(&sde->flushlist_lock);
23905da0fc9dSDennis Dalessandro iowait_inc_wait_count(wait, tx->num_desc);
2391cf131a81SMike Marciniszyn queue_work_on(sde->cpu, system_highpri_wq, &sde->flush_worker);
2392f48ad614SDennis Dalessandro ret = -ECOMM;
2393f48ad614SDennis Dalessandro goto unlock;
2394f48ad614SDennis Dalessandro nodesc:
2395bcad2913SKaike Wan ret = sdma_check_progress(sde, wait, tx, pkts_sent);
2396f48ad614SDennis Dalessandro if (ret == -EAGAIN) {
2397f48ad614SDennis Dalessandro ret = 0;
2398f48ad614SDennis Dalessandro goto retry;
2399f48ad614SDennis Dalessandro }
2400f48ad614SDennis Dalessandro sde->descq_full_count++;
2401f48ad614SDennis Dalessandro goto unlock;
2402f48ad614SDennis Dalessandro }
2403f48ad614SDennis Dalessandro
2404f48ad614SDennis Dalessandro /**
2405f48ad614SDennis Dalessandro * sdma_send_txlist() - submit a list of tx req to ring
2406f48ad614SDennis Dalessandro * @sde: sdma engine to use
24075da0fc9dSDennis Dalessandro * @wait: SE wait structure to use when full (may be NULL)
2408f48ad614SDennis Dalessandro * @tx_list: list of sdma_txreqs to submit
2409d7480310SLee Jones * @count_out: pointer to a u16 which, after return will contain the total number of
24100b115ef1SHarish Chegondi * sdma_txreqs removed from the tx_list. This will include sdma_txreqs
24110b115ef1SHarish Chegondi * whose SDMA descriptors are submitted to the ring and the sdma_txreqs
24120b115ef1SHarish Chegondi * which are added to SDMA engine flush list if the SDMA engine state is
24130b115ef1SHarish Chegondi * not running.
2414f48ad614SDennis Dalessandro *
2415f48ad614SDennis Dalessandro * The call submits the list into the ring.
2416f48ad614SDennis Dalessandro *
2417f48ad614SDennis Dalessandro * If the iowait structure is non-NULL and not equal to the iowait list
2418f48ad614SDennis Dalessandro * the unprocessed part of the list will be appended to the list in wait.
2419f48ad614SDennis Dalessandro *
2420f48ad614SDennis Dalessandro * In all cases, the tx_list will be updated so the head of the tx_list is
2421f48ad614SDennis Dalessandro * the list of descriptors that have yet to be transmitted.
2422f48ad614SDennis Dalessandro *
2423f48ad614SDennis Dalessandro * The intent of this call is to provide a more efficient
2424f48ad614SDennis Dalessandro * way of submitting multiple packets to SDMA while holding the tail
2425f48ad614SDennis Dalessandro * side locking.
2426f48ad614SDennis Dalessandro *
2427f48ad614SDennis Dalessandro * Return:
24280b115ef1SHarish Chegondi * 0 - Success,
2429f48ad614SDennis Dalessandro * -EINVAL - sdma_txreq incomplete, -EBUSY - no space in ring (wait == NULL)
2430f48ad614SDennis Dalessandro * -EIOCBQUEUED - tx queued to iowait, -ECOMM bad sdma state
2431f48ad614SDennis Dalessandro */
sdma_send_txlist(struct sdma_engine * sde,struct iowait_work * wait,struct list_head * tx_list,u16 * count_out)24325da0fc9dSDennis Dalessandro int sdma_send_txlist(struct sdma_engine *sde, struct iowait_work *wait,
24333ca633f1SMichael J. Ruhl struct list_head *tx_list, u16 *count_out)
2434f48ad614SDennis Dalessandro {
2435f48ad614SDennis Dalessandro struct sdma_txreq *tx, *tx_next;
2436f48ad614SDennis Dalessandro int ret = 0;
2437f48ad614SDennis Dalessandro unsigned long flags;
2438f48ad614SDennis Dalessandro u16 tail = INVALID_TAIL;
24390b115ef1SHarish Chegondi u32 submit_count = 0, flush_count = 0, total_count;
2440f48ad614SDennis Dalessandro
2441f48ad614SDennis Dalessandro spin_lock_irqsave(&sde->tail_lock, flags);
2442f48ad614SDennis Dalessandro retry:
2443f48ad614SDennis Dalessandro list_for_each_entry_safe(tx, tx_next, tx_list, list) {
24445da0fc9dSDennis Dalessandro tx->wait = iowait_ioww_to_iow(wait);
2445f48ad614SDennis Dalessandro if (unlikely(!__sdma_running(sde)))
2446f48ad614SDennis Dalessandro goto unlock_noconn;
2447f48ad614SDennis Dalessandro if (unlikely(tx->num_desc > sde->desc_avail))
2448f48ad614SDennis Dalessandro goto nodesc;
2449f48ad614SDennis Dalessandro if (unlikely(tx->tlen)) {
2450f48ad614SDennis Dalessandro ret = -EINVAL;
2451f48ad614SDennis Dalessandro goto update_tail;
2452f48ad614SDennis Dalessandro }
2453f48ad614SDennis Dalessandro list_del_init(&tx->list);
2454f48ad614SDennis Dalessandro tail = submit_tx(sde, tx);
24550b115ef1SHarish Chegondi submit_count++;
2456f48ad614SDennis Dalessandro if (tail != INVALID_TAIL &&
24570b115ef1SHarish Chegondi (submit_count & SDMA_TAIL_UPDATE_THRESH) == 0) {
2458f48ad614SDennis Dalessandro sdma_update_tail(sde, tail);
2459f48ad614SDennis Dalessandro tail = INVALID_TAIL;
2460f48ad614SDennis Dalessandro }
2461f48ad614SDennis Dalessandro }
2462f48ad614SDennis Dalessandro update_tail:
24630b115ef1SHarish Chegondi total_count = submit_count + flush_count;
2464bcad2913SKaike Wan if (wait) {
24655da0fc9dSDennis Dalessandro iowait_sdma_add(iowait_ioww_to_iow(wait), total_count);
24665da0fc9dSDennis Dalessandro iowait_starve_clear(submit_count > 0,
24675da0fc9dSDennis Dalessandro iowait_ioww_to_iow(wait));
2468bcad2913SKaike Wan }
2469f48ad614SDennis Dalessandro if (tail != INVALID_TAIL)
2470f48ad614SDennis Dalessandro sdma_update_tail(sde, tail);
2471f48ad614SDennis Dalessandro spin_unlock_irqrestore(&sde->tail_lock, flags);
24720b115ef1SHarish Chegondi *count_out = total_count;
24730b115ef1SHarish Chegondi return ret;
2474f48ad614SDennis Dalessandro unlock_noconn:
2475f48ad614SDennis Dalessandro spin_lock(&sde->flushlist_lock);
2476f48ad614SDennis Dalessandro list_for_each_entry_safe(tx, tx_next, tx_list, list) {
24775da0fc9dSDennis Dalessandro tx->wait = iowait_ioww_to_iow(wait);
2478f48ad614SDennis Dalessandro list_del_init(&tx->list);
2479f48ad614SDennis Dalessandro tx->next_descq_idx = 0;
2480f48ad614SDennis Dalessandro #ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER
2481f48ad614SDennis Dalessandro tx->sn = sde->tail_sn++;
2482f48ad614SDennis Dalessandro trace_hfi1_sdma_in_sn(sde, tx->sn);
2483f48ad614SDennis Dalessandro #endif
2484f48ad614SDennis Dalessandro list_add_tail(&tx->list, &sde->flushlist);
24850b115ef1SHarish Chegondi flush_count++;
24865da0fc9dSDennis Dalessandro iowait_inc_wait_count(wait, tx->num_desc);
2487f48ad614SDennis Dalessandro }
2488f48ad614SDennis Dalessandro spin_unlock(&sde->flushlist_lock);
2489cf131a81SMike Marciniszyn queue_work_on(sde->cpu, system_highpri_wq, &sde->flush_worker);
2490f48ad614SDennis Dalessandro ret = -ECOMM;
2491f48ad614SDennis Dalessandro goto update_tail;
2492f48ad614SDennis Dalessandro nodesc:
2493bcad2913SKaike Wan ret = sdma_check_progress(sde, wait, tx, submit_count > 0);
2494f48ad614SDennis Dalessandro if (ret == -EAGAIN) {
2495f48ad614SDennis Dalessandro ret = 0;
2496f48ad614SDennis Dalessandro goto retry;
2497f48ad614SDennis Dalessandro }
2498f48ad614SDennis Dalessandro sde->descq_full_count++;
2499f48ad614SDennis Dalessandro goto update_tail;
2500f48ad614SDennis Dalessandro }
2501f48ad614SDennis Dalessandro
sdma_process_event(struct sdma_engine * sde,enum sdma_events event)2502f48ad614SDennis Dalessandro static void sdma_process_event(struct sdma_engine *sde, enum sdma_events event)
2503f48ad614SDennis Dalessandro {
2504f48ad614SDennis Dalessandro unsigned long flags;
2505f48ad614SDennis Dalessandro
2506f48ad614SDennis Dalessandro spin_lock_irqsave(&sde->tail_lock, flags);
2507f48ad614SDennis Dalessandro write_seqlock(&sde->head_lock);
2508f48ad614SDennis Dalessandro
2509f48ad614SDennis Dalessandro __sdma_process_event(sde, event);
2510f48ad614SDennis Dalessandro
2511f48ad614SDennis Dalessandro if (sde->state.current_state == sdma_state_s99_running)
2512f48ad614SDennis Dalessandro sdma_desc_avail(sde, sdma_descq_freecnt(sde));
2513f48ad614SDennis Dalessandro
2514f48ad614SDennis Dalessandro write_sequnlock(&sde->head_lock);
2515f48ad614SDennis Dalessandro spin_unlock_irqrestore(&sde->tail_lock, flags);
2516f48ad614SDennis Dalessandro }
2517f48ad614SDennis Dalessandro
__sdma_process_event(struct sdma_engine * sde,enum sdma_events event)2518f48ad614SDennis Dalessandro static void __sdma_process_event(struct sdma_engine *sde,
2519f48ad614SDennis Dalessandro enum sdma_events event)
2520f48ad614SDennis Dalessandro {
2521f48ad614SDennis Dalessandro struct sdma_state *ss = &sde->state;
2522f48ad614SDennis Dalessandro int need_progress = 0;
2523f48ad614SDennis Dalessandro
2524f48ad614SDennis Dalessandro /* CONFIG SDMA temporary */
2525f48ad614SDennis Dalessandro #ifdef CONFIG_SDMA_VERBOSITY
2526f48ad614SDennis Dalessandro dd_dev_err(sde->dd, "CONFIG SDMA(%u) [%s] %s\n", sde->this_idx,
2527f48ad614SDennis Dalessandro sdma_state_names[ss->current_state],
2528f48ad614SDennis Dalessandro sdma_event_names[event]);
2529f48ad614SDennis Dalessandro #endif
2530f48ad614SDennis Dalessandro
2531f48ad614SDennis Dalessandro switch (ss->current_state) {
2532f48ad614SDennis Dalessandro case sdma_state_s00_hw_down:
2533f48ad614SDennis Dalessandro switch (event) {
2534f48ad614SDennis Dalessandro case sdma_event_e00_go_hw_down:
2535f48ad614SDennis Dalessandro break;
2536f48ad614SDennis Dalessandro case sdma_event_e30_go_running:
2537f48ad614SDennis Dalessandro /*
2538f48ad614SDennis Dalessandro * If down, but running requested (usually result
2539f48ad614SDennis Dalessandro * of link up, then we need to start up.
2540f48ad614SDennis Dalessandro * This can happen when hw down is requested while
2541f48ad614SDennis Dalessandro * bringing the link up with traffic active on
2542f48ad614SDennis Dalessandro * 7220, e.g.
2543f48ad614SDennis Dalessandro */
2544f48ad614SDennis Dalessandro ss->go_s99_running = 1;
25456f24b159SGustavo A. R. Silva fallthrough; /* and start dma engine */
2546f48ad614SDennis Dalessandro case sdma_event_e10_go_hw_start:
2547f48ad614SDennis Dalessandro /* This reference means the state machine is started */
2548f48ad614SDennis Dalessandro sdma_get(&sde->state);
2549f48ad614SDennis Dalessandro sdma_set_state(sde,
2550f48ad614SDennis Dalessandro sdma_state_s10_hw_start_up_halt_wait);
2551f48ad614SDennis Dalessandro break;
2552f48ad614SDennis Dalessandro case sdma_event_e15_hw_halt_done:
2553f48ad614SDennis Dalessandro break;
2554f48ad614SDennis Dalessandro case sdma_event_e25_hw_clean_up_done:
2555f48ad614SDennis Dalessandro break;
2556f48ad614SDennis Dalessandro case sdma_event_e40_sw_cleaned:
2557f48ad614SDennis Dalessandro sdma_sw_tear_down(sde);
2558f48ad614SDennis Dalessandro break;
2559f48ad614SDennis Dalessandro case sdma_event_e50_hw_cleaned:
2560f48ad614SDennis Dalessandro break;
2561f48ad614SDennis Dalessandro case sdma_event_e60_hw_halted:
2562f48ad614SDennis Dalessandro break;
2563f48ad614SDennis Dalessandro case sdma_event_e70_go_idle:
2564f48ad614SDennis Dalessandro break;
2565f48ad614SDennis Dalessandro case sdma_event_e80_hw_freeze:
2566f48ad614SDennis Dalessandro break;
2567f48ad614SDennis Dalessandro case sdma_event_e81_hw_frozen:
2568f48ad614SDennis Dalessandro break;
2569f48ad614SDennis Dalessandro case sdma_event_e82_hw_unfreeze:
2570f48ad614SDennis Dalessandro break;
2571f48ad614SDennis Dalessandro case sdma_event_e85_link_down:
2572f48ad614SDennis Dalessandro break;
2573f48ad614SDennis Dalessandro case sdma_event_e90_sw_halted:
2574f48ad614SDennis Dalessandro break;
2575f48ad614SDennis Dalessandro }
2576f48ad614SDennis Dalessandro break;
2577f48ad614SDennis Dalessandro
2578f48ad614SDennis Dalessandro case sdma_state_s10_hw_start_up_halt_wait:
2579f48ad614SDennis Dalessandro switch (event) {
2580f48ad614SDennis Dalessandro case sdma_event_e00_go_hw_down:
2581f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s00_hw_down);
2582f48ad614SDennis Dalessandro sdma_sw_tear_down(sde);
2583f48ad614SDennis Dalessandro break;
2584f48ad614SDennis Dalessandro case sdma_event_e10_go_hw_start:
2585f48ad614SDennis Dalessandro break;
2586f48ad614SDennis Dalessandro case sdma_event_e15_hw_halt_done:
2587f48ad614SDennis Dalessandro sdma_set_state(sde,
2588f48ad614SDennis Dalessandro sdma_state_s15_hw_start_up_clean_wait);
2589f48ad614SDennis Dalessandro sdma_start_hw_clean_up(sde);
2590f48ad614SDennis Dalessandro break;
2591f48ad614SDennis Dalessandro case sdma_event_e25_hw_clean_up_done:
2592f48ad614SDennis Dalessandro break;
2593f48ad614SDennis Dalessandro case sdma_event_e30_go_running:
2594f48ad614SDennis Dalessandro ss->go_s99_running = 1;
2595f48ad614SDennis Dalessandro break;
2596f48ad614SDennis Dalessandro case sdma_event_e40_sw_cleaned:
2597f48ad614SDennis Dalessandro break;
2598f48ad614SDennis Dalessandro case sdma_event_e50_hw_cleaned:
2599f48ad614SDennis Dalessandro break;
2600f48ad614SDennis Dalessandro case sdma_event_e60_hw_halted:
2601f48ad614SDennis Dalessandro schedule_work(&sde->err_halt_worker);
2602f48ad614SDennis Dalessandro break;
2603f48ad614SDennis Dalessandro case sdma_event_e70_go_idle:
2604f48ad614SDennis Dalessandro ss->go_s99_running = 0;
2605f48ad614SDennis Dalessandro break;
2606f48ad614SDennis Dalessandro case sdma_event_e80_hw_freeze:
2607f48ad614SDennis Dalessandro break;
2608f48ad614SDennis Dalessandro case sdma_event_e81_hw_frozen:
2609f48ad614SDennis Dalessandro break;
2610f48ad614SDennis Dalessandro case sdma_event_e82_hw_unfreeze:
2611f48ad614SDennis Dalessandro break;
2612f48ad614SDennis Dalessandro case sdma_event_e85_link_down:
2613f48ad614SDennis Dalessandro break;
2614f48ad614SDennis Dalessandro case sdma_event_e90_sw_halted:
2615f48ad614SDennis Dalessandro break;
2616f48ad614SDennis Dalessandro }
2617f48ad614SDennis Dalessandro break;
2618f48ad614SDennis Dalessandro
2619f48ad614SDennis Dalessandro case sdma_state_s15_hw_start_up_clean_wait:
2620f48ad614SDennis Dalessandro switch (event) {
2621f48ad614SDennis Dalessandro case sdma_event_e00_go_hw_down:
2622f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s00_hw_down);
2623f48ad614SDennis Dalessandro sdma_sw_tear_down(sde);
2624f48ad614SDennis Dalessandro break;
2625f48ad614SDennis Dalessandro case sdma_event_e10_go_hw_start:
2626f48ad614SDennis Dalessandro break;
2627f48ad614SDennis Dalessandro case sdma_event_e15_hw_halt_done:
2628f48ad614SDennis Dalessandro break;
2629f48ad614SDennis Dalessandro case sdma_event_e25_hw_clean_up_done:
2630f48ad614SDennis Dalessandro sdma_hw_start_up(sde);
2631f48ad614SDennis Dalessandro sdma_set_state(sde, ss->go_s99_running ?
2632f48ad614SDennis Dalessandro sdma_state_s99_running :
2633f48ad614SDennis Dalessandro sdma_state_s20_idle);
2634f48ad614SDennis Dalessandro break;
2635f48ad614SDennis Dalessandro case sdma_event_e30_go_running:
2636f48ad614SDennis Dalessandro ss->go_s99_running = 1;
2637f48ad614SDennis Dalessandro break;
2638f48ad614SDennis Dalessandro case sdma_event_e40_sw_cleaned:
2639f48ad614SDennis Dalessandro break;
2640f48ad614SDennis Dalessandro case sdma_event_e50_hw_cleaned:
2641f48ad614SDennis Dalessandro break;
2642f48ad614SDennis Dalessandro case sdma_event_e60_hw_halted:
2643f48ad614SDennis Dalessandro break;
2644f48ad614SDennis Dalessandro case sdma_event_e70_go_idle:
2645f48ad614SDennis Dalessandro ss->go_s99_running = 0;
2646f48ad614SDennis Dalessandro break;
2647f48ad614SDennis Dalessandro case sdma_event_e80_hw_freeze:
2648f48ad614SDennis Dalessandro break;
2649f48ad614SDennis Dalessandro case sdma_event_e81_hw_frozen:
2650f48ad614SDennis Dalessandro break;
2651f48ad614SDennis Dalessandro case sdma_event_e82_hw_unfreeze:
2652f48ad614SDennis Dalessandro break;
2653f48ad614SDennis Dalessandro case sdma_event_e85_link_down:
2654f48ad614SDennis Dalessandro break;
2655f48ad614SDennis Dalessandro case sdma_event_e90_sw_halted:
2656f48ad614SDennis Dalessandro break;
2657f48ad614SDennis Dalessandro }
2658f48ad614SDennis Dalessandro break;
2659f48ad614SDennis Dalessandro
2660f48ad614SDennis Dalessandro case sdma_state_s20_idle:
2661f48ad614SDennis Dalessandro switch (event) {
2662f48ad614SDennis Dalessandro case sdma_event_e00_go_hw_down:
2663f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s00_hw_down);
2664f48ad614SDennis Dalessandro sdma_sw_tear_down(sde);
2665f48ad614SDennis Dalessandro break;
2666f48ad614SDennis Dalessandro case sdma_event_e10_go_hw_start:
2667f48ad614SDennis Dalessandro break;
2668f48ad614SDennis Dalessandro case sdma_event_e15_hw_halt_done:
2669f48ad614SDennis Dalessandro break;
2670f48ad614SDennis Dalessandro case sdma_event_e25_hw_clean_up_done:
2671f48ad614SDennis Dalessandro break;
2672f48ad614SDennis Dalessandro case sdma_event_e30_go_running:
2673f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s99_running);
2674f48ad614SDennis Dalessandro ss->go_s99_running = 1;
2675f48ad614SDennis Dalessandro break;
2676f48ad614SDennis Dalessandro case sdma_event_e40_sw_cleaned:
2677f48ad614SDennis Dalessandro break;
2678f48ad614SDennis Dalessandro case sdma_event_e50_hw_cleaned:
2679f48ad614SDennis Dalessandro break;
2680f48ad614SDennis Dalessandro case sdma_event_e60_hw_halted:
2681f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s50_hw_halt_wait);
2682f48ad614SDennis Dalessandro schedule_work(&sde->err_halt_worker);
2683f48ad614SDennis Dalessandro break;
2684f48ad614SDennis Dalessandro case sdma_event_e70_go_idle:
2685f48ad614SDennis Dalessandro break;
2686f48ad614SDennis Dalessandro case sdma_event_e85_link_down:
2687f48ad614SDennis Dalessandro case sdma_event_e80_hw_freeze:
2688f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s80_hw_freeze);
2689f48ad614SDennis Dalessandro atomic_dec(&sde->dd->sdma_unfreeze_count);
2690f48ad614SDennis Dalessandro wake_up_interruptible(&sde->dd->sdma_unfreeze_wq);
2691f48ad614SDennis Dalessandro break;
2692f48ad614SDennis Dalessandro case sdma_event_e81_hw_frozen:
2693f48ad614SDennis Dalessandro break;
2694f48ad614SDennis Dalessandro case sdma_event_e82_hw_unfreeze:
2695f48ad614SDennis Dalessandro break;
2696f48ad614SDennis Dalessandro case sdma_event_e90_sw_halted:
2697f48ad614SDennis Dalessandro break;
2698f48ad614SDennis Dalessandro }
2699f48ad614SDennis Dalessandro break;
2700f48ad614SDennis Dalessandro
2701f48ad614SDennis Dalessandro case sdma_state_s30_sw_clean_up_wait:
2702f48ad614SDennis Dalessandro switch (event) {
2703f48ad614SDennis Dalessandro case sdma_event_e00_go_hw_down:
2704f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s00_hw_down);
2705f48ad614SDennis Dalessandro break;
2706f48ad614SDennis Dalessandro case sdma_event_e10_go_hw_start:
2707f48ad614SDennis Dalessandro break;
2708f48ad614SDennis Dalessandro case sdma_event_e15_hw_halt_done:
2709f48ad614SDennis Dalessandro break;
2710f48ad614SDennis Dalessandro case sdma_event_e25_hw_clean_up_done:
2711f48ad614SDennis Dalessandro break;
2712f48ad614SDennis Dalessandro case sdma_event_e30_go_running:
2713f48ad614SDennis Dalessandro ss->go_s99_running = 1;
2714f48ad614SDennis Dalessandro break;
2715f48ad614SDennis Dalessandro case sdma_event_e40_sw_cleaned:
2716f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s40_hw_clean_up_wait);
2717f48ad614SDennis Dalessandro sdma_start_hw_clean_up(sde);
2718f48ad614SDennis Dalessandro break;
2719f48ad614SDennis Dalessandro case sdma_event_e50_hw_cleaned:
2720f48ad614SDennis Dalessandro break;
2721f48ad614SDennis Dalessandro case sdma_event_e60_hw_halted:
2722f48ad614SDennis Dalessandro break;
2723f48ad614SDennis Dalessandro case sdma_event_e70_go_idle:
2724f48ad614SDennis Dalessandro ss->go_s99_running = 0;
2725f48ad614SDennis Dalessandro break;
2726f48ad614SDennis Dalessandro case sdma_event_e80_hw_freeze:
2727f48ad614SDennis Dalessandro break;
2728f48ad614SDennis Dalessandro case sdma_event_e81_hw_frozen:
2729f48ad614SDennis Dalessandro break;
2730f48ad614SDennis Dalessandro case sdma_event_e82_hw_unfreeze:
2731f48ad614SDennis Dalessandro break;
2732f48ad614SDennis Dalessandro case sdma_event_e85_link_down:
2733f48ad614SDennis Dalessandro ss->go_s99_running = 0;
2734f48ad614SDennis Dalessandro break;
2735f48ad614SDennis Dalessandro case sdma_event_e90_sw_halted:
2736f48ad614SDennis Dalessandro break;
2737f48ad614SDennis Dalessandro }
2738f48ad614SDennis Dalessandro break;
2739f48ad614SDennis Dalessandro
2740f48ad614SDennis Dalessandro case sdma_state_s40_hw_clean_up_wait:
2741f48ad614SDennis Dalessandro switch (event) {
2742f48ad614SDennis Dalessandro case sdma_event_e00_go_hw_down:
2743f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s00_hw_down);
2744f48ad614SDennis Dalessandro tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
2745f48ad614SDennis Dalessandro break;
2746f48ad614SDennis Dalessandro case sdma_event_e10_go_hw_start:
2747f48ad614SDennis Dalessandro break;
2748f48ad614SDennis Dalessandro case sdma_event_e15_hw_halt_done:
2749f48ad614SDennis Dalessandro break;
2750f48ad614SDennis Dalessandro case sdma_event_e25_hw_clean_up_done:
2751f48ad614SDennis Dalessandro sdma_hw_start_up(sde);
2752f48ad614SDennis Dalessandro sdma_set_state(sde, ss->go_s99_running ?
2753f48ad614SDennis Dalessandro sdma_state_s99_running :
2754f48ad614SDennis Dalessandro sdma_state_s20_idle);
2755f48ad614SDennis Dalessandro break;
2756f48ad614SDennis Dalessandro case sdma_event_e30_go_running:
2757f48ad614SDennis Dalessandro ss->go_s99_running = 1;
2758f48ad614SDennis Dalessandro break;
2759f48ad614SDennis Dalessandro case sdma_event_e40_sw_cleaned:
2760f48ad614SDennis Dalessandro break;
2761f48ad614SDennis Dalessandro case sdma_event_e50_hw_cleaned:
2762f48ad614SDennis Dalessandro break;
2763f48ad614SDennis Dalessandro case sdma_event_e60_hw_halted:
2764f48ad614SDennis Dalessandro break;
2765f48ad614SDennis Dalessandro case sdma_event_e70_go_idle:
2766f48ad614SDennis Dalessandro ss->go_s99_running = 0;
2767f48ad614SDennis Dalessandro break;
2768f48ad614SDennis Dalessandro case sdma_event_e80_hw_freeze:
2769f48ad614SDennis Dalessandro break;
2770f48ad614SDennis Dalessandro case sdma_event_e81_hw_frozen:
2771f48ad614SDennis Dalessandro break;
2772f48ad614SDennis Dalessandro case sdma_event_e82_hw_unfreeze:
2773f48ad614SDennis Dalessandro break;
2774f48ad614SDennis Dalessandro case sdma_event_e85_link_down:
2775f48ad614SDennis Dalessandro ss->go_s99_running = 0;
2776f48ad614SDennis Dalessandro break;
2777f48ad614SDennis Dalessandro case sdma_event_e90_sw_halted:
2778f48ad614SDennis Dalessandro break;
2779f48ad614SDennis Dalessandro }
2780f48ad614SDennis Dalessandro break;
2781f48ad614SDennis Dalessandro
2782f48ad614SDennis Dalessandro case sdma_state_s50_hw_halt_wait:
2783f48ad614SDennis Dalessandro switch (event) {
2784f48ad614SDennis Dalessandro case sdma_event_e00_go_hw_down:
2785f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s00_hw_down);
2786f48ad614SDennis Dalessandro tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
2787f48ad614SDennis Dalessandro break;
2788f48ad614SDennis Dalessandro case sdma_event_e10_go_hw_start:
2789f48ad614SDennis Dalessandro break;
2790f48ad614SDennis Dalessandro case sdma_event_e15_hw_halt_done:
2791f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s30_sw_clean_up_wait);
2792f48ad614SDennis Dalessandro tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
2793f48ad614SDennis Dalessandro break;
2794f48ad614SDennis Dalessandro case sdma_event_e25_hw_clean_up_done:
2795f48ad614SDennis Dalessandro break;
2796f48ad614SDennis Dalessandro case sdma_event_e30_go_running:
2797f48ad614SDennis Dalessandro ss->go_s99_running = 1;
2798f48ad614SDennis Dalessandro break;
2799f48ad614SDennis Dalessandro case sdma_event_e40_sw_cleaned:
2800f48ad614SDennis Dalessandro break;
2801f48ad614SDennis Dalessandro case sdma_event_e50_hw_cleaned:
2802f48ad614SDennis Dalessandro break;
2803f48ad614SDennis Dalessandro case sdma_event_e60_hw_halted:
2804f48ad614SDennis Dalessandro schedule_work(&sde->err_halt_worker);
2805f48ad614SDennis Dalessandro break;
2806f48ad614SDennis Dalessandro case sdma_event_e70_go_idle:
2807f48ad614SDennis Dalessandro ss->go_s99_running = 0;
2808f48ad614SDennis Dalessandro break;
2809f48ad614SDennis Dalessandro case sdma_event_e80_hw_freeze:
2810f48ad614SDennis Dalessandro break;
2811f48ad614SDennis Dalessandro case sdma_event_e81_hw_frozen:
2812f48ad614SDennis Dalessandro break;
2813f48ad614SDennis Dalessandro case sdma_event_e82_hw_unfreeze:
2814f48ad614SDennis Dalessandro break;
2815f48ad614SDennis Dalessandro case sdma_event_e85_link_down:
2816f48ad614SDennis Dalessandro ss->go_s99_running = 0;
2817f48ad614SDennis Dalessandro break;
2818f48ad614SDennis Dalessandro case sdma_event_e90_sw_halted:
2819f48ad614SDennis Dalessandro break;
2820f48ad614SDennis Dalessandro }
2821f48ad614SDennis Dalessandro break;
2822f48ad614SDennis Dalessandro
2823f48ad614SDennis Dalessandro case sdma_state_s60_idle_halt_wait:
2824f48ad614SDennis Dalessandro switch (event) {
2825f48ad614SDennis Dalessandro case sdma_event_e00_go_hw_down:
2826f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s00_hw_down);
2827f48ad614SDennis Dalessandro tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
2828f48ad614SDennis Dalessandro break;
2829f48ad614SDennis Dalessandro case sdma_event_e10_go_hw_start:
2830f48ad614SDennis Dalessandro break;
2831f48ad614SDennis Dalessandro case sdma_event_e15_hw_halt_done:
2832f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s30_sw_clean_up_wait);
2833f48ad614SDennis Dalessandro tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
2834f48ad614SDennis Dalessandro break;
2835f48ad614SDennis Dalessandro case sdma_event_e25_hw_clean_up_done:
2836f48ad614SDennis Dalessandro break;
2837f48ad614SDennis Dalessandro case sdma_event_e30_go_running:
2838f48ad614SDennis Dalessandro ss->go_s99_running = 1;
2839f48ad614SDennis Dalessandro break;
2840f48ad614SDennis Dalessandro case sdma_event_e40_sw_cleaned:
2841f48ad614SDennis Dalessandro break;
2842f48ad614SDennis Dalessandro case sdma_event_e50_hw_cleaned:
2843f48ad614SDennis Dalessandro break;
2844f48ad614SDennis Dalessandro case sdma_event_e60_hw_halted:
2845f48ad614SDennis Dalessandro schedule_work(&sde->err_halt_worker);
2846f48ad614SDennis Dalessandro break;
2847f48ad614SDennis Dalessandro case sdma_event_e70_go_idle:
2848f48ad614SDennis Dalessandro ss->go_s99_running = 0;
2849f48ad614SDennis Dalessandro break;
2850f48ad614SDennis Dalessandro case sdma_event_e80_hw_freeze:
2851f48ad614SDennis Dalessandro break;
2852f48ad614SDennis Dalessandro case sdma_event_e81_hw_frozen:
2853f48ad614SDennis Dalessandro break;
2854f48ad614SDennis Dalessandro case sdma_event_e82_hw_unfreeze:
2855f48ad614SDennis Dalessandro break;
2856f48ad614SDennis Dalessandro case sdma_event_e85_link_down:
2857f48ad614SDennis Dalessandro break;
2858f48ad614SDennis Dalessandro case sdma_event_e90_sw_halted:
2859f48ad614SDennis Dalessandro break;
2860f48ad614SDennis Dalessandro }
2861f48ad614SDennis Dalessandro break;
2862f48ad614SDennis Dalessandro
2863f48ad614SDennis Dalessandro case sdma_state_s80_hw_freeze:
2864f48ad614SDennis Dalessandro switch (event) {
2865f48ad614SDennis Dalessandro case sdma_event_e00_go_hw_down:
2866f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s00_hw_down);
2867f48ad614SDennis Dalessandro tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
2868f48ad614SDennis Dalessandro break;
2869f48ad614SDennis Dalessandro case sdma_event_e10_go_hw_start:
2870f48ad614SDennis Dalessandro break;
2871f48ad614SDennis Dalessandro case sdma_event_e15_hw_halt_done:
2872f48ad614SDennis Dalessandro break;
2873f48ad614SDennis Dalessandro case sdma_event_e25_hw_clean_up_done:
2874f48ad614SDennis Dalessandro break;
2875f48ad614SDennis Dalessandro case sdma_event_e30_go_running:
2876f48ad614SDennis Dalessandro ss->go_s99_running = 1;
2877f48ad614SDennis Dalessandro break;
2878f48ad614SDennis Dalessandro case sdma_event_e40_sw_cleaned:
2879f48ad614SDennis Dalessandro break;
2880f48ad614SDennis Dalessandro case sdma_event_e50_hw_cleaned:
2881f48ad614SDennis Dalessandro break;
2882f48ad614SDennis Dalessandro case sdma_event_e60_hw_halted:
2883f48ad614SDennis Dalessandro break;
2884f48ad614SDennis Dalessandro case sdma_event_e70_go_idle:
2885f48ad614SDennis Dalessandro ss->go_s99_running = 0;
2886f48ad614SDennis Dalessandro break;
2887f48ad614SDennis Dalessandro case sdma_event_e80_hw_freeze:
2888f48ad614SDennis Dalessandro break;
2889f48ad614SDennis Dalessandro case sdma_event_e81_hw_frozen:
2890f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s82_freeze_sw_clean);
2891f48ad614SDennis Dalessandro tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
2892f48ad614SDennis Dalessandro break;
2893f48ad614SDennis Dalessandro case sdma_event_e82_hw_unfreeze:
2894f48ad614SDennis Dalessandro break;
2895f48ad614SDennis Dalessandro case sdma_event_e85_link_down:
2896f48ad614SDennis Dalessandro break;
2897f48ad614SDennis Dalessandro case sdma_event_e90_sw_halted:
2898f48ad614SDennis Dalessandro break;
2899f48ad614SDennis Dalessandro }
2900f48ad614SDennis Dalessandro break;
2901f48ad614SDennis Dalessandro
2902f48ad614SDennis Dalessandro case sdma_state_s82_freeze_sw_clean:
2903f48ad614SDennis Dalessandro switch (event) {
2904f48ad614SDennis Dalessandro case sdma_event_e00_go_hw_down:
2905f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s00_hw_down);
2906f48ad614SDennis Dalessandro tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
2907f48ad614SDennis Dalessandro break;
2908f48ad614SDennis Dalessandro case sdma_event_e10_go_hw_start:
2909f48ad614SDennis Dalessandro break;
2910f48ad614SDennis Dalessandro case sdma_event_e15_hw_halt_done:
2911f48ad614SDennis Dalessandro break;
2912f48ad614SDennis Dalessandro case sdma_event_e25_hw_clean_up_done:
2913f48ad614SDennis Dalessandro break;
2914f48ad614SDennis Dalessandro case sdma_event_e30_go_running:
2915f48ad614SDennis Dalessandro ss->go_s99_running = 1;
2916f48ad614SDennis Dalessandro break;
2917f48ad614SDennis Dalessandro case sdma_event_e40_sw_cleaned:
2918f48ad614SDennis Dalessandro /* notify caller this engine is done cleaning */
2919f48ad614SDennis Dalessandro atomic_dec(&sde->dd->sdma_unfreeze_count);
2920f48ad614SDennis Dalessandro wake_up_interruptible(&sde->dd->sdma_unfreeze_wq);
2921f48ad614SDennis Dalessandro break;
2922f48ad614SDennis Dalessandro case sdma_event_e50_hw_cleaned:
2923f48ad614SDennis Dalessandro break;
2924f48ad614SDennis Dalessandro case sdma_event_e60_hw_halted:
2925f48ad614SDennis Dalessandro break;
2926f48ad614SDennis Dalessandro case sdma_event_e70_go_idle:
2927f48ad614SDennis Dalessandro ss->go_s99_running = 0;
2928f48ad614SDennis Dalessandro break;
2929f48ad614SDennis Dalessandro case sdma_event_e80_hw_freeze:
2930f48ad614SDennis Dalessandro break;
2931f48ad614SDennis Dalessandro case sdma_event_e81_hw_frozen:
2932f48ad614SDennis Dalessandro break;
2933f48ad614SDennis Dalessandro case sdma_event_e82_hw_unfreeze:
2934f48ad614SDennis Dalessandro sdma_hw_start_up(sde);
2935f48ad614SDennis Dalessandro sdma_set_state(sde, ss->go_s99_running ?
2936f48ad614SDennis Dalessandro sdma_state_s99_running :
2937f48ad614SDennis Dalessandro sdma_state_s20_idle);
2938f48ad614SDennis Dalessandro break;
2939f48ad614SDennis Dalessandro case sdma_event_e85_link_down:
2940f48ad614SDennis Dalessandro break;
2941f48ad614SDennis Dalessandro case sdma_event_e90_sw_halted:
2942f48ad614SDennis Dalessandro break;
2943f48ad614SDennis Dalessandro }
2944f48ad614SDennis Dalessandro break;
2945f48ad614SDennis Dalessandro
2946f48ad614SDennis Dalessandro case sdma_state_s99_running:
2947f48ad614SDennis Dalessandro switch (event) {
2948f48ad614SDennis Dalessandro case sdma_event_e00_go_hw_down:
2949f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s00_hw_down);
2950f48ad614SDennis Dalessandro tasklet_hi_schedule(&sde->sdma_sw_clean_up_task);
2951f48ad614SDennis Dalessandro break;
2952f48ad614SDennis Dalessandro case sdma_event_e10_go_hw_start:
2953f48ad614SDennis Dalessandro break;
2954f48ad614SDennis Dalessandro case sdma_event_e15_hw_halt_done:
2955f48ad614SDennis Dalessandro break;
2956f48ad614SDennis Dalessandro case sdma_event_e25_hw_clean_up_done:
2957f48ad614SDennis Dalessandro break;
2958f48ad614SDennis Dalessandro case sdma_event_e30_go_running:
2959f48ad614SDennis Dalessandro break;
2960f48ad614SDennis Dalessandro case sdma_event_e40_sw_cleaned:
2961f48ad614SDennis Dalessandro break;
2962f48ad614SDennis Dalessandro case sdma_event_e50_hw_cleaned:
2963f48ad614SDennis Dalessandro break;
2964f48ad614SDennis Dalessandro case sdma_event_e60_hw_halted:
2965f48ad614SDennis Dalessandro need_progress = 1;
2966f48ad614SDennis Dalessandro sdma_err_progress_check_schedule(sde);
29676f24b159SGustavo A. R. Silva fallthrough;
2968f48ad614SDennis Dalessandro case sdma_event_e90_sw_halted:
2969f48ad614SDennis Dalessandro /*
2970f48ad614SDennis Dalessandro * SW initiated halt does not perform engines
2971f48ad614SDennis Dalessandro * progress check
2972f48ad614SDennis Dalessandro */
2973f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s50_hw_halt_wait);
2974f48ad614SDennis Dalessandro schedule_work(&sde->err_halt_worker);
2975f48ad614SDennis Dalessandro break;
2976f48ad614SDennis Dalessandro case sdma_event_e70_go_idle:
2977f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s60_idle_halt_wait);
2978f48ad614SDennis Dalessandro break;
2979f48ad614SDennis Dalessandro case sdma_event_e85_link_down:
2980f48ad614SDennis Dalessandro ss->go_s99_running = 0;
29816f24b159SGustavo A. R. Silva fallthrough;
2982f48ad614SDennis Dalessandro case sdma_event_e80_hw_freeze:
2983f48ad614SDennis Dalessandro sdma_set_state(sde, sdma_state_s80_hw_freeze);
2984f48ad614SDennis Dalessandro atomic_dec(&sde->dd->sdma_unfreeze_count);
2985f48ad614SDennis Dalessandro wake_up_interruptible(&sde->dd->sdma_unfreeze_wq);
2986f48ad614SDennis Dalessandro break;
2987f48ad614SDennis Dalessandro case sdma_event_e81_hw_frozen:
2988f48ad614SDennis Dalessandro break;
2989f48ad614SDennis Dalessandro case sdma_event_e82_hw_unfreeze:
2990f48ad614SDennis Dalessandro break;
2991f48ad614SDennis Dalessandro }
2992f48ad614SDennis Dalessandro break;
2993f48ad614SDennis Dalessandro }
2994f48ad614SDennis Dalessandro
2995f48ad614SDennis Dalessandro ss->last_event = event;
2996f48ad614SDennis Dalessandro if (need_progress)
2997f48ad614SDennis Dalessandro sdma_make_progress(sde, 0);
2998f48ad614SDennis Dalessandro }
2999f48ad614SDennis Dalessandro
3000f48ad614SDennis Dalessandro /*
3001f48ad614SDennis Dalessandro * _extend_sdma_tx_descs() - helper to extend txreq
3002f48ad614SDennis Dalessandro *
3003f48ad614SDennis Dalessandro * This is called once the initial nominal allocation
3004f48ad614SDennis Dalessandro * of descriptors in the sdma_txreq is exhausted.
3005f48ad614SDennis Dalessandro *
3006f48ad614SDennis Dalessandro * The code will bump the allocation up to the max
3007f48ad614SDennis Dalessandro * of MAX_DESC (64) descriptors. There doesn't seem
3008f48ad614SDennis Dalessandro * much point in an interim step. The last descriptor
3009f48ad614SDennis Dalessandro * is reserved for coalesce buffer in order to support
3010f48ad614SDennis Dalessandro * cases where input packet has >MAX_DESC iovecs.
3011f48ad614SDennis Dalessandro *
3012f48ad614SDennis Dalessandro */
_extend_sdma_tx_descs(struct hfi1_devdata * dd,struct sdma_txreq * tx)3013f48ad614SDennis Dalessandro static int _extend_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
3014f48ad614SDennis Dalessandro {
3015f48ad614SDennis Dalessandro int i;
3016cbe71c61STuo Li struct sdma_desc *descp;
3017f48ad614SDennis Dalessandro
3018f48ad614SDennis Dalessandro /* Handle last descriptor */
3019f48ad614SDennis Dalessandro if (unlikely((tx->num_desc == (MAX_DESC - 1)))) {
3020f48ad614SDennis Dalessandro /* if tlen is 0, it is for padding, release last descriptor */
3021f48ad614SDennis Dalessandro if (!tx->tlen) {
3022f48ad614SDennis Dalessandro tx->desc_limit = MAX_DESC;
3023f48ad614SDennis Dalessandro } else if (!tx->coalesce_buf) {
3024f48ad614SDennis Dalessandro /* allocate coalesce buffer with space for padding */
3025f48ad614SDennis Dalessandro tx->coalesce_buf = kmalloc(tx->tlen + sizeof(u32),
3026f48ad614SDennis Dalessandro GFP_ATOMIC);
3027f48ad614SDennis Dalessandro if (!tx->coalesce_buf)
3028f48ad614SDennis Dalessandro goto enomem;
3029f48ad614SDennis Dalessandro tx->coalesce_idx = 0;
3030f48ad614SDennis Dalessandro }
3031f48ad614SDennis Dalessandro return 0;
3032f48ad614SDennis Dalessandro }
3033f48ad614SDennis Dalessandro
3034f48ad614SDennis Dalessandro if (unlikely(tx->num_desc == MAX_DESC))
3035f48ad614SDennis Dalessandro goto enomem;
3036f48ad614SDennis Dalessandro
3037cbe71c61STuo Li descp = kmalloc_array(MAX_DESC, sizeof(struct sdma_desc), GFP_ATOMIC);
3038cbe71c61STuo Li if (!descp)
3039f48ad614SDennis Dalessandro goto enomem;
3040cbe71c61STuo Li tx->descp = descp;
3041f48ad614SDennis Dalessandro
3042f48ad614SDennis Dalessandro /* reserve last descriptor for coalescing */
3043f48ad614SDennis Dalessandro tx->desc_limit = MAX_DESC - 1;
3044f48ad614SDennis Dalessandro /* copy ones already built */
3045f48ad614SDennis Dalessandro for (i = 0; i < tx->num_desc; i++)
3046f48ad614SDennis Dalessandro tx->descp[i] = tx->descs[i];
3047f48ad614SDennis Dalessandro return 0;
3048f48ad614SDennis Dalessandro enomem:
304963df8e09SMike Marciniszyn __sdma_txclean(dd, tx);
3050f48ad614SDennis Dalessandro return -ENOMEM;
3051f48ad614SDennis Dalessandro }
3052f48ad614SDennis Dalessandro
3053f48ad614SDennis Dalessandro /*
3054f48ad614SDennis Dalessandro * ext_coal_sdma_tx_descs() - extend or coalesce sdma tx descriptors
3055f48ad614SDennis Dalessandro *
3056f48ad614SDennis Dalessandro * This is called once the initial nominal allocation of descriptors
3057f48ad614SDennis Dalessandro * in the sdma_txreq is exhausted.
3058f48ad614SDennis Dalessandro *
3059f48ad614SDennis Dalessandro * This function calls _extend_sdma_tx_descs to extend or allocate
3060f48ad614SDennis Dalessandro * coalesce buffer. If there is a allocated coalesce buffer, it will
3061f48ad614SDennis Dalessandro * copy the input packet data into the coalesce buffer. It also adds
3062f48ad614SDennis Dalessandro * coalesce buffer descriptor once when whole packet is received.
3063f48ad614SDennis Dalessandro *
3064f48ad614SDennis Dalessandro * Return:
3065f48ad614SDennis Dalessandro * <0 - error
3066f48ad614SDennis Dalessandro * 0 - coalescing, don't populate descriptor
3067f48ad614SDennis Dalessandro * 1 - continue with populating descriptor
3068f48ad614SDennis Dalessandro */
ext_coal_sdma_tx_descs(struct hfi1_devdata * dd,struct sdma_txreq * tx,int type,void * kvaddr,struct page * page,unsigned long offset,u16 len)3069f48ad614SDennis Dalessandro int ext_coal_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx,
3070f48ad614SDennis Dalessandro int type, void *kvaddr, struct page *page,
3071f48ad614SDennis Dalessandro unsigned long offset, u16 len)
3072f48ad614SDennis Dalessandro {
3073f48ad614SDennis Dalessandro int pad_len, rval;
3074f48ad614SDennis Dalessandro dma_addr_t addr;
3075f48ad614SDennis Dalessandro
3076f48ad614SDennis Dalessandro rval = _extend_sdma_tx_descs(dd, tx);
3077f48ad614SDennis Dalessandro if (rval) {
307863df8e09SMike Marciniszyn __sdma_txclean(dd, tx);
3079f48ad614SDennis Dalessandro return rval;
3080f48ad614SDennis Dalessandro }
3081f48ad614SDennis Dalessandro
3082f48ad614SDennis Dalessandro /* If coalesce buffer is allocated, copy data into it */
3083f48ad614SDennis Dalessandro if (tx->coalesce_buf) {
3084f48ad614SDennis Dalessandro if (type == SDMA_MAP_NONE) {
308563df8e09SMike Marciniszyn __sdma_txclean(dd, tx);
3086f48ad614SDennis Dalessandro return -EINVAL;
3087f48ad614SDennis Dalessandro }
3088f48ad614SDennis Dalessandro
3089f48ad614SDennis Dalessandro if (type == SDMA_MAP_PAGE) {
309036f5625aSIra Weiny kvaddr = kmap_local_page(page);
3091f48ad614SDennis Dalessandro kvaddr += offset;
3092f48ad614SDennis Dalessandro } else if (WARN_ON(!kvaddr)) {
309363df8e09SMike Marciniszyn __sdma_txclean(dd, tx);
3094f48ad614SDennis Dalessandro return -EINVAL;
3095f48ad614SDennis Dalessandro }
3096f48ad614SDennis Dalessandro
3097f48ad614SDennis Dalessandro memcpy(tx->coalesce_buf + tx->coalesce_idx, kvaddr, len);
3098f48ad614SDennis Dalessandro tx->coalesce_idx += len;
3099f48ad614SDennis Dalessandro if (type == SDMA_MAP_PAGE)
310036f5625aSIra Weiny kunmap_local(kvaddr);
3101f48ad614SDennis Dalessandro
3102f48ad614SDennis Dalessandro /* If there is more data, return */
3103f48ad614SDennis Dalessandro if (tx->tlen - tx->coalesce_idx)
3104f48ad614SDennis Dalessandro return 0;
3105f48ad614SDennis Dalessandro
3106f48ad614SDennis Dalessandro /* Whole packet is received; add any padding */
3107f48ad614SDennis Dalessandro pad_len = tx->packet_len & (sizeof(u32) - 1);
3108f48ad614SDennis Dalessandro if (pad_len) {
3109f48ad614SDennis Dalessandro pad_len = sizeof(u32) - pad_len;
3110f48ad614SDennis Dalessandro memset(tx->coalesce_buf + tx->coalesce_idx, 0, pad_len);
3111f48ad614SDennis Dalessandro /* padding is taken care of for coalescing case */
3112f48ad614SDennis Dalessandro tx->packet_len += pad_len;
3113f48ad614SDennis Dalessandro tx->tlen += pad_len;
3114f48ad614SDennis Dalessandro }
3115f48ad614SDennis Dalessandro
3116f48ad614SDennis Dalessandro /* dma map the coalesce buffer */
3117f48ad614SDennis Dalessandro addr = dma_map_single(&dd->pcidev->dev,
3118f48ad614SDennis Dalessandro tx->coalesce_buf,
3119f48ad614SDennis Dalessandro tx->tlen,
3120f48ad614SDennis Dalessandro DMA_TO_DEVICE);
3121f48ad614SDennis Dalessandro
3122f48ad614SDennis Dalessandro if (unlikely(dma_mapping_error(&dd->pcidev->dev, addr))) {
312363df8e09SMike Marciniszyn __sdma_txclean(dd, tx);
3124f48ad614SDennis Dalessandro return -ENOSPC;
3125f48ad614SDennis Dalessandro }
3126f48ad614SDennis Dalessandro
3127f48ad614SDennis Dalessandro /* Add descriptor for coalesce buffer */
3128f48ad614SDennis Dalessandro tx->desc_limit = MAX_DESC;
3129c9358de1SBrendan Cunningham return _sdma_txadd_daddr(dd, SDMA_MAP_SINGLE, tx,
3130c9358de1SBrendan Cunningham addr, tx->tlen, NULL, NULL, NULL);
3131f48ad614SDennis Dalessandro }
3132f48ad614SDennis Dalessandro
3133f48ad614SDennis Dalessandro return 1;
3134f48ad614SDennis Dalessandro }
3135f48ad614SDennis Dalessandro
3136f48ad614SDennis Dalessandro /* Update sdes when the lmc changes */
sdma_update_lmc(struct hfi1_devdata * dd,u64 mask,u32 lid)3137f48ad614SDennis Dalessandro void sdma_update_lmc(struct hfi1_devdata *dd, u64 mask, u32 lid)
3138f48ad614SDennis Dalessandro {
3139f48ad614SDennis Dalessandro struct sdma_engine *sde;
3140f48ad614SDennis Dalessandro int i;
3141f48ad614SDennis Dalessandro u64 sreg;
3142f48ad614SDennis Dalessandro
3143f48ad614SDennis Dalessandro sreg = ((mask & SD(CHECK_SLID_MASK_MASK)) <<
3144f48ad614SDennis Dalessandro SD(CHECK_SLID_MASK_SHIFT)) |
3145f48ad614SDennis Dalessandro (((lid & mask) & SD(CHECK_SLID_VALUE_MASK)) <<
3146f48ad614SDennis Dalessandro SD(CHECK_SLID_VALUE_SHIFT));
3147f48ad614SDennis Dalessandro
3148f48ad614SDennis Dalessandro for (i = 0; i < dd->num_sdma; i++) {
3149f48ad614SDennis Dalessandro hfi1_cdbg(LINKVERB, "SendDmaEngine[%d].SLID_CHECK = 0x%x",
3150f48ad614SDennis Dalessandro i, (u32)sreg);
3151f48ad614SDennis Dalessandro sde = &dd->per_sdma[i];
3152f48ad614SDennis Dalessandro write_sde_csr(sde, SD(CHECK_SLID), sreg);
3153f48ad614SDennis Dalessandro }
3154f48ad614SDennis Dalessandro }
3155f48ad614SDennis Dalessandro
3156f48ad614SDennis Dalessandro /* tx not dword sized - pad */
_pad_sdma_tx_descs(struct hfi1_devdata * dd,struct sdma_txreq * tx)3157f48ad614SDennis Dalessandro int _pad_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx)
3158f48ad614SDennis Dalessandro {
3159f48ad614SDennis Dalessandro int rval = 0;
3160f48ad614SDennis Dalessandro
3161*a2fef1d8SDaniel Vacek if ((unlikely(tx->num_desc == tx->desc_limit))) {
3162f48ad614SDennis Dalessandro rval = _extend_sdma_tx_descs(dd, tx);
3163f48ad614SDennis Dalessandro if (rval) {
316463df8e09SMike Marciniszyn __sdma_txclean(dd, tx);
3165f48ad614SDennis Dalessandro return rval;
3166f48ad614SDennis Dalessandro }
3167f48ad614SDennis Dalessandro }
316800cbce5cSPatrick Kelsey
3169f48ad614SDennis Dalessandro /* finish the one just added */
3170f48ad614SDennis Dalessandro make_tx_sdma_desc(
3171f48ad614SDennis Dalessandro tx,
3172f48ad614SDennis Dalessandro SDMA_MAP_NONE,
3173f48ad614SDennis Dalessandro dd->sdma_pad_phys,
3174c9358de1SBrendan Cunningham sizeof(u32) - (tx->packet_len & (sizeof(u32) - 1)),
3175c9358de1SBrendan Cunningham NULL, NULL, NULL);
3176fd8958efSPatrick Kelsey tx->num_desc++;
3177f48ad614SDennis Dalessandro _sdma_close_tx(dd, tx);
3178f48ad614SDennis Dalessandro return rval;
3179f48ad614SDennis Dalessandro }
3180f48ad614SDennis Dalessandro
3181f48ad614SDennis Dalessandro /*
3182f48ad614SDennis Dalessandro * Add ahg to the sdma_txreq
3183f48ad614SDennis Dalessandro *
3184f48ad614SDennis Dalessandro * The logic will consume up to 3
3185f48ad614SDennis Dalessandro * descriptors at the beginning of
3186f48ad614SDennis Dalessandro * sdma_txreq.
3187f48ad614SDennis Dalessandro */
_sdma_txreq_ahgadd(struct sdma_txreq * tx,u8 num_ahg,u8 ahg_entry,u32 * ahg,u8 ahg_hlen)3188f48ad614SDennis Dalessandro void _sdma_txreq_ahgadd(
3189f48ad614SDennis Dalessandro struct sdma_txreq *tx,
3190f48ad614SDennis Dalessandro u8 num_ahg,
3191f48ad614SDennis Dalessandro u8 ahg_entry,
3192f48ad614SDennis Dalessandro u32 *ahg,
3193f48ad614SDennis Dalessandro u8 ahg_hlen)
3194f48ad614SDennis Dalessandro {
3195f48ad614SDennis Dalessandro u32 i, shift = 0, desc = 0;
3196f48ad614SDennis Dalessandro u8 mode;
3197f48ad614SDennis Dalessandro
3198f48ad614SDennis Dalessandro WARN_ON_ONCE(num_ahg > 9 || (ahg_hlen & 3) || ahg_hlen == 4);
3199f48ad614SDennis Dalessandro /* compute mode */
3200f48ad614SDennis Dalessandro if (num_ahg == 1)
3201f48ad614SDennis Dalessandro mode = SDMA_AHG_APPLY_UPDATE1;
3202f48ad614SDennis Dalessandro else if (num_ahg <= 5)
3203f48ad614SDennis Dalessandro mode = SDMA_AHG_APPLY_UPDATE2;
3204f48ad614SDennis Dalessandro else
3205f48ad614SDennis Dalessandro mode = SDMA_AHG_APPLY_UPDATE3;
3206f48ad614SDennis Dalessandro tx->num_desc++;
3207f48ad614SDennis Dalessandro /* initialize to consumed descriptors to zero */
3208f48ad614SDennis Dalessandro switch (mode) {
3209f48ad614SDennis Dalessandro case SDMA_AHG_APPLY_UPDATE3:
3210f48ad614SDennis Dalessandro tx->num_desc++;
3211f48ad614SDennis Dalessandro tx->descs[2].qw[0] = 0;
3212f48ad614SDennis Dalessandro tx->descs[2].qw[1] = 0;
32136f24b159SGustavo A. R. Silva fallthrough;
3214f48ad614SDennis Dalessandro case SDMA_AHG_APPLY_UPDATE2:
3215f48ad614SDennis Dalessandro tx->num_desc++;
3216f48ad614SDennis Dalessandro tx->descs[1].qw[0] = 0;
3217f48ad614SDennis Dalessandro tx->descs[1].qw[1] = 0;
3218f48ad614SDennis Dalessandro break;
3219f48ad614SDennis Dalessandro }
3220f48ad614SDennis Dalessandro ahg_hlen >>= 2;
3221f48ad614SDennis Dalessandro tx->descs[0].qw[1] |=
3222f48ad614SDennis Dalessandro (((u64)ahg_entry & SDMA_DESC1_HEADER_INDEX_MASK)
3223f48ad614SDennis Dalessandro << SDMA_DESC1_HEADER_INDEX_SHIFT) |
3224f48ad614SDennis Dalessandro (((u64)ahg_hlen & SDMA_DESC1_HEADER_DWS_MASK)
3225f48ad614SDennis Dalessandro << SDMA_DESC1_HEADER_DWS_SHIFT) |
3226f48ad614SDennis Dalessandro (((u64)mode & SDMA_DESC1_HEADER_MODE_MASK)
3227f48ad614SDennis Dalessandro << SDMA_DESC1_HEADER_MODE_SHIFT) |
3228f48ad614SDennis Dalessandro (((u64)ahg[0] & SDMA_DESC1_HEADER_UPDATE1_MASK)
3229f48ad614SDennis Dalessandro << SDMA_DESC1_HEADER_UPDATE1_SHIFT);
3230f48ad614SDennis Dalessandro for (i = 0; i < (num_ahg - 1); i++) {
3231f48ad614SDennis Dalessandro if (!shift && !(i & 2))
3232f48ad614SDennis Dalessandro desc++;
3233f48ad614SDennis Dalessandro tx->descs[desc].qw[!!(i & 2)] |=
3234f48ad614SDennis Dalessandro (((u64)ahg[i + 1])
3235f48ad614SDennis Dalessandro << shift);
3236f48ad614SDennis Dalessandro shift = (shift + 32) & 63;
3237f48ad614SDennis Dalessandro }
3238f48ad614SDennis Dalessandro }
3239f48ad614SDennis Dalessandro
3240f48ad614SDennis Dalessandro /**
3241f48ad614SDennis Dalessandro * sdma_ahg_alloc - allocate an AHG entry
3242f48ad614SDennis Dalessandro * @sde: engine to allocate from
3243f48ad614SDennis Dalessandro *
3244f48ad614SDennis Dalessandro * Return:
3245f48ad614SDennis Dalessandro * 0-31 when successful, -EOPNOTSUPP if AHG is not enabled,
3246f48ad614SDennis Dalessandro * -ENOSPC if an entry is not available
3247f48ad614SDennis Dalessandro */
sdma_ahg_alloc(struct sdma_engine * sde)3248f48ad614SDennis Dalessandro int sdma_ahg_alloc(struct sdma_engine *sde)
3249f48ad614SDennis Dalessandro {
3250f48ad614SDennis Dalessandro int nr;
3251f48ad614SDennis Dalessandro int oldbit;
3252f48ad614SDennis Dalessandro
3253f48ad614SDennis Dalessandro if (!sde) {
3254f48ad614SDennis Dalessandro trace_hfi1_ahg_allocate(sde, -EINVAL);
3255f48ad614SDennis Dalessandro return -EINVAL;
3256f48ad614SDennis Dalessandro }
3257f48ad614SDennis Dalessandro while (1) {
32586aa7de05SMark Rutland nr = ffz(READ_ONCE(sde->ahg_bits));
3259f48ad614SDennis Dalessandro if (nr > 31) {
3260f48ad614SDennis Dalessandro trace_hfi1_ahg_allocate(sde, -ENOSPC);
3261f48ad614SDennis Dalessandro return -ENOSPC;
3262f48ad614SDennis Dalessandro }
3263f48ad614SDennis Dalessandro oldbit = test_and_set_bit(nr, &sde->ahg_bits);
3264f48ad614SDennis Dalessandro if (!oldbit)
3265f48ad614SDennis Dalessandro break;
3266f48ad614SDennis Dalessandro cpu_relax();
3267f48ad614SDennis Dalessandro }
3268f48ad614SDennis Dalessandro trace_hfi1_ahg_allocate(sde, nr);
3269f48ad614SDennis Dalessandro return nr;
3270f48ad614SDennis Dalessandro }
3271f48ad614SDennis Dalessandro
3272f48ad614SDennis Dalessandro /**
3273f48ad614SDennis Dalessandro * sdma_ahg_free - free an AHG entry
3274f48ad614SDennis Dalessandro * @sde: engine to return AHG entry
3275f48ad614SDennis Dalessandro * @ahg_index: index to free
3276f48ad614SDennis Dalessandro *
3277f48ad614SDennis Dalessandro * This routine frees the indicate AHG entry.
3278f48ad614SDennis Dalessandro */
sdma_ahg_free(struct sdma_engine * sde,int ahg_index)3279f48ad614SDennis Dalessandro void sdma_ahg_free(struct sdma_engine *sde, int ahg_index)
3280f48ad614SDennis Dalessandro {
3281f48ad614SDennis Dalessandro if (!sde)
3282f48ad614SDennis Dalessandro return;
3283f48ad614SDennis Dalessandro trace_hfi1_ahg_deallocate(sde, ahg_index);
3284f48ad614SDennis Dalessandro if (ahg_index < 0 || ahg_index > 31)
3285f48ad614SDennis Dalessandro return;
3286f48ad614SDennis Dalessandro clear_bit(ahg_index, &sde->ahg_bits);
3287f48ad614SDennis Dalessandro }
3288f48ad614SDennis Dalessandro
3289f48ad614SDennis Dalessandro /*
3290f48ad614SDennis Dalessandro * SPC freeze handling for SDMA engines. Called when the driver knows
3291f48ad614SDennis Dalessandro * the SPC is going into a freeze but before the freeze is fully
3292f48ad614SDennis Dalessandro * settled. Generally an error interrupt.
3293f48ad614SDennis Dalessandro *
3294f48ad614SDennis Dalessandro * This event will pull the engine out of running so no more entries can be
3295f48ad614SDennis Dalessandro * added to the engine's queue.
3296f48ad614SDennis Dalessandro */
sdma_freeze_notify(struct hfi1_devdata * dd,int link_down)3297f48ad614SDennis Dalessandro void sdma_freeze_notify(struct hfi1_devdata *dd, int link_down)
3298f48ad614SDennis Dalessandro {
3299f48ad614SDennis Dalessandro int i;
3300f48ad614SDennis Dalessandro enum sdma_events event = link_down ? sdma_event_e85_link_down :
3301f48ad614SDennis Dalessandro sdma_event_e80_hw_freeze;
3302f48ad614SDennis Dalessandro
3303f48ad614SDennis Dalessandro /* set up the wait but do not wait here */
3304f48ad614SDennis Dalessandro atomic_set(&dd->sdma_unfreeze_count, dd->num_sdma);
3305f48ad614SDennis Dalessandro
3306f48ad614SDennis Dalessandro /* tell all engines to stop running and wait */
3307f48ad614SDennis Dalessandro for (i = 0; i < dd->num_sdma; i++)
3308f48ad614SDennis Dalessandro sdma_process_event(&dd->per_sdma[i], event);
3309f48ad614SDennis Dalessandro
3310f48ad614SDennis Dalessandro /* sdma_freeze() will wait for all engines to have stopped */
3311f48ad614SDennis Dalessandro }
3312f48ad614SDennis Dalessandro
3313f48ad614SDennis Dalessandro /*
3314f48ad614SDennis Dalessandro * SPC freeze handling for SDMA engines. Called when the driver knows
3315f48ad614SDennis Dalessandro * the SPC is fully frozen.
3316f48ad614SDennis Dalessandro */
sdma_freeze(struct hfi1_devdata * dd)3317f48ad614SDennis Dalessandro void sdma_freeze(struct hfi1_devdata *dd)
3318f48ad614SDennis Dalessandro {
3319f48ad614SDennis Dalessandro int i;
3320f48ad614SDennis Dalessandro int ret;
3321f48ad614SDennis Dalessandro
3322f48ad614SDennis Dalessandro /*
3323f48ad614SDennis Dalessandro * Make sure all engines have moved out of the running state before
3324f48ad614SDennis Dalessandro * continuing.
3325f48ad614SDennis Dalessandro */
3326f48ad614SDennis Dalessandro ret = wait_event_interruptible(dd->sdma_unfreeze_wq,
3327f48ad614SDennis Dalessandro atomic_read(&dd->sdma_unfreeze_count) <=
3328f48ad614SDennis Dalessandro 0);
3329f48ad614SDennis Dalessandro /* interrupted or count is negative, then unloading - just exit */
3330f48ad614SDennis Dalessandro if (ret || atomic_read(&dd->sdma_unfreeze_count) < 0)
3331f48ad614SDennis Dalessandro return;
3332f48ad614SDennis Dalessandro
3333f48ad614SDennis Dalessandro /* set up the count for the next wait */
3334f48ad614SDennis Dalessandro atomic_set(&dd->sdma_unfreeze_count, dd->num_sdma);
3335f48ad614SDennis Dalessandro
3336f48ad614SDennis Dalessandro /* tell all engines that the SPC is frozen, they can start cleaning */
3337f48ad614SDennis Dalessandro for (i = 0; i < dd->num_sdma; i++)
3338f48ad614SDennis Dalessandro sdma_process_event(&dd->per_sdma[i], sdma_event_e81_hw_frozen);
3339f48ad614SDennis Dalessandro
3340f48ad614SDennis Dalessandro /*
3341f48ad614SDennis Dalessandro * Wait for everyone to finish software clean before exiting. The
3342f48ad614SDennis Dalessandro * software clean will read engine CSRs, so must be completed before
3343f48ad614SDennis Dalessandro * the next step, which will clear the engine CSRs.
3344f48ad614SDennis Dalessandro */
3345f48ad614SDennis Dalessandro (void)wait_event_interruptible(dd->sdma_unfreeze_wq,
3346f48ad614SDennis Dalessandro atomic_read(&dd->sdma_unfreeze_count) <= 0);
3347f48ad614SDennis Dalessandro /* no need to check results - done no matter what */
3348f48ad614SDennis Dalessandro }
3349f48ad614SDennis Dalessandro
3350f48ad614SDennis Dalessandro /*
3351f48ad614SDennis Dalessandro * SPC freeze handling for the SDMA engines. Called after the SPC is unfrozen.
3352f48ad614SDennis Dalessandro *
3353f48ad614SDennis Dalessandro * The SPC freeze acts like a SDMA halt and a hardware clean combined. All
3354f48ad614SDennis Dalessandro * that is left is a software clean. We could do it after the SPC is fully
3355f48ad614SDennis Dalessandro * frozen, but then we'd have to add another state to wait for the unfreeze.
3356f48ad614SDennis Dalessandro * Instead, just defer the software clean until the unfreeze step.
3357f48ad614SDennis Dalessandro */
sdma_unfreeze(struct hfi1_devdata * dd)3358f48ad614SDennis Dalessandro void sdma_unfreeze(struct hfi1_devdata *dd)
3359f48ad614SDennis Dalessandro {
3360f48ad614SDennis Dalessandro int i;
3361f48ad614SDennis Dalessandro
3362f48ad614SDennis Dalessandro /* tell all engines start freeze clean up */
3363f48ad614SDennis Dalessandro for (i = 0; i < dd->num_sdma; i++)
3364f48ad614SDennis Dalessandro sdma_process_event(&dd->per_sdma[i],
3365f48ad614SDennis Dalessandro sdma_event_e82_hw_unfreeze);
3366f48ad614SDennis Dalessandro }
3367f48ad614SDennis Dalessandro
3368f48ad614SDennis Dalessandro /**
3369f48ad614SDennis Dalessandro * _sdma_engine_progress_schedule() - schedule progress on engine
3370f48ad614SDennis Dalessandro * @sde: sdma_engine to schedule progress
3371f48ad614SDennis Dalessandro *
3372f48ad614SDennis Dalessandro */
_sdma_engine_progress_schedule(struct sdma_engine * sde)3373f48ad614SDennis Dalessandro void _sdma_engine_progress_schedule(
3374f48ad614SDennis Dalessandro struct sdma_engine *sde)
3375f48ad614SDennis Dalessandro {
3376f48ad614SDennis Dalessandro trace_hfi1_sdma_engine_progress(sde, sde->progress_mask);
3377f48ad614SDennis Dalessandro /* assume we have selected a good cpu */
3378f48ad614SDennis Dalessandro write_csr(sde->dd,
3379f48ad614SDennis Dalessandro CCE_INT_FORCE + (8 * (IS_SDMA_START / 64)),
3380f48ad614SDennis Dalessandro sde->progress_mask);
3381f48ad614SDennis Dalessandro }
3382