1 | /* GRTM CCSDS Telemetry Encoder driver |
---|
2 | * |
---|
3 | * COPYRIGHT (c) 2007. |
---|
4 | * Cobham Gaisler AB. |
---|
5 | * |
---|
6 | * The license and distribution terms for this file may be |
---|
7 | * found in the file LICENSE in this distribution or at |
---|
8 | * http://www.rtems.org/license/LICENSE. |
---|
9 | */ |
---|
10 | |
---|
11 | #include <bsp.h> |
---|
12 | #include <rtems/libio.h> |
---|
13 | #include <stdlib.h> |
---|
14 | #include <stdio.h> |
---|
15 | #include <string.h> |
---|
16 | #include <assert.h> |
---|
17 | #include <ctype.h> |
---|
18 | #include <rtems/bspIo.h> |
---|
19 | |
---|
20 | #include <drvmgr/drvmgr.h> |
---|
21 | #include <ambapp.h> |
---|
22 | #include <drvmgr/ambapp_bus.h> |
---|
23 | #include <bsp/grtm.h> |
---|
24 | |
---|
25 | #include <grlib_impl.h> |
---|
26 | |
---|
27 | /* |
---|
28 | #define DEBUG |
---|
29 | #define DEBUGFUNCS |
---|
30 | */ |
---|
31 | |
---|
32 | #include <bsp/debug_defs.h> |
---|
33 | |
---|
34 | /* GRTM register map */ |
---|
35 | struct grtm_regs { |
---|
36 | volatile unsigned int dma_ctrl; /* DMA Control Register (0x00) */ |
---|
37 | volatile unsigned int dma_status; /* DMA Status Register (0x04) */ |
---|
38 | volatile unsigned int dma_len; /* DMA Length Register (0x08) */ |
---|
39 | volatile unsigned int dma_bd; /* DMA Descriptor Pointer Register (0x0c) */ |
---|
40 | |
---|
41 | volatile unsigned int dma_cfg; /* DMA Configuration Register (0x10) */ |
---|
42 | volatile unsigned int revision; /* GRTM Revision Register (0x14) */ |
---|
43 | |
---|
44 | int unused0[(0x80-0x18)/4]; |
---|
45 | |
---|
46 | volatile unsigned int ctrl; /* TM Control Register (0x80) */ |
---|
47 | volatile unsigned int status; /* TM Status Register (0x84) */ |
---|
48 | volatile unsigned int cfg; /* TM Configuration Register (0x88) */ |
---|
49 | volatile unsigned int size; /* TM Size Register (0x8c) */ |
---|
50 | |
---|
51 | volatile unsigned int phy; /* TM Physical Layer Register (0x90) */ |
---|
52 | volatile unsigned int code; /* TM Coding Sub-Layer Register (0x94) */ |
---|
53 | volatile unsigned int asmr; /* TM Attached Synchronization Marker Register (0x98) */ |
---|
54 | |
---|
55 | int unused1; |
---|
56 | |
---|
57 | volatile unsigned int all_frm; /* TM All Frames Generation Register (0xa0) */ |
---|
58 | volatile unsigned int mst_frm; /* TM Master Channel Frame Generation Register (0xa4) */ |
---|
59 | volatile unsigned int idle_frm; /* TM Idle Frame Generation Register (0xa8) */ |
---|
60 | |
---|
61 | int unused2[(0xc0-0xac)/4]; |
---|
62 | |
---|
63 | volatile unsigned int fsh[4]; /* TM FSH/Insert Zone Registers (0xc0..0xcc) */ |
---|
64 | |
---|
65 | volatile unsigned int ocf; /* TM Operational Control Field Register (0xd0) */ |
---|
66 | }; |
---|
67 | |
---|
68 | /* DMA Control Register (0x00) */ |
---|
69 | #define GRTM_DMA_CTRL_EN_BIT 0 |
---|
70 | #define GRTM_DMA_CTRL_IE_BIT 1 |
---|
71 | #define GRTM_DMA_CTRL_TXRST_BIT 2 |
---|
72 | #define GRTM_DMA_CTRL_RST_BIT 3 |
---|
73 | #define GRTM_DMA_CTRL_TFIE_BIT 4 |
---|
74 | |
---|
75 | #define GRTM_DMA_CTRL_EN (1<<GRTM_DMA_CTRL_EN_BIT) |
---|
76 | #define GRTM_DMA_CTRL_IE (1<<GRTM_DMA_CTRL_IE_BIT) |
---|
77 | #define GRTM_DMA_CTRL_TXRST (1<<GRTM_DMA_CTRL_TXRST_BIT) |
---|
78 | #define GRTM_DMA_CTRL_RST (1<<GRTM_DMA_CTRL_RST_BIT) |
---|
79 | #define GRTM_DMA_CTRL_TFIE (1<<GRTM_DMA_CTRL_TFIE_BIT) |
---|
80 | |
---|
81 | /* DMA Status Register (0x04) */ |
---|
82 | #define GRTM_DMA_STS_TE_BIT 0 |
---|
83 | #define GRTM_DMA_STS_TI_BIT 1 |
---|
84 | #define GRTM_DMA_STS_TA_BIT 2 |
---|
85 | #define GRTM_DMA_STS_TFF_BIT 3 |
---|
86 | #define GRTM_DMA_STS_TFS_BIT 4 |
---|
87 | |
---|
88 | #define GRTM_DMA_STS_TE (1<<GRTM_DMA_STS_TE_BIT) |
---|
89 | #define GRTM_DMA_STS_TI (1<<GRTM_DMA_STS_TI_BIT) |
---|
90 | #define GRTM_DMA_STS_TA (1<<GRTM_DMA_STS_TA_BIT) |
---|
91 | #define GRTM_DMA_STS_TFF (1<<GRTM_DMA_STS_TFF_BIT) |
---|
92 | #define GRTM_DMA_STS_TFS (1<<GRTM_DMA_STS_TFS_BIT) |
---|
93 | #define GRTM_DMA_STS_ALL 0x1f |
---|
94 | |
---|
95 | /* DMA Length Register (0x08) */ |
---|
96 | #define GRTM_DMA_LEN_LEN_BIT 0 |
---|
97 | #define GRTM_DMA_LEN_LIM_BIT 16 |
---|
98 | |
---|
99 | #define GRTM_DMA_LEN_LEN (0x7ff<<GRTM_DMA_LEN_LEN_BIT) |
---|
100 | #define GRTM_DMA_LEN_LIM (0x3ff<<GRTM_DMA_LEN_LIM_BIT) |
---|
101 | |
---|
102 | /* DMA Descriptor Pointer Register (0x0c) */ |
---|
103 | #define GRTM_DMA_BD_INDEX_BIT 0 |
---|
104 | #define GRTM_DMA_BD_BASE_BIT 10 |
---|
105 | |
---|
106 | #define GRTM_DMA_BD_INDEX (0x3ff<<GRTM_DMA_BD_INDEX_BIT) |
---|
107 | #define GRTM_DMA_BD_BASE (0xfffffc<<GRTM_DMA_BD_BASE_BIT) |
---|
108 | |
---|
109 | /* DMA Configuration Register (0x10) */ |
---|
110 | #define GRTM_DMA_CFG_BLKSZ_BIT 0 |
---|
111 | #define GRTM_DMA_CFG_FIFOSZ_BIT 16 |
---|
112 | |
---|
113 | #define GRTM_DMA_CFG_BLKSZ (0xffff<<GRTM_DMA_CFG_BLKSZ_BIT) |
---|
114 | #define GRTM_DMA_CFG_FIFOSZ (0xffff<<GRTM_DMA_CFG_FIFOSZ_BIT) |
---|
115 | |
---|
116 | /* TM Control Register (0x80) */ |
---|
117 | #define GRTM_CTRL_EN_BIT 0 |
---|
118 | |
---|
119 | #define GRTM_CTRL_EN (1<<GRTM_CTRL_EN_BIT) |
---|
120 | |
---|
121 | /* TM Status Register (0x84) - Unused */ |
---|
122 | |
---|
123 | /* TM Configuration Register (0x88) */ |
---|
124 | #define GRTM_CFG_SC_BIT 0 |
---|
125 | #define GRTM_CFG_SP_BIT 1 |
---|
126 | #define GRTM_CFG_CE_BIT 2 |
---|
127 | #define GRTM_CFG_NRZ_BIT 3 |
---|
128 | #define GRTM_CFG_PSR_BIT 4 |
---|
129 | #define GRTM_CFG_TE_BIT 5 |
---|
130 | #define GRTM_CFG_RSDEP_BIT 6 |
---|
131 | #define GRTM_CFG_RS_BIT 9 |
---|
132 | #define GRTM_CFG_AASM_BIT 11 |
---|
133 | #define GRTM_CFG_FECF_BIT 12 |
---|
134 | #define GRTM_CFG_OCF_BIT 13 |
---|
135 | #define GRTM_CFG_EVC_BIT 14 |
---|
136 | #define GRTM_CFG_IDLE_BIT 15 |
---|
137 | #define GRTM_CFG_FSH_BIT 16 |
---|
138 | #define GRTM_CFG_MCG_BIT 17 |
---|
139 | #define GRTM_CFG_IZ_BIT 18 |
---|
140 | #define GRTM_CFG_FHEC_BIT 19 |
---|
141 | #define GRTM_CFG_AOS_BIT 20 |
---|
142 | #define GRTM_CFG_CIF_BIT 21 |
---|
143 | #define GRTM_CFG_OCFB_BIT 22 |
---|
144 | |
---|
145 | #define GRTM_CFG_SC (1<<GRTM_CFG_SC_BIT) |
---|
146 | #define GRTM_CFG_SP (1<<GRTM_CFG_SP_BIT) |
---|
147 | #define GRTM_CFG_CE (1<<GRTM_CFG_CE_BIT) |
---|
148 | #define GRTM_CFG_NRZ (1<<GRTM_CFG_NRZ_BIT) |
---|
149 | #define GRTM_CFG_PSR (1<<GRTM_CFG_PSR_BIT) |
---|
150 | #define GRTM_CFG_TE (1<<GRTM_CFG_TE_BIT) |
---|
151 | #define GRTM_CFG_RSDEP (0x7<<GRTM_CFG_RSDEP_BIT) |
---|
152 | #define GRTM_CFG_RS (0x3<<GRTM_CFG_RS_BIT) |
---|
153 | #define GRTM_CFG_AASM (1<<GRTM_CFG_AASM_BIT) |
---|
154 | #define GRTM_CFG_FECF (1<<GRTM_CFG_FECF_BIT) |
---|
155 | #define GRTM_CFG_OCF (1<<GRTM_CFG_OCF_BIT) |
---|
156 | #define GRTM_CFG_EVC (1<<GRTM_CFG_EVC_BIT) |
---|
157 | #define GRTM_CFG_IDLE (1<<GRTM_CFG_IDLE_BIT) |
---|
158 | #define GRTM_CFG_FSH (1<<GRTM_CFG_FSH_BIT) |
---|
159 | #define GRTM_CFG_MCG (1<<GRTM_CFG_MCG_BIT) |
---|
160 | #define GRTM_CFG_IZ (1<<GRTM_CFG_IZ_BIT) |
---|
161 | #define GRTM_CFG_FHEC (1<<GRTM_CFG_FHEC_BIT) |
---|
162 | #define GRTM_CFG_AOS (1<<GRTM_CFG_AOS_BIT) |
---|
163 | #define GRTM_CFG_CIF (1<<GRTM_CFG_CIF_BIT) |
---|
164 | #define GRTM_CFG_OCFB (1<<GRTM_CFG_OCFB_BIT) |
---|
165 | |
---|
166 | /* TM Size Register (0x8c) */ |
---|
167 | #define GRTM_SIZE_BLKSZ_BIT 0 |
---|
168 | #define GRTM_SIZE_FIFOSZ_BIT 8 |
---|
169 | #define GRTM_SIZE_LEN_BIT 20 |
---|
170 | |
---|
171 | #define GRTM_SIZE_BLKSZ (0xff<<GRTM_SIZE_BLKSZ_BIT) |
---|
172 | #define GRTM_SIZE_FIFOSZ (0xfff<<GRTM_SIZE_FIFOSZ_BIT) |
---|
173 | #define GRTM_SIZE_LEN (0xfff<<GRTM_SIZE_LEN_BIT) |
---|
174 | |
---|
175 | /* TM Physical Layer Register (0x90) */ |
---|
176 | #define GRTM_PHY_SUB_BIT 0 |
---|
177 | #define GRTM_PHY_SCF_BIT 15 |
---|
178 | #define GRTM_PHY_SYM_BIT 16 |
---|
179 | #define GRTM_PHY_SF_BIT 31 |
---|
180 | |
---|
181 | #define GRTM_PHY_SUB (0x7fff<<GRTM_PHY_SUB_BIT) |
---|
182 | #define GRTM_PHY_SCF (1<<GRTM_PHY_SCF_BIT) |
---|
183 | #define GRTM_PHY_SYM (0x7fff<<GRTM_PHY_SYM_BIT) |
---|
184 | #define GRTM_PHY_SF (1<<GRTM_PHY_SF_BIT) |
---|
185 | |
---|
186 | /* TM Coding Sub-Layer Register (0x94) */ |
---|
187 | #define GRTM_CODE_SC_BIT 0 |
---|
188 | #define GRTM_CODE_SP_BIT 1 |
---|
189 | #define GRTM_CODE_CERATE_BIT 2 |
---|
190 | #define GRTM_CODE_CE_BIT 5 |
---|
191 | #define GRTM_CODE_NRZ_BIT 6 |
---|
192 | #define GRTM_CODE_PSR_BIT 7 |
---|
193 | #define GRTM_CODE_RS8_BIT 11 |
---|
194 | #define GRTM_CODE_RSDEP_BIT 12 |
---|
195 | #define GRTM_CODE_RS_BIT 15 |
---|
196 | #define GRTM_CODE_AASM_BIT 16 |
---|
197 | #define GRTM_CODE_CSEL_BIT 17 |
---|
198 | |
---|
199 | #define GRTM_CODE_SC (1<<GRTM_CODE_SC_BIT) |
---|
200 | #define GRTM_CODE_SP (1<<GRTM_CODE_SP_BIT) |
---|
201 | #define GRTM_CODE_CERATE (0x7<<GRTM_CODE_CERATE_BIT) |
---|
202 | #define GRTM_CODE_CE (1<<GRTM_CODE_CE_BIT) |
---|
203 | #define GRTM_CODE_NRZ (1<<GRTM_CODE_NRZ_BIT) |
---|
204 | #define GRTM_CODE_PSR (1<<GRTM_CODE_PSR_BIT) |
---|
205 | #define GRTM_CODE_RS8 (1<<GRTM_CODE_RS8_BIT) |
---|
206 | #define GRTM_CODE_RSDEP (0x7<<GRTM_CODE_RSDEP_BIT) |
---|
207 | #define GRTM_CODE_RS (1<<GRTM_CODE_RS_BIT) |
---|
208 | #define GRTM_CODE_AASM (1<<GRTM_CODE_AASM_BIT) |
---|
209 | #define GRTM_CODE_CSEL (0x3<<GRTM_CODE_CSEL_BIT) |
---|
210 | |
---|
211 | /* TM Attached Synchronization Marker Register (0x98) */ |
---|
212 | #define GRTM_ASM_BIT 0 |
---|
213 | |
---|
214 | #define GRTM_ASM 0xffffffff |
---|
215 | |
---|
216 | /* TM All Frames Generation Register (0xa0) */ |
---|
217 | #define GRTM_ALL_LEN_BIT 0 |
---|
218 | #define GRTM_ALL_VER_BIT 12 |
---|
219 | #define GRTM_ALL_FHEC_BIT 14 |
---|
220 | #define GRTM_ALL_FECF_BIT 15 |
---|
221 | #define GRTM_ALL_IZ_BIT 16 |
---|
222 | #define GRTM_ALL_IZLEN_BIT 17 |
---|
223 | |
---|
224 | #define GRTM_ALL_LEN (0x7ff<<GRTM_ALL_LEN_BIT) |
---|
225 | #define GRTM_ALL_VER (0x3<<GRTM_ALL_VER_BIT) |
---|
226 | #define GRTM_ALL_FHEC (1<<GRTM_ALL_FHEC_BIT) |
---|
227 | #define GRTM_ALL_FECF (1<<GRTM_ALL_FECF_BIT) |
---|
228 | #define GRTM_ALL_IZ (1<<GRTM_ALL_IZ_BIT) |
---|
229 | #define GRTM_ALL_IZLEN (0x1f<<GRTM_ALL_IZLEN_BIT) |
---|
230 | |
---|
231 | /* TM Master Channel Frame Generation Register (0xa4) */ |
---|
232 | #define GRTM_MST_OW_BIT 0 |
---|
233 | #define GRTM_MST_OCF_BIT 1 |
---|
234 | #define GRTM_MST_FSH_BIT 2 |
---|
235 | #define GRTM_MST_MC_BIT 3 |
---|
236 | #define GRTM_MST_MCCNTR_BIT 24 |
---|
237 | |
---|
238 | #define GRTM_MST_OW (1<<GRTM_MST_OW_BIT) |
---|
239 | #define GRTM_MST_OCF (1<<GRTM_MST_OCF_BIT) |
---|
240 | #define GRTM_MST_FSH (1<<GRTM_MST_FSH_BIT) |
---|
241 | #define GRTM_MST_MC (0xff<<GRTM_MST_MC_BIT) |
---|
242 | |
---|
243 | /* TM Idle Frame Generation Register (0xa8) */ |
---|
244 | #define GRTM_IDLE_SCID_BIT 0 |
---|
245 | #define GRTM_IDLE_VCID_BIT 10 |
---|
246 | #define GRTM_IDLE_MC_BIT 16 |
---|
247 | #define GRTM_IDLE_VCC_BIT 17 |
---|
248 | #define GRTM_IDLE_FSH_BIT 18 |
---|
249 | #define GRTM_IDLE_EVC_BIT 19 |
---|
250 | #define GRTM_IDLE_OCF_BIT 20 |
---|
251 | #define GRTM_IDLE_IDLE_BIT 21 |
---|
252 | #define GRTM_IDLE_MCCNTR_BIT 24 |
---|
253 | |
---|
254 | #define GRTM_IDLE_SCID (0x3ff<<GRTM_IDLE_SCID_BIT) |
---|
255 | #define GRTM_IDLE_VCID (0x3f<<GRTM_IDLE_VCID_BIT) |
---|
256 | #define GRTM_IDLE_MC (1<<GRTM_IDLE_MC_BIT) |
---|
257 | #define GRTM_IDLE_VCC (1<<GRTM_IDLE_VCC_BIT) |
---|
258 | #define GRTM_IDLE_FSH (1<<GRTM_IDLE_FSH_BIT) |
---|
259 | #define GRTM_IDLE_EVC (1<<GRTM_IDLE_EVC_BIT) |
---|
260 | #define GRTM_IDLE_OCF (1<<GRTM_IDLE_OCF_BIT) |
---|
261 | #define GRTM_IDLE_IDLE (1<<GRTM_IDLE_IDLE_BIT) |
---|
262 | #define GRTM_IDLE_MCCNTR (0xff<<GRTM_IDLE_MCCNTR_BIT) |
---|
263 | |
---|
264 | /* TM FSH/Insert Zone Registers (0xc0..0xcc) */ |
---|
265 | #define GRTM_FSH_DATA_BIT 0 |
---|
266 | |
---|
267 | #define GRTM_FSH_DATA 0xffffffff |
---|
268 | |
---|
269 | |
---|
270 | /* TM Operational Control Field Register (0xd0) */ |
---|
271 | #define GRTM_OCF_CLCW_BIT 0 |
---|
272 | |
---|
273 | #define GRTM_OCF_CLCW 0xffffffff |
---|
274 | |
---|
275 | |
---|
276 | /* GRTM Revision 0 */ |
---|
277 | #define GRTM_REV0_DMA_CTRL_TXRDY_BIT 5 |
---|
278 | #define GRTM_REV0_DMA_CTRL_TXRDY (1<<GRTM_REV0_DMA_CTRL_TXRDY_BIT) |
---|
279 | |
---|
280 | /* GRTM Revision 1 */ |
---|
281 | #define GRTM_REV1_DMA_STS_TXRDY_BIT 6 |
---|
282 | #define GRTM_REV1_DMA_STS_TXSTAT_BIT 7 |
---|
283 | #define GRTM_REV1_DMA_STS_TXRDY (1<<GRTM_REV1_DMA_STS_TXRDY_BIT) |
---|
284 | #define GRTM_REV1_DMA_STS_TXSTAT (1<<GRTM_REV1_DMA_STS_TXSTAT_BIT) |
---|
285 | |
---|
286 | #define GRTM_REV1_REV_SREV_BIT 0 |
---|
287 | #define GRTM_REV1_REV_MREV_BIT 8 |
---|
288 | #define GRTM_REV1_REV_TIRQ_BIT 16 |
---|
289 | #define GRTM_REV1_REV_SREV (0xff<<GRTM_REV1_REV_SREV_BIT) |
---|
290 | #define GRTM_REV1_REV_MREV (0xff<<GRTM_REV1_REV_MREV_BIT) |
---|
291 | #define GRTM_REV1_REV_TIRQ (1<<GRTM_REV1_REV_TIRQ_BIT) |
---|
292 | |
---|
293 | |
---|
294 | /* GRTM transmit descriptor (0x400 Alignment need) */ |
---|
295 | struct grtm_bd { |
---|
296 | volatile unsigned int ctrl; |
---|
297 | unsigned int address; |
---|
298 | }; |
---|
299 | |
---|
300 | #define GRTM_BD_EN_BIT 0 |
---|
301 | #define GRTM_BD_WR_BIT 1 |
---|
302 | #define GRTM_BD_IE_BIT 2 |
---|
303 | #define GRTM_BD_FECFB_BIT 3 |
---|
304 | #define GRTM_BD_IZB_BIT 4 |
---|
305 | #define GRTM_BD_FHECB_BIT 5 |
---|
306 | #define GRTM_BD_OCFB_BIT 6 |
---|
307 | #define GRTM_BD_FSHB_BIT 7 |
---|
308 | #define GRTM_BD_MCB_BIT 8 |
---|
309 | #define GRTM_BD_VCE_BIT 9 |
---|
310 | #define GRTM_BD_TS_BIT 14 |
---|
311 | #define GRTM_BD_UE_BIT 15 |
---|
312 | |
---|
313 | #define GRTM_BD_EN (1<<GRTM_BD_EN_BIT) |
---|
314 | #define GRTM_BD_WR (1<<GRTM_BD_WR_BIT) |
---|
315 | #define GRTM_BD_IE (1<<GRTM_BD_IE_BIT) |
---|
316 | #define GRTM_BD_FECFB (1<<GRTM_BD_FECFB_BIT) |
---|
317 | #define GRTM_BD_IZB (1<<GRTM_BD_IZB_BIT) |
---|
318 | #define GRTM_BD_FHECB (1<<GRTM_BD_FHECB_BIT) |
---|
319 | #define GRTM_BD_OCFB (1<<GRTM_BD_OCFB_BIT) |
---|
320 | #define GRTM_BD_FSHB (1<<GRTM_BD_FSHB_BIT) |
---|
321 | #define GRTM_BD_MCB (1<<GRTM_BD_MCB_BIT) |
---|
322 | #define GRTM_BD_VCE (1<<GRTM_BD_VCE_BIT) |
---|
323 | #define GRTM_BD_TS (1<<GRTM_BD_TS_BIT) |
---|
324 | #define GRTM_BD_UE (1<<GRTM_BD_UE_BIT) |
---|
325 | |
---|
326 | /* Load register */ |
---|
327 | |
---|
328 | #define READ_REG(address) (*(volatile unsigned int *)address) |
---|
329 | |
---|
330 | /* Driver functions */ |
---|
331 | static rtems_device_driver grtm_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
332 | static rtems_device_driver grtm_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
333 | static rtems_device_driver grtm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
334 | static rtems_device_driver grtm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
335 | static rtems_device_driver grtm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
336 | static rtems_device_driver grtm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg); |
---|
337 | |
---|
338 | #define GRTM_DRIVER_TABLE_ENTRY { grtm_initialize, grtm_open, grtm_close, grtm_read, grtm_write, grtm_ioctl } |
---|
339 | |
---|
340 | static rtems_driver_address_table grtm_driver = GRTM_DRIVER_TABLE_ENTRY; |
---|
341 | |
---|
342 | /* Structure that connects BD with SoftWare Frame */ |
---|
343 | struct grtm_ring { |
---|
344 | struct grtm_ring *next; |
---|
345 | struct grtm_bd *bd; |
---|
346 | struct grtm_frame *frm; |
---|
347 | }; |
---|
348 | |
---|
349 | struct grtm_priv { |
---|
350 | struct drvmgr_dev *dev; /* Driver manager device */ |
---|
351 | char devName[32]; /* Device Name */ |
---|
352 | struct grtm_regs *regs; |
---|
353 | int irq; |
---|
354 | int minor; |
---|
355 | int subrev; /* GRTM Revision */ |
---|
356 | SPIN_DECLARE(devlock); /* spin-lock ISR protection */ |
---|
357 | |
---|
358 | int open; |
---|
359 | int running; |
---|
360 | |
---|
361 | struct grtm_bd *bds; |
---|
362 | void *_bds; |
---|
363 | |
---|
364 | /* Interrupt generation */ |
---|
365 | int enable_cnt_curr;/* Down counter, when 0 the interrupt bit is set for next descriptor */ |
---|
366 | volatile int handling_transmission; /* Tells ISR if user are active changing descriptors/queues */ |
---|
367 | |
---|
368 | struct grtm_ring *_ring; /* Root of ring */ |
---|
369 | struct grtm_ring *ring; /* Next ring to use for new frames to be transmitted */ |
---|
370 | struct grtm_ring *ring_end; /* Oldest activated ring used */ |
---|
371 | |
---|
372 | /* Collections of frames Ready to sent/ Scheduled for transmission/Sent |
---|
373 | * frames waiting for the user to reclaim |
---|
374 | */ |
---|
375 | struct grtm_list ready; /* Frames Waiting for free BDs */ |
---|
376 | struct grtm_list scheduled; /* Frames in BDs beeing transmitted */ |
---|
377 | struct grtm_list sent; /* Sent Frames waiting for user to reclaim and reuse */ |
---|
378 | |
---|
379 | /* Number of frames in the lists */ |
---|
380 | int ready_cnt; /* Number of ready frames */ |
---|
381 | int scheduled_cnt; /* Number of scheduled frames */ |
---|
382 | int sent_cnt; /* Number of sent frames */ |
---|
383 | |
---|
384 | struct grtm_ioc_hw hw_avail; /* Hardware support available */ |
---|
385 | struct grtm_ioc_config config; |
---|
386 | struct grtm_ioc_stats stats; |
---|
387 | |
---|
388 | rtems_id sem_tx; |
---|
389 | }; |
---|
390 | |
---|
391 | /* Prototypes */ |
---|
392 | static void *grtm_memalign(unsigned int boundary, unsigned int length, void *realbuf); |
---|
393 | static void grtm_hw_reset(struct grtm_priv *pDev); |
---|
394 | static void grtm_interrupt(void *arg); |
---|
395 | |
---|
396 | /* Common Global Variables */ |
---|
397 | static rtems_id grtm_dev_sem; |
---|
398 | static int grtm_driver_io_registered = 0; |
---|
399 | static rtems_device_major_number grtm_driver_io_major = 0; |
---|
400 | |
---|
401 | /******************* Driver manager interface ***********************/ |
---|
402 | |
---|
403 | /* Driver prototypes */ |
---|
404 | static int grtm_register_io(rtems_device_major_number *m); |
---|
405 | static int grtm_device_init(struct grtm_priv *pDev); |
---|
406 | |
---|
407 | static int grtm_init2(struct drvmgr_dev *dev); |
---|
408 | static int grtm_init3(struct drvmgr_dev *dev); |
---|
409 | |
---|
410 | static struct drvmgr_drv_ops grtm_ops = |
---|
411 | { |
---|
412 | {NULL, grtm_init2, grtm_init3, NULL}, |
---|
413 | NULL, |
---|
414 | NULL |
---|
415 | }; |
---|
416 | |
---|
417 | static struct amba_dev_id grtm_ids[] = |
---|
418 | { |
---|
419 | {VENDOR_GAISLER, GAISLER_GRTM}, |
---|
420 | {0, 0} /* Mark end of table */ |
---|
421 | }; |
---|
422 | |
---|
423 | static struct amba_drv_info grtm_drv_info = |
---|
424 | { |
---|
425 | { |
---|
426 | DRVMGR_OBJ_DRV, /* Driver */ |
---|
427 | NULL, /* Next driver */ |
---|
428 | NULL, /* Device list */ |
---|
429 | DRIVER_AMBAPP_GAISLER_GRTM_ID, /* Driver ID */ |
---|
430 | "GRTM_DRV", /* Driver Name */ |
---|
431 | DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */ |
---|
432 | &grtm_ops, |
---|
433 | NULL, /* Funcs */ |
---|
434 | 0, /* No devices yet */ |
---|
435 | 0, |
---|
436 | }, |
---|
437 | &grtm_ids[0] |
---|
438 | }; |
---|
439 | |
---|
440 | void grtm_register_drv (void) |
---|
441 | { |
---|
442 | DBG("Registering GRTM driver\n"); |
---|
443 | drvmgr_drv_register(&grtm_drv_info.general); |
---|
444 | } |
---|
445 | |
---|
446 | static int grtm_init2(struct drvmgr_dev *dev) |
---|
447 | { |
---|
448 | struct grtm_priv *priv; |
---|
449 | |
---|
450 | DBG("GRTM[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name); |
---|
451 | priv = dev->priv = grlib_calloc(1, sizeof(*priv)); |
---|
452 | if ( !priv ) |
---|
453 | return DRVMGR_NOMEM; |
---|
454 | priv->dev = dev; |
---|
455 | |
---|
456 | /* This core will not find other cores, so we wait for init2() */ |
---|
457 | |
---|
458 | return DRVMGR_OK; |
---|
459 | } |
---|
460 | |
---|
461 | static int grtm_init3(struct drvmgr_dev *dev) |
---|
462 | { |
---|
463 | struct grtm_priv *priv; |
---|
464 | char prefix[32]; |
---|
465 | rtems_status_code status; |
---|
466 | |
---|
467 | priv = dev->priv; |
---|
468 | |
---|
469 | /* Do initialization */ |
---|
470 | |
---|
471 | if ( grtm_driver_io_registered == 0) { |
---|
472 | /* Register the I/O driver only once for all cores */ |
---|
473 | if ( grtm_register_io(&grtm_driver_io_major) ) { |
---|
474 | /* Failed to register I/O driver */ |
---|
475 | dev->priv = NULL; |
---|
476 | return DRVMGR_FAIL; |
---|
477 | } |
---|
478 | |
---|
479 | grtm_driver_io_registered = 1; |
---|
480 | } |
---|
481 | |
---|
482 | /* I/O system registered and initialized |
---|
483 | * Now we take care of device initialization. |
---|
484 | */ |
---|
485 | if ( grtm_device_init(priv) ) { |
---|
486 | return DRVMGR_FAIL; |
---|
487 | } |
---|
488 | |
---|
489 | /* Get Filesystem name prefix */ |
---|
490 | prefix[0] = '\0'; |
---|
491 | if ( drvmgr_get_dev_prefix(dev, prefix) ) { |
---|
492 | /* Failed to get prefix, make sure of a unique FS name |
---|
493 | * by using the driver minor. |
---|
494 | */ |
---|
495 | sprintf(priv->devName, "/dev/grtm%d", dev->minor_drv); |
---|
496 | } else { |
---|
497 | /* Got special prefix, this means we have a bus prefix |
---|
498 | * And we should use our "bus minor" |
---|
499 | */ |
---|
500 | sprintf(priv->devName, "/dev/%sgrtm%d", prefix, dev->minor_bus); |
---|
501 | } |
---|
502 | |
---|
503 | SPIN_INIT(&priv->devlock, priv->devName); |
---|
504 | |
---|
505 | /* Register Device */ |
---|
506 | status = rtems_io_register_name(priv->devName, grtm_driver_io_major, dev->minor_drv); |
---|
507 | if (status != RTEMS_SUCCESSFUL) { |
---|
508 | return DRVMGR_FAIL; |
---|
509 | } |
---|
510 | |
---|
511 | return DRVMGR_OK; |
---|
512 | } |
---|
513 | |
---|
514 | /******************* Driver Implementation ***********************/ |
---|
515 | |
---|
516 | static int grtm_register_io(rtems_device_major_number *m) |
---|
517 | { |
---|
518 | rtems_status_code r; |
---|
519 | |
---|
520 | if ((r = rtems_io_register_driver(0, &grtm_driver, m)) == RTEMS_SUCCESSFUL) { |
---|
521 | DBG("GRTM driver successfully registered, major: %d\n", *m); |
---|
522 | } else { |
---|
523 | switch(r) { |
---|
524 | case RTEMS_TOO_MANY: |
---|
525 | printk("GRTM rtems_io_register_driver failed: RTEMS_TOO_MANY\n"); |
---|
526 | return -1; |
---|
527 | case RTEMS_INVALID_NUMBER: |
---|
528 | printk("GRTM rtems_io_register_driver failed: RTEMS_INVALID_NUMBER\n"); |
---|
529 | return -1; |
---|
530 | case RTEMS_RESOURCE_IN_USE: |
---|
531 | printk("GRTM rtems_io_register_driver failed: RTEMS_RESOURCE_IN_USE\n"); |
---|
532 | return -1; |
---|
533 | default: |
---|
534 | printk("GRTM rtems_io_register_driver failed\n"); |
---|
535 | return -1; |
---|
536 | } |
---|
537 | } |
---|
538 | return 0; |
---|
539 | } |
---|
540 | |
---|
541 | static int grtm_device_init(struct grtm_priv *pDev) |
---|
542 | { |
---|
543 | struct amba_dev_info *ambadev; |
---|
544 | struct ambapp_core *pnpinfo; |
---|
545 | union drvmgr_key_value *value; |
---|
546 | |
---|
547 | /* Get device information from AMBA PnP information */ |
---|
548 | ambadev = (struct amba_dev_info *)pDev->dev->businfo; |
---|
549 | if ( ambadev == NULL ) { |
---|
550 | return -1; |
---|
551 | } |
---|
552 | pnpinfo = &ambadev->info; |
---|
553 | pDev->irq = pnpinfo->irq; |
---|
554 | pDev->regs = (struct grtm_regs *)pnpinfo->apb_slv->start; |
---|
555 | pDev->minor = pDev->dev->minor_drv; |
---|
556 | pDev->open = 0; |
---|
557 | pDev->running = 0; |
---|
558 | |
---|
559 | /* Create Binary RX Semaphore with count = 0 */ |
---|
560 | if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'M', '0' + pDev->minor), |
---|
561 | 0, |
---|
562 | RTEMS_FIFO|RTEMS_SIMPLE_BINARY_SEMAPHORE|RTEMS_NO_INHERIT_PRIORITY|\ |
---|
563 | RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, |
---|
564 | 0, |
---|
565 | &pDev->sem_tx) != RTEMS_SUCCESSFUL ) { |
---|
566 | return -1; |
---|
567 | } |
---|
568 | |
---|
569 | /* Allocate Memory for Buffer Descriptor Table, or let user provide a custom |
---|
570 | * address. |
---|
571 | */ |
---|
572 | value = drvmgr_dev_key_get(pDev->dev, "bdTabAdr", DRVMGR_KT_POINTER); |
---|
573 | if ( value ) { |
---|
574 | pDev->bds = (struct grtm_bd *)value->ptr; |
---|
575 | pDev->_bds = (void *)value->ptr; |
---|
576 | } else { |
---|
577 | pDev->bds = (struct grtm_bd *)grtm_memalign(0x400, 0x400, &pDev->_bds); |
---|
578 | } |
---|
579 | if ( !pDev->bds ) { |
---|
580 | DBG("GRTM: Failed to allocate descriptor table\n"); |
---|
581 | return -1; |
---|
582 | } |
---|
583 | memset(pDev->bds, 0, 0x400); |
---|
584 | |
---|
585 | pDev->_ring = grlib_malloc(sizeof(*pDev->_ring) * 128); |
---|
586 | if ( !pDev->_ring ) { |
---|
587 | return -1; |
---|
588 | } |
---|
589 | |
---|
590 | /* Reset Hardware before attaching IRQ handler */ |
---|
591 | grtm_hw_reset(pDev); |
---|
592 | |
---|
593 | /* Read SUB revision number, ignore */ |
---|
594 | pDev->subrev = (READ_REG(&pDev->regs->revision) & GRTM_REV1_REV_SREV) |
---|
595 | >> GRTM_REV1_REV_SREV_BIT; |
---|
596 | |
---|
597 | return 0; |
---|
598 | } |
---|
599 | |
---|
600 | |
---|
601 | static inline void grtm_list_clr(struct grtm_list *list) |
---|
602 | { |
---|
603 | list->head = NULL; |
---|
604 | list->tail = NULL; |
---|
605 | } |
---|
606 | |
---|
607 | static void grtm_hw_reset(struct grtm_priv *pDev) |
---|
608 | { |
---|
609 | /* Reset Core */ |
---|
610 | pDev->regs->dma_ctrl = GRTM_DMA_CTRL_RST; |
---|
611 | } |
---|
612 | |
---|
613 | static void grtm_hw_get_implementation(struct grtm_priv *pDev, struct grtm_ioc_hw *hwcfg) |
---|
614 | { |
---|
615 | unsigned int cfg = READ_REG(&pDev->regs->cfg); |
---|
616 | |
---|
617 | hwcfg->cs = (cfg & GRTM_CFG_SC) ? 1:0; |
---|
618 | hwcfg->sp = (cfg & GRTM_CFG_SP) ? 1:0; |
---|
619 | hwcfg->ce = (cfg & GRTM_CFG_CE) ? 1:0; |
---|
620 | hwcfg->nrz = (cfg & GRTM_CFG_NRZ) ? 1:0; |
---|
621 | hwcfg->psr = (cfg & GRTM_CFG_PSR) ? 1:0; |
---|
622 | hwcfg->te = (cfg & GRTM_CFG_TE) ? 1:0; |
---|
623 | hwcfg->rsdep = (cfg & GRTM_CFG_RSDEP)>>GRTM_CFG_RSDEP_BIT; |
---|
624 | hwcfg->rs = (cfg & GRTM_CFG_RS)>>GRTM_CFG_RS_BIT; |
---|
625 | hwcfg->aasm = (cfg & GRTM_CFG_AASM) ? 1:0; |
---|
626 | hwcfg->fecf = (cfg & GRTM_CFG_FECF) ? 1:0; |
---|
627 | hwcfg->ocf = (cfg & GRTM_CFG_OCF) ? 1:0; |
---|
628 | hwcfg->evc = (cfg & GRTM_CFG_EVC) ? 1:0; |
---|
629 | hwcfg->idle = (cfg & GRTM_CFG_IDLE) ? 1:0; |
---|
630 | hwcfg->fsh = (cfg & GRTM_CFG_FSH) ? 1:0; |
---|
631 | hwcfg->mcg = (cfg & GRTM_CFG_MCG) ? 1:0; |
---|
632 | hwcfg->iz = (cfg & GRTM_CFG_IZ) ? 1:0; |
---|
633 | hwcfg->fhec = (cfg & GRTM_CFG_FHEC) ? 1:0; |
---|
634 | hwcfg->aos = (cfg & GRTM_CFG_AOS) ? 1:0; |
---|
635 | hwcfg->cif = (cfg & GRTM_CFG_CIF) ? 1:0; |
---|
636 | hwcfg->ocfb = (cfg & GRTM_CFG_OCFB) ? 1:0; |
---|
637 | |
---|
638 | cfg = READ_REG(&pDev->regs->dma_cfg); |
---|
639 | hwcfg->blk_size = (cfg & GRTM_DMA_CFG_BLKSZ) >> GRTM_DMA_CFG_BLKSZ_BIT; |
---|
640 | hwcfg->fifo_size= (cfg & GRTM_DMA_CFG_FIFOSZ) >> GRTM_DMA_CFG_FIFOSZ_BIT; |
---|
641 | } |
---|
642 | |
---|
643 | |
---|
644 | /* TODO: Implement proper default calculation from hardware configuration */ |
---|
645 | static void grtm_hw_get_default_modes(struct grtm_ioc_config *cfg, struct grtm_ioc_hw *hwcfg) |
---|
646 | { |
---|
647 | cfg->mode = GRTM_MODE_TM; |
---|
648 | cfg->frame_length = 223; |
---|
649 | cfg->limit = 0; /* Make driver auto configure it on START, user may override with non-zero value */ |
---|
650 | cfg->as_marker = 0x1ACFFC1D; |
---|
651 | |
---|
652 | /* Physical */ |
---|
653 | cfg->phy_subrate = 1; |
---|
654 | cfg->phy_symbolrate = 1; |
---|
655 | cfg->phy_opts = 0; |
---|
656 | |
---|
657 | /* Coding Layer */ |
---|
658 | cfg->code_rsdep = 1; |
---|
659 | cfg->code_ce_rate = 0; |
---|
660 | cfg->code_csel = 0; |
---|
661 | cfg->code_opts = 0; |
---|
662 | |
---|
663 | /* All Frame Generation */ |
---|
664 | cfg->all_izlen = 0; |
---|
665 | cfg->all_opts = GRTM_IOC_ALL_FECF; |
---|
666 | |
---|
667 | /* Master Channel Frame Generation */ |
---|
668 | if ( hwcfg->mcg ) { |
---|
669 | cfg->mf_opts = GRTM_IOC_MF_MC; |
---|
670 | } else { |
---|
671 | cfg->mf_opts = 0; |
---|
672 | } |
---|
673 | |
---|
674 | /* Idle Frame Generation */ |
---|
675 | cfg->idle_scid = 0; |
---|
676 | cfg->idle_vcid = 0; |
---|
677 | if ( hwcfg->idle ) { |
---|
678 | cfg->idle_opts = GRTM_IOC_IDLE_EN; |
---|
679 | } else { |
---|
680 | cfg->idle_opts = 0; |
---|
681 | } |
---|
682 | |
---|
683 | /* Interrupt options */ |
---|
684 | cfg->blocking = 0; /* non-blocking mode is default */ |
---|
685 | cfg->enable_cnt = 16; /* generate interrupt every 16 descriptor */ |
---|
686 | cfg->isr_desc_proc = 1; /* Let interrupt handler do descriptor processing */ |
---|
687 | cfg->timeout = RTEMS_NO_TIMEOUT; |
---|
688 | |
---|
689 | } |
---|
690 | |
---|
691 | static void *grtm_memalign(unsigned int boundary, unsigned int length, void *realbuf) |
---|
692 | { |
---|
693 | *(int *)realbuf = (int)grlib_malloc(length+boundary); |
---|
694 | DBG("GRTM: Alloced %d (0x%x) bytes, requested: %d\n",length+boundary,length+boundary,length); |
---|
695 | return (void *)(((*(unsigned int *)realbuf)+boundary) & ~(boundary-1)); |
---|
696 | } |
---|
697 | |
---|
698 | static int grtm_hw_set_config(struct grtm_priv *pDev, struct grtm_ioc_config *cfg, struct grtm_ioc_hw *hwcfg) |
---|
699 | { |
---|
700 | struct grtm_regs *regs = pDev->regs; |
---|
701 | unsigned int tmp; |
---|
702 | unsigned int limit; |
---|
703 | |
---|
704 | if ( cfg->limit == 0 ) { |
---|
705 | /* Calculate Limit */ |
---|
706 | if ( cfg->frame_length > hwcfg->blk_size ) { |
---|
707 | limit = hwcfg->blk_size*2; |
---|
708 | } else { |
---|
709 | limit = cfg->frame_length; |
---|
710 | } |
---|
711 | } else { |
---|
712 | /* Use user configured limit */ |
---|
713 | limit = cfg->limit; |
---|
714 | } |
---|
715 | |
---|
716 | /* Frame Length and Limit */ |
---|
717 | regs->dma_len = (((limit-1) << GRTM_DMA_LEN_LIM_BIT) & GRTM_DMA_LEN_LIM)| |
---|
718 | (((cfg->frame_length-1) << GRTM_DMA_LEN_LEN_BIT) & GRTM_DMA_LEN_LEN); |
---|
719 | |
---|
720 | /* Physical layer options */ |
---|
721 | tmp = (cfg->phy_opts & (GRTM_IOC_PHY_SCF|GRTM_IOC_PHY_SF)) | |
---|
722 | (((cfg->phy_symbolrate-1)<<GRTM_PHY_SYM_BIT) & GRTM_PHY_SYM) | (((cfg->phy_subrate-1)<<GRTM_PHY_SUB_BIT) & GRTM_PHY_SUB); |
---|
723 | regs->phy = tmp; |
---|
724 | |
---|
725 | /* Coding Sub-layer Options */ |
---|
726 | tmp = (cfg->code_opts & GRTM_IOC_CODE_ALL) | ((cfg->code_csel<<GRTM_CODE_CSEL_BIT) & GRTM_CODE_CSEL) | |
---|
727 | (((cfg->code_rsdep-1)<<GRTM_CODE_RSDEP_BIT) & GRTM_CODE_RSDEP) | ((cfg->code_ce_rate<<GRTM_CODE_CERATE_BIT) & GRTM_CODE_CERATE); |
---|
728 | regs->code = tmp; |
---|
729 | |
---|
730 | /* Attached synchronization marker register */ |
---|
731 | regs->asmr = cfg->as_marker; |
---|
732 | |
---|
733 | /* All Frames Generation */ |
---|
734 | tmp = ((cfg->all_opts & GRTM_IOC_ALL_ALL)<<14) | |
---|
735 | ((cfg->all_izlen<<GRTM_ALL_IZLEN_BIT) & GRTM_ALL_IZLEN) | |
---|
736 | ((cfg->mode<<GRTM_ALL_VER_BIT) & GRTM_ALL_VER); |
---|
737 | regs->all_frm = tmp; |
---|
738 | |
---|
739 | /* Master Frame Generation */ |
---|
740 | regs->mst_frm = cfg->mf_opts & GRTM_IOC_MF_ALL; |
---|
741 | |
---|
742 | /* Idle frame Generation */ |
---|
743 | tmp = ((cfg->idle_opts & GRTM_IOC_IDLE_ALL) << 16) | |
---|
744 | ((cfg->idle_vcid << GRTM_IDLE_VCID_BIT) & GRTM_IDLE_VCID) | |
---|
745 | ((cfg->idle_scid << GRTM_IDLE_SCID_BIT) & GRTM_IDLE_SCID); |
---|
746 | regs->idle_frm = tmp; |
---|
747 | |
---|
748 | return 0; |
---|
749 | } |
---|
750 | |
---|
751 | static int grtm_start(struct grtm_priv *pDev) |
---|
752 | { |
---|
753 | struct grtm_regs *regs = pDev->regs; |
---|
754 | int i; |
---|
755 | struct grtm_ioc_config *cfg = &pDev->config; |
---|
756 | unsigned int txrdy; |
---|
757 | |
---|
758 | /* Clear Descriptors */ |
---|
759 | memset(pDev->bds,0,0x400); |
---|
760 | |
---|
761 | /* Clear stats */ |
---|
762 | memset(&pDev->stats,0,sizeof(struct grtm_ioc_stats)); |
---|
763 | |
---|
764 | /* Init Descriptor Ring */ |
---|
765 | memset(pDev->_ring,0,sizeof(struct grtm_ring)*128); |
---|
766 | for(i=0;i<127;i++){ |
---|
767 | pDev->_ring[i].next = &pDev->_ring[i+1]; |
---|
768 | pDev->_ring[i].bd = &pDev->bds[i]; |
---|
769 | pDev->_ring[i].frm = NULL; |
---|
770 | } |
---|
771 | pDev->_ring[127].next = &pDev->_ring[0]; |
---|
772 | pDev->_ring[127].bd = &pDev->bds[127]; |
---|
773 | pDev->_ring[127].frm = NULL; |
---|
774 | |
---|
775 | pDev->ring = &pDev->_ring[0]; |
---|
776 | pDev->ring_end = &pDev->_ring[0]; |
---|
777 | |
---|
778 | /* Clear Scheduled, Ready and Sent list */ |
---|
779 | grtm_list_clr(&pDev->ready); |
---|
780 | grtm_list_clr(&pDev->scheduled); |
---|
781 | grtm_list_clr(&pDev->sent); |
---|
782 | |
---|
783 | /* Software init */ |
---|
784 | pDev->handling_transmission = 0; |
---|
785 | |
---|
786 | /* Reset the transmitter */ |
---|
787 | regs->dma_ctrl = GRTM_DMA_CTRL_TXRST; |
---|
788 | regs->dma_ctrl = 0; /* Leave Reset */ |
---|
789 | |
---|
790 | /* Clear old interrupts */ |
---|
791 | regs->dma_status = GRTM_DMA_STS_ALL; |
---|
792 | |
---|
793 | /* Set Descriptor Pointer Base register to point to first descriptor */ |
---|
794 | drvmgr_translate_check(pDev->dev, CPUMEM_TO_DMA, (void *)pDev->bds, |
---|
795 | (void **)®s->dma_bd, 0x400); |
---|
796 | |
---|
797 | /* Set hardware options as defined by config */ |
---|
798 | if ( grtm_hw_set_config(pDev, cfg, &pDev->hw_avail) ) { |
---|
799 | return RTEMS_IO_ERROR; |
---|
800 | } |
---|
801 | |
---|
802 | /* Enable TM Transmitter */ |
---|
803 | regs->ctrl = GRTM_CTRL_EN; |
---|
804 | |
---|
805 | /* Wait for TXRDY to be cleared */ |
---|
806 | i=1000; |
---|
807 | while( i > 0 ) { |
---|
808 | asm volatile ("nop"::); |
---|
809 | i--; |
---|
810 | } |
---|
811 | |
---|
812 | /* Check transmitter startup OK */ |
---|
813 | i = 1000000; |
---|
814 | do { |
---|
815 | /* Location of TXRDY Bit is different for different revisions */ |
---|
816 | if ( pDev->subrev == 0 ) { |
---|
817 | txrdy = READ_REG(®s->dma_ctrl) & |
---|
818 | GRTM_REV0_DMA_CTRL_TXRDY; |
---|
819 | } else { |
---|
820 | txrdy = READ_REG(®s->dma_status) & |
---|
821 | GRTM_REV1_DMA_STS_TXRDY; |
---|
822 | } |
---|
823 | if (txrdy != 0) |
---|
824 | break; |
---|
825 | |
---|
826 | asm volatile ("nop"::); |
---|
827 | } while ( --i > 0 ); |
---|
828 | if ( i == 0 ) { |
---|
829 | /* Reset Failed */ |
---|
830 | DBG("GRTM: start: Reseting transmitter failed (%d)\n",i); |
---|
831 | return RTEMS_IO_ERROR; |
---|
832 | } |
---|
833 | DBG("GRTM: reset time %d\n",i); |
---|
834 | |
---|
835 | /* Everything is configured, the TM transmitter is started |
---|
836 | * and idle frames has been sent. |
---|
837 | */ |
---|
838 | |
---|
839 | /* Mark running before enabling the DMA transmitter */ |
---|
840 | pDev->running = 1; |
---|
841 | |
---|
842 | /* Enable interrupts (Error and DMA TX) */ |
---|
843 | regs->dma_ctrl = GRTM_DMA_CTRL_IE; |
---|
844 | |
---|
845 | DBG("GRTM: STARTED\n"); |
---|
846 | |
---|
847 | return RTEMS_SUCCESSFUL; |
---|
848 | } |
---|
849 | |
---|
850 | static void grtm_stop(struct grtm_priv *pDev) |
---|
851 | { |
---|
852 | struct grtm_regs *regs = pDev->regs; |
---|
853 | |
---|
854 | /* Disable the transmitter & Interrupts */ |
---|
855 | regs->dma_ctrl = 0; |
---|
856 | |
---|
857 | /* Clear any pending interrupt */ |
---|
858 | regs->dma_status = GRTM_DMA_STS_ALL; |
---|
859 | |
---|
860 | DBG("GRTM: STOPPED\n"); |
---|
861 | |
---|
862 | /* Flush semaphore in case a thread is stuck waiting for TX Interrupts */ |
---|
863 | rtems_semaphore_flush(pDev->sem_tx); |
---|
864 | } |
---|
865 | |
---|
866 | static rtems_device_driver grtm_open( |
---|
867 | rtems_device_major_number major, |
---|
868 | rtems_device_minor_number minor, |
---|
869 | void *arg) |
---|
870 | { |
---|
871 | struct grtm_priv *pDev; |
---|
872 | struct drvmgr_dev *dev; |
---|
873 | |
---|
874 | FUNCDBG(); |
---|
875 | |
---|
876 | if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) { |
---|
877 | DBG("Wrong minor %d\n", minor); |
---|
878 | return RTEMS_INVALID_NUMBER; |
---|
879 | } |
---|
880 | pDev = (struct grtm_priv *)dev->priv; |
---|
881 | |
---|
882 | /* Wait until we get semaphore */ |
---|
883 | if ( rtems_semaphore_obtain(grtm_dev_sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT) != RTEMS_SUCCESSFUL ){ |
---|
884 | return RTEMS_INTERNAL_ERROR; |
---|
885 | } |
---|
886 | |
---|
887 | /* Is device in use? */ |
---|
888 | if ( pDev->open ){ |
---|
889 | rtems_semaphore_release(grtm_dev_sem); |
---|
890 | return RTEMS_RESOURCE_IN_USE; |
---|
891 | } |
---|
892 | |
---|
893 | /* Mark device taken */ |
---|
894 | pDev->open = 1; |
---|
895 | |
---|
896 | rtems_semaphore_release(grtm_dev_sem); |
---|
897 | |
---|
898 | DBG("grtm_open: OPENED minor %d (pDev: 0x%x)\n",pDev->minor,(unsigned int)pDev); |
---|
899 | |
---|
900 | /* Set defaults */ |
---|
901 | pDev->config.timeout = RTEMS_NO_TIMEOUT; /* no timeout (wait forever) */ |
---|
902 | pDev->config.blocking = 0; /* polling mode */ |
---|
903 | |
---|
904 | pDev->running = 0; /* not in running mode yet */ |
---|
905 | |
---|
906 | memset(&pDev->config,0,sizeof(pDev->config)); |
---|
907 | |
---|
908 | /* The core has been reset when we execute here, so it is possible |
---|
909 | * to read out what HW is implemented from core. |
---|
910 | */ |
---|
911 | grtm_hw_get_implementation(pDev, &pDev->hw_avail); |
---|
912 | |
---|
913 | /* Get default modes */ |
---|
914 | grtm_hw_get_default_modes(&pDev->config,&pDev->hw_avail); |
---|
915 | |
---|
916 | return RTEMS_SUCCESSFUL; |
---|
917 | } |
---|
918 | |
---|
919 | static rtems_device_driver grtm_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
920 | { |
---|
921 | struct grtm_priv *pDev; |
---|
922 | struct drvmgr_dev *dev; |
---|
923 | |
---|
924 | FUNCDBG(); |
---|
925 | |
---|
926 | if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) { |
---|
927 | return RTEMS_INVALID_NUMBER; |
---|
928 | } |
---|
929 | pDev = (struct grtm_priv *)dev->priv; |
---|
930 | |
---|
931 | if ( pDev->running ){ |
---|
932 | drvmgr_interrupt_unregister(dev, 0, grtm_interrupt, pDev); |
---|
933 | grtm_stop(pDev); |
---|
934 | pDev->running = 0; |
---|
935 | } |
---|
936 | |
---|
937 | /* Reset core */ |
---|
938 | grtm_hw_reset(pDev); |
---|
939 | |
---|
940 | /* Clear descriptor area just for sure */ |
---|
941 | memset(pDev->bds, 0, 0x400); |
---|
942 | |
---|
943 | /* Mark not open */ |
---|
944 | pDev->open = 0; |
---|
945 | |
---|
946 | return RTEMS_SUCCESSFUL; |
---|
947 | } |
---|
948 | |
---|
949 | static rtems_device_driver grtm_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
950 | { |
---|
951 | FUNCDBG(); |
---|
952 | return RTEMS_NOT_IMPLEMENTED; |
---|
953 | } |
---|
954 | |
---|
955 | static rtems_device_driver grtm_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
956 | { |
---|
957 | FUNCDBG(); |
---|
958 | return RTEMS_NOT_IMPLEMENTED; |
---|
959 | } |
---|
960 | |
---|
961 | /* Scans the desciptor table for scheduled frames that has been sent, |
---|
962 | * and moves these frames from the head of the scheduled queue to the |
---|
963 | * tail of the sent queue. |
---|
964 | * |
---|
965 | * Also, for all frames the status is updated. |
---|
966 | * |
---|
967 | * Return Value |
---|
968 | * Number of frames freed. |
---|
969 | */ |
---|
970 | static int grtm_free_sent(struct grtm_priv *pDev) |
---|
971 | { |
---|
972 | struct grtm_ring *curr; |
---|
973 | struct grtm_frame *last_frm, *first_frm; |
---|
974 | int freed_frame_cnt=0; |
---|
975 | unsigned int ctrl; |
---|
976 | |
---|
977 | curr = pDev->ring_end; |
---|
978 | |
---|
979 | /* Step into TX ring to find sent frames */ |
---|
980 | if ( !curr->frm ){ |
---|
981 | /* No scheduled frames, abort */ |
---|
982 | return 0; |
---|
983 | } |
---|
984 | |
---|
985 | /* There has been messages scheduled ==> scheduled messages may have been |
---|
986 | * transmitted and needs to be collected. |
---|
987 | */ |
---|
988 | |
---|
989 | first_frm = curr->frm; |
---|
990 | |
---|
991 | /* Loop until first enabled unsent frame is found. |
---|
992 | * A unused descriptor is indicated by an unassigned frm field |
---|
993 | */ |
---|
994 | while ( curr->frm && !((ctrl=READ_REG(&curr->bd->ctrl)) & GRTM_BD_EN) ){ |
---|
995 | /* Handle one sent Frame */ |
---|
996 | |
---|
997 | /* Remember last handled frame so that insertion/removal from |
---|
998 | * frames lists go fast. |
---|
999 | */ |
---|
1000 | last_frm = curr->frm; |
---|
1001 | |
---|
1002 | /* 1. Set flags to indicate error(s) and other information */ |
---|
1003 | last_frm->flags |= GRTM_FLAGS_SENT; /* Mark sent */ |
---|
1004 | |
---|
1005 | /* Update Stats */ |
---|
1006 | pDev->stats.frames_sent++; |
---|
1007 | |
---|
1008 | /* Did packet encounter link error? */ |
---|
1009 | if ( ctrl & GRTM_BD_UE ) { |
---|
1010 | pDev->stats.err_underrun++; |
---|
1011 | last_frm->flags |= GRRM_FLAGS_ERR; |
---|
1012 | } |
---|
1013 | |
---|
1014 | curr->frm = NULL; /* Mark unused */ |
---|
1015 | |
---|
1016 | /* Increment */ |
---|
1017 | curr = curr->next; |
---|
1018 | freed_frame_cnt++; |
---|
1019 | } |
---|
1020 | |
---|
1021 | /* 1. Remove all handled frames from scheduled queue |
---|
1022 | * 2. Put all handled frames into sent queue |
---|
1023 | */ |
---|
1024 | if ( freed_frame_cnt > 0 ){ |
---|
1025 | |
---|
1026 | /* Save TX ring posistion */ |
---|
1027 | pDev->ring_end = curr; |
---|
1028 | |
---|
1029 | /* Remove all sent frames from scheduled list */ |
---|
1030 | if ( pDev->scheduled.tail == last_frm ){ |
---|
1031 | /* All scheduled frames sent... */ |
---|
1032 | pDev->scheduled.head = NULL; |
---|
1033 | pDev->scheduled.tail = NULL; |
---|
1034 | }else{ |
---|
1035 | pDev->scheduled.head = last_frm->next; |
---|
1036 | } |
---|
1037 | last_frm->next = NULL; |
---|
1038 | |
---|
1039 | /* Put all sent frames into "Sent queue" for user to |
---|
1040 | * collect, later on. |
---|
1041 | */ |
---|
1042 | if ( !pDev->sent.head ){ |
---|
1043 | /* Sent queue empty */ |
---|
1044 | pDev->sent.head = first_frm; |
---|
1045 | pDev->sent.tail = last_frm; |
---|
1046 | }else{ |
---|
1047 | pDev->sent.tail->next = first_frm; |
---|
1048 | pDev->sent.tail = last_frm; |
---|
1049 | } |
---|
1050 | } |
---|
1051 | return freed_frame_cnt; |
---|
1052 | } |
---|
1053 | |
---|
1054 | |
---|
1055 | /* Moves as many frames in the ready queue (as there are free descriptors for) |
---|
1056 | * to the scheduled queue. The free descriptors are then assigned one frame |
---|
1057 | * each and enabled for transmission. |
---|
1058 | * |
---|
1059 | * Return Value |
---|
1060 | * Returns number of frames moved from ready to scheduled queue |
---|
1061 | */ |
---|
1062 | static int grtm_schedule_ready(struct grtm_priv *pDev) |
---|
1063 | { |
---|
1064 | int cnt; |
---|
1065 | unsigned int ctrl, dmactrl; |
---|
1066 | struct grtm_ring *curr_bd; |
---|
1067 | struct grtm_frame *curr_frm, *last_frm; |
---|
1068 | |
---|
1069 | if ( !pDev->ready.head ){ |
---|
1070 | return 0; |
---|
1071 | } |
---|
1072 | |
---|
1073 | cnt=0; |
---|
1074 | curr_frm = pDev->ready.head; |
---|
1075 | curr_bd = pDev->ring; |
---|
1076 | while( !curr_bd->frm ){ |
---|
1077 | /* Assign frame to descriptor */ |
---|
1078 | curr_bd->frm = curr_frm; |
---|
1079 | |
---|
1080 | /* Prepare descriptor address. Three cases: |
---|
1081 | * - GRTM core on same bus as CPU ==> no translation (Address used by CPU = address used by GRTM) |
---|
1082 | * - GRTM core on remote bus, and payload address given as used by CPU ==> Translation needed |
---|
1083 | * - GRTM core on remote bus, and payload address given as used by GRTM ==> no translation [ USER does custom translation] |
---|
1084 | */ |
---|
1085 | if ( curr_frm->flags & (GRTM_FLAGS_TRANSLATE|GRTM_FLAGS_TRANSLATE_AND_REMEMBER) ) { |
---|
1086 | /* Do translation */ |
---|
1087 | drvmgr_translate(pDev->dev, CPUMEM_TO_DMA, (void *)curr_frm->payload, (void **)&curr_bd->bd->address); |
---|
1088 | if ( curr_frm->flags & GRTM_FLAGS_TRANSLATE_AND_REMEMBER ) { |
---|
1089 | if ( curr_frm->payload != (unsigned int *)curr_bd->bd->address ) { |
---|
1090 | /* Translation needed */ |
---|
1091 | curr_frm->flags &= ~GRTM_FLAGS_TRANSLATE_AND_REMEMBER; |
---|
1092 | curr_frm->flags |= GRTM_FLAGS_TRANSLATE; |
---|
1093 | } else { |
---|
1094 | /* No Trnaslation needed */ |
---|
1095 | curr_frm->flags &= ~(GRTM_FLAGS_TRANSLATE|GRTM_FLAGS_TRANSLATE_AND_REMEMBER); |
---|
1096 | } |
---|
1097 | } |
---|
1098 | } else { |
---|
1099 | /* Custom translation or no translation needed */ |
---|
1100 | curr_bd->bd->address = (unsigned int)curr_frm->payload; |
---|
1101 | } |
---|
1102 | |
---|
1103 | ctrl = GRTM_BD_EN; |
---|
1104 | if ( curr_bd->next == pDev->_ring ){ |
---|
1105 | ctrl |= GRTM_BD_WR; /* Wrap around */ |
---|
1106 | } |
---|
1107 | /* Apply user options/flags */ |
---|
1108 | ctrl |= (curr_frm->flags & GRTM_FLAGS_MASK); |
---|
1109 | |
---|
1110 | /* Is this Frame going to be an interrupt Frame? */ |
---|
1111 | if ( (--pDev->enable_cnt_curr) <= 0 ){ |
---|
1112 | if ( pDev->config.enable_cnt == 0 ){ |
---|
1113 | pDev->enable_cnt_curr = 0x3fffffff; |
---|
1114 | }else{ |
---|
1115 | pDev->enable_cnt_curr = pDev->config.enable_cnt; |
---|
1116 | ctrl |= GRTM_BD_IE; |
---|
1117 | } |
---|
1118 | } |
---|
1119 | |
---|
1120 | /* Enable descriptor */ |
---|
1121 | curr_bd->bd->ctrl = ctrl; |
---|
1122 | |
---|
1123 | last_frm = curr_frm; |
---|
1124 | curr_bd = curr_bd->next; |
---|
1125 | cnt++; |
---|
1126 | |
---|
1127 | /* Get Next Frame from Ready Queue */ |
---|
1128 | if ( curr_frm == pDev->ready.tail ){ |
---|
1129 | /* Handled all in ready queue. */ |
---|
1130 | curr_frm = NULL; |
---|
1131 | break; |
---|
1132 | } |
---|
1133 | curr_frm = curr_frm->next; |
---|
1134 | } |
---|
1135 | |
---|
1136 | /* Has frames have been scheduled? */ |
---|
1137 | if ( cnt > 0 ){ |
---|
1138 | /* Make last frame mark end of chain, probably pointless... */ |
---|
1139 | last_frm->next = NULL; |
---|
1140 | |
---|
1141 | /* Insert scheduled packets into scheduled queue */ |
---|
1142 | if ( !pDev->scheduled.head ){ |
---|
1143 | /* empty scheduled queue */ |
---|
1144 | pDev->scheduled.head = pDev->ready.head; |
---|
1145 | pDev->scheduled.tail = last_frm; |
---|
1146 | }else{ |
---|
1147 | pDev->scheduled.tail->next = pDev->ready.head; |
---|
1148 | pDev->scheduled.tail = last_frm; |
---|
1149 | } |
---|
1150 | |
---|
1151 | /* Remove scheduled packets from ready queue */ |
---|
1152 | pDev->ready.head = curr_frm; |
---|
1153 | if ( !curr_frm ){ |
---|
1154 | pDev->ready.tail = NULL; |
---|
1155 | } |
---|
1156 | |
---|
1157 | /* Update TX ring posistion */ |
---|
1158 | pDev->ring = curr_bd; |
---|
1159 | |
---|
1160 | /* Make hardware aware of the newly enabled descriptors */ |
---|
1161 | dmactrl = READ_REG(&pDev->regs->dma_ctrl); |
---|
1162 | dmactrl &= ~(GRTM_DMA_CTRL_TXRST | GRTM_DMA_CTRL_RST); |
---|
1163 | dmactrl |= GRTM_DMA_CTRL_EN; |
---|
1164 | pDev->regs->dma_ctrl = dmactrl; |
---|
1165 | } |
---|
1166 | |
---|
1167 | return cnt; |
---|
1168 | } |
---|
1169 | |
---|
1170 | static void grtm_tx_process(struct grtm_priv *pDev) |
---|
1171 | { |
---|
1172 | int num; |
---|
1173 | |
---|
1174 | /* Free used descriptors and put the sent frame into the "Sent queue" |
---|
1175 | * (SCHEDULED->SENT) |
---|
1176 | */ |
---|
1177 | num = grtm_free_sent(pDev); |
---|
1178 | pDev->scheduled_cnt -= num; |
---|
1179 | pDev->sent_cnt += num; |
---|
1180 | |
---|
1181 | /* Use all available free descriptors there are frames for |
---|
1182 | * in the ready queue. |
---|
1183 | * (READY->SCHEDULED) |
---|
1184 | */ |
---|
1185 | if (pDev->running) { |
---|
1186 | num = grtm_schedule_ready(pDev); |
---|
1187 | pDev->ready_cnt -= num; |
---|
1188 | pDev->scheduled_cnt += num; |
---|
1189 | } |
---|
1190 | } |
---|
1191 | |
---|
1192 | /* |
---|
1193 | * The TX lock protects user tasks from the ISR. If TX DMA interrupt occurs |
---|
1194 | * while the user task is processing the TX DMA descriptors the ISR will |
---|
1195 | * ignore interrupt the request by not processing the DMA table since that |
---|
1196 | * is done by the user task anyway. In SMP, when a user task enters the TX DMA |
---|
1197 | * processing while the ISR (on another CPU) is also processing the user task |
---|
1198 | * will loop waiting for the ISR to complete. |
---|
1199 | */ |
---|
1200 | static int grtm_request_txlock(struct grtm_priv *pDev, int block) |
---|
1201 | { |
---|
1202 | SPIN_IRQFLAGS(irqflags); |
---|
1203 | int got_lock = 0; |
---|
1204 | |
---|
1205 | do { |
---|
1206 | SPIN_LOCK_IRQ(&pDev->devlock, irqflags); |
---|
1207 | if (pDev->handling_transmission == 0) { |
---|
1208 | pDev->handling_transmission = 1; |
---|
1209 | got_lock = 1; |
---|
1210 | } |
---|
1211 | SPIN_UNLOCK_IRQ(&pDev->devlock, irqflags); |
---|
1212 | } while (!got_lock && block); |
---|
1213 | |
---|
1214 | return got_lock; |
---|
1215 | } |
---|
1216 | |
---|
1217 | static inline int grtm_request_txlock_isr(struct grtm_priv *pDev) |
---|
1218 | { |
---|
1219 | SPIN_ISR_IRQFLAGS(irqflags); |
---|
1220 | int got_lock = 0; |
---|
1221 | |
---|
1222 | SPIN_LOCK(&pDev->devlock, irqflags); |
---|
1223 | if (pDev->handling_transmission == 0) { |
---|
1224 | pDev->handling_transmission = 1; |
---|
1225 | got_lock = 1; |
---|
1226 | } |
---|
1227 | SPIN_UNLOCK(&pDev->devlock, irqflags); |
---|
1228 | |
---|
1229 | return got_lock; |
---|
1230 | } |
---|
1231 | |
---|
1232 | static inline void grtm_release_txlock(struct grtm_priv *pDev) |
---|
1233 | { |
---|
1234 | pDev->handling_transmission = 0; |
---|
1235 | } |
---|
1236 | |
---|
1237 | static rtems_device_driver grtm_ioctl(rtems_device_major_number major, rtems_device_minor_number minor, void *arg) |
---|
1238 | { |
---|
1239 | struct grtm_priv *pDev; |
---|
1240 | struct drvmgr_dev *dev; |
---|
1241 | rtems_libio_ioctl_args_t *ioarg = (rtems_libio_ioctl_args_t *)arg; |
---|
1242 | unsigned int *data; |
---|
1243 | int status; |
---|
1244 | struct grtm_ioc_config *cfg; |
---|
1245 | struct grtm_ioc_hw_status *hwregs; |
---|
1246 | struct grtm_list *chain; |
---|
1247 | struct grtm_frame *curr; |
---|
1248 | struct grtm_ioc_hw *hwimpl; |
---|
1249 | struct grtm_ioc_stats *stats; |
---|
1250 | int num,ret; |
---|
1251 | |
---|
1252 | FUNCDBG(); |
---|
1253 | |
---|
1254 | if ( drvmgr_get_dev(&grtm_drv_info.general, minor, &dev) ) { |
---|
1255 | return RTEMS_INVALID_NUMBER; |
---|
1256 | } |
---|
1257 | pDev = (struct grtm_priv *)dev->priv; |
---|
1258 | |
---|
1259 | if (!ioarg) |
---|
1260 | return RTEMS_INVALID_NAME; |
---|
1261 | |
---|
1262 | data = ioarg->buffer; |
---|
1263 | ioarg->ioctl_return = 0; |
---|
1264 | switch(ioarg->command) { |
---|
1265 | case GRTM_IOC_START: |
---|
1266 | if ( pDev->running ) { |
---|
1267 | return RTEMS_RESOURCE_IN_USE; /* EBUSY */ |
---|
1268 | } |
---|
1269 | if ( (status=grtm_start(pDev)) != RTEMS_SUCCESSFUL ){ |
---|
1270 | return status; |
---|
1271 | } |
---|
1272 | /* Register ISR & Enable interrupt */ |
---|
1273 | drvmgr_interrupt_register(dev, 0, "grtm", grtm_interrupt, pDev); |
---|
1274 | |
---|
1275 | /* Read and write are now open... */ |
---|
1276 | break; |
---|
1277 | |
---|
1278 | case GRTM_IOC_STOP: |
---|
1279 | if ( !pDev->running ) { |
---|
1280 | return RTEMS_RESOURCE_IN_USE; |
---|
1281 | } |
---|
1282 | |
---|
1283 | /* Disable interrupts */ |
---|
1284 | drvmgr_interrupt_unregister(dev, 0, grtm_interrupt, pDev); |
---|
1285 | grtm_stop(pDev); |
---|
1286 | pDev->running = 0; |
---|
1287 | break; |
---|
1288 | |
---|
1289 | case GRTM_IOC_ISSTARTED: |
---|
1290 | if ( !pDev->running ) { |
---|
1291 | return RTEMS_RESOURCE_IN_USE; |
---|
1292 | } |
---|
1293 | break; |
---|
1294 | |
---|
1295 | case GRTM_IOC_SET_BLOCKING_MODE: |
---|
1296 | if ( (unsigned int)data > GRTM_BLKMODE_BLK ) { |
---|
1297 | return RTEMS_INVALID_NAME; |
---|
1298 | } |
---|
1299 | DBG("GRTM: Set blocking mode: %d\n",(unsigned int)data); |
---|
1300 | pDev->config.blocking = (unsigned int)data; |
---|
1301 | break; |
---|
1302 | |
---|
1303 | case GRTM_IOC_SET_TIMEOUT: |
---|
1304 | DBG("GRTM: Timeout: %d\n",(unsigned int)data); |
---|
1305 | pDev->config.timeout = (rtems_interval)data; |
---|
1306 | break; |
---|
1307 | |
---|
1308 | case GRTM_IOC_SET_CONFIG: |
---|
1309 | cfg = (struct grtm_ioc_config *)data; |
---|
1310 | if ( !cfg ) { |
---|
1311 | return RTEMS_INVALID_NAME; |
---|
1312 | } |
---|
1313 | |
---|
1314 | if ( pDev->running ) { |
---|
1315 | return RTEMS_RESOURCE_IN_USE; |
---|
1316 | } |
---|
1317 | |
---|
1318 | pDev->config = *cfg; |
---|
1319 | break; |
---|
1320 | |
---|
1321 | case GRTM_IOC_GET_STATS: |
---|
1322 | stats = (struct grtm_ioc_stats *)data; |
---|
1323 | if ( !stats ) { |
---|
1324 | return RTEMS_INVALID_NAME; |
---|
1325 | } |
---|
1326 | memcpy(stats,&pDev->stats,sizeof(struct grtm_ioc_stats)); |
---|
1327 | break; |
---|
1328 | |
---|
1329 | case GRTM_IOC_CLR_STATS: |
---|
1330 | memset(&pDev->stats,0,sizeof(struct grtm_ioc_stats)); |
---|
1331 | break; |
---|
1332 | |
---|
1333 | case GRTM_IOC_GET_CONFIG: |
---|
1334 | cfg = (struct grtm_ioc_config *)data; |
---|
1335 | if ( !cfg ) { |
---|
1336 | return RTEMS_INVALID_NAME; |
---|
1337 | } |
---|
1338 | |
---|
1339 | *cfg = pDev->config; |
---|
1340 | break; |
---|
1341 | |
---|
1342 | case GRTM_IOC_GET_OCFREG: |
---|
1343 | if ( !pDev->hw_avail.ocf ) { |
---|
1344 | /* Hardware does not implement the OCF register */ |
---|
1345 | return RTEMS_NOT_DEFINED; |
---|
1346 | } |
---|
1347 | if ( !data ) { |
---|
1348 | return RTEMS_INVALID_NAME; |
---|
1349 | } |
---|
1350 | *(unsigned int **)data = (unsigned int *)&pDev->regs->ocf; |
---|
1351 | break; |
---|
1352 | |
---|
1353 | case GRTM_IOC_GET_HW_IMPL: |
---|
1354 | hwimpl = (struct grtm_ioc_hw *)data; |
---|
1355 | if ( !hwimpl ) { |
---|
1356 | return RTEMS_INVALID_NAME; |
---|
1357 | } |
---|
1358 | *hwimpl = pDev->hw_avail; |
---|
1359 | break; |
---|
1360 | |
---|
1361 | case GRTM_IOC_GET_HW_STATUS: |
---|
1362 | hwregs = (struct grtm_ioc_hw_status *)data; |
---|
1363 | if ( !hwregs ) { |
---|
1364 | return RTEMS_INVALID_NAME; |
---|
1365 | } |
---|
1366 | /* We disable interrupt in order to get a snapshot of the registers */ |
---|
1367 | /* TODO: implement hwregs */ |
---|
1368 | break; |
---|
1369 | |
---|
1370 | /* Put a chain of frames at the back of the "Ready frames" queue. This |
---|
1371 | * triggers the driver to put frames from the Ready queue into unused |
---|
1372 | * available descriptors. (Ready -> Scheduled) |
---|
1373 | */ |
---|
1374 | |
---|
1375 | case GRTM_IOC_SEND: |
---|
1376 | if ( !pDev->running ){ |
---|
1377 | return RTEMS_RESOURCE_IN_USE; |
---|
1378 | } |
---|
1379 | |
---|
1380 | /* Get pointer to frame chain wished be sent */ |
---|
1381 | chain = (struct grtm_list *)ioarg->buffer; |
---|
1382 | if ( !chain ){ |
---|
1383 | /* No new frames to send ==> just trigger hardware |
---|
1384 | * to send previously made ready frames to be sent. |
---|
1385 | * If someone else is processing the DMA we igore the |
---|
1386 | * request. |
---|
1387 | */ |
---|
1388 | if (grtm_request_txlock(pDev, 0)) { |
---|
1389 | grtm_tx_process(pDev); |
---|
1390 | grtm_release_txlock(pDev); |
---|
1391 | } |
---|
1392 | break; |
---|
1393 | } |
---|
1394 | if ( !chain->tail || !chain->head ){ |
---|
1395 | return RTEMS_INVALID_NAME; |
---|
1396 | } |
---|
1397 | |
---|
1398 | DBG("GRTM_SEND: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail); |
---|
1399 | |
---|
1400 | /* Mark ready frames unsent by clearing GRTM_FLAGS_SENT of all frames */ |
---|
1401 | |
---|
1402 | num = 0; |
---|
1403 | curr = chain->head; |
---|
1404 | while(curr != chain->tail){ |
---|
1405 | curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR); |
---|
1406 | curr = curr->next; |
---|
1407 | num++; |
---|
1408 | } |
---|
1409 | curr->flags = curr->flags & ~(GRTM_FLAGS_SENT|GRRM_FLAGS_ERR); |
---|
1410 | num++; |
---|
1411 | |
---|
1412 | /* wait until we get the device lock */ |
---|
1413 | grtm_request_txlock(pDev, 1); |
---|
1414 | |
---|
1415 | /* 1. Put frames into ready queue |
---|
1416 | * (New Frames->READY) |
---|
1417 | */ |
---|
1418 | if ( pDev->ready.head ){ |
---|
1419 | /* Frames already on ready queue (no free descriptors previously) ==> |
---|
1420 | * Put frames at end of ready queue |
---|
1421 | */ |
---|
1422 | pDev->ready.tail->next = chain->head; |
---|
1423 | pDev->ready.tail = chain->tail; |
---|
1424 | chain->tail->next = NULL; |
---|
1425 | }else{ |
---|
1426 | /* All frames is put into the ready queue for later processing */ |
---|
1427 | pDev->ready.head = chain->head; |
---|
1428 | pDev->ready.tail = chain->tail; |
---|
1429 | chain->tail->next = NULL; |
---|
1430 | } |
---|
1431 | pDev->ready_cnt += num; /* Added 'num' frames to ready queue */ |
---|
1432 | |
---|
1433 | /* 2. SCHEDULED->SENT |
---|
1434 | * 3. READY->SCHEDULED |
---|
1435 | */ |
---|
1436 | grtm_tx_process(pDev); |
---|
1437 | grtm_release_txlock(pDev); |
---|
1438 | break; |
---|
1439 | |
---|
1440 | /* Take all available sent frames from the "Sent frames" queue. |
---|
1441 | * If no frames has been sent, the thread may get blocked if in blocking |
---|
1442 | * mode. The blocking mode is not available if driver is not in running mode. |
---|
1443 | * |
---|
1444 | * Note this ioctl may return success even if the driver is not in STARTED mode. |
---|
1445 | * This is because in case of a error (link error of similar) and the driver switch |
---|
1446 | * from START to STOP mode we must still be able to get our frames back. |
---|
1447 | * |
---|
1448 | * Note in case the driver fails to send a frame for some reason (link error), |
---|
1449 | * the sent flag is set to 0 indicating a failure. |
---|
1450 | * |
---|
1451 | */ |
---|
1452 | case GRTM_IOC_RECLAIM: |
---|
1453 | /* Get pointer to were to place reaped chain */ |
---|
1454 | chain = (struct grtm_list *)ioarg->buffer; |
---|
1455 | if ( !chain ){ |
---|
1456 | return RTEMS_INVALID_NAME; |
---|
1457 | } |
---|
1458 | |
---|
1459 | /* Lock out interrupt handler */ |
---|
1460 | grtm_request_txlock(pDev, 1); |
---|
1461 | |
---|
1462 | do { |
---|
1463 | /* Process descriptor table and populate with new |
---|
1464 | * buffers: |
---|
1465 | * * SCHEDULED->SENT |
---|
1466 | * * READY->SCHEDULED |
---|
1467 | */ |
---|
1468 | grtm_tx_process(pDev); |
---|
1469 | |
---|
1470 | /* Are there any frames on the sent queue waiting to be |
---|
1471 | * reclaimed? |
---|
1472 | */ |
---|
1473 | |
---|
1474 | if ( !pDev->sent.head ){ |
---|
1475 | /* No frames to reclaim - no frame in sent queue. |
---|
1476 | * Instead we block thread until frames have been sent |
---|
1477 | * if in blocking mode. |
---|
1478 | */ |
---|
1479 | if ( pDev->running && pDev->config.blocking ){ |
---|
1480 | ret = rtems_semaphore_obtain(pDev->sem_tx,RTEMS_WAIT,pDev->config.timeout); |
---|
1481 | if ( ret == RTEMS_TIMEOUT ) { |
---|
1482 | grtm_release_txlock(pDev); |
---|
1483 | return RTEMS_TIMEOUT; |
---|
1484 | } else if ( ret == RTEMS_SUCCESSFUL ) { |
---|
1485 | /* There might be frames available, go check */ |
---|
1486 | continue; |
---|
1487 | } else { |
---|
1488 | /* any error (driver closed, internal error etc.) */ |
---|
1489 | grtm_release_txlock(pDev); |
---|
1490 | return RTEMS_UNSATISFIED; |
---|
1491 | } |
---|
1492 | |
---|
1493 | }else{ |
---|
1494 | /* non-blocking mode, we quit */ |
---|
1495 | chain->head = NULL; |
---|
1496 | chain->tail = NULL; |
---|
1497 | /* do not lock out interrupt handler any more */ |
---|
1498 | grtm_release_txlock(pDev); |
---|
1499 | return RTEMS_TIMEOUT; |
---|
1500 | } |
---|
1501 | }else{ |
---|
1502 | /* Take all sent framess from sent queue to userspace queue */ |
---|
1503 | chain->head = pDev->sent.head; |
---|
1504 | chain->tail = pDev->sent.tail; |
---|
1505 | chain->tail->next = NULL; /* Just for sure */ |
---|
1506 | |
---|
1507 | /* Mark no Sent */ |
---|
1508 | grtm_list_clr(&pDev->sent); |
---|
1509 | pDev->sent_cnt = 0; |
---|
1510 | |
---|
1511 | DBG("TX_RECLAIM: head: 0x%x, tail: 0x%x\n",chain->head,chain->tail); |
---|
1512 | break; |
---|
1513 | } |
---|
1514 | |
---|
1515 | }while(1); |
---|
1516 | |
---|
1517 | /* do not lock out interrupt handler any more */ |
---|
1518 | grtm_release_txlock(pDev); |
---|
1519 | break; |
---|
1520 | |
---|
1521 | default: |
---|
1522 | return RTEMS_NOT_DEFINED; |
---|
1523 | } |
---|
1524 | return RTEMS_SUCCESSFUL; |
---|
1525 | } |
---|
1526 | |
---|
1527 | static void grtm_interrupt(void *arg) |
---|
1528 | { |
---|
1529 | struct grtm_priv *pDev = arg; |
---|
1530 | struct grtm_regs *regs = pDev->regs; |
---|
1531 | unsigned int status; |
---|
1532 | |
---|
1533 | /* Clear interrupt by reading it */ |
---|
1534 | status = READ_REG(®s->dma_status); |
---|
1535 | |
---|
1536 | /* Spurious Interrupt? */ |
---|
1537 | if ( !pDev->running || !status) |
---|
1538 | return; |
---|
1539 | |
---|
1540 | regs->dma_status = status; |
---|
1541 | |
---|
1542 | if ( status & GRTM_DMA_STS_TFF ){ |
---|
1543 | pDev->stats.err_transfer_frame++; |
---|
1544 | } |
---|
1545 | |
---|
1546 | if ( status & GRTM_DMA_STS_TA ){ |
---|
1547 | pDev->stats.err_ahb++; |
---|
1548 | } |
---|
1549 | |
---|
1550 | if ( status & GRTM_DMA_STS_TE ){ |
---|
1551 | pDev->stats.err_tx++; |
---|
1552 | } |
---|
1553 | |
---|
1554 | if ( status & GRTM_DMA_STS_TI ){ |
---|
1555 | |
---|
1556 | if ( pDev->config.isr_desc_proc) { |
---|
1557 | if (grtm_request_txlock_isr(pDev)) { |
---|
1558 | grtm_tx_process(pDev); |
---|
1559 | grtm_release_txlock(pDev); |
---|
1560 | } |
---|
1561 | |
---|
1562 | #if 0 |
---|
1563 | if ( (pDev->config.blocking==GRTM_BLKMODE_COMPLETE) && pDev->timeout ){ |
---|
1564 | /* Signal to thread only if enough data is available */ |
---|
1565 | if ( pDev->wait_for_frames > grtm_data_avail(pDev) ){ |
---|
1566 | /* Not enough data available */ |
---|
1567 | goto procceed_processing_interrupts; |
---|
1568 | } |
---|
1569 | |
---|
1570 | /* Enough number of frames has been transmitted which means that |
---|
1571 | * the waiting thread should be woken up. |
---|
1572 | */ |
---|
1573 | rtems_semaphore_release(pDev->sem_tx); |
---|
1574 | } |
---|
1575 | #endif |
---|
1576 | } |
---|
1577 | |
---|
1578 | if ( pDev->config.blocking == GRTM_BLKMODE_BLK ) { |
---|
1579 | /* Blocking mode */ |
---|
1580 | |
---|
1581 | #if 0 |
---|
1582 | /* Disable further Interrupts until handled by waiting task. */ |
---|
1583 | regs->dma_ctrl = READ_REG(®s->dma_ctrl) & ~GRTM_DMA_CTRL_IE; |
---|
1584 | #endif |
---|
1585 | |
---|
1586 | /* Signal Semaphore to wake waiting thread in ioctl(SEND|RECLAIM) */ |
---|
1587 | rtems_semaphore_release(pDev->sem_tx); |
---|
1588 | } |
---|
1589 | |
---|
1590 | } |
---|
1591 | #if 0 |
---|
1592 | procceed_processing_interrupts: |
---|
1593 | ; |
---|
1594 | #endif |
---|
1595 | } |
---|
1596 | |
---|
1597 | static rtems_device_driver grtm_initialize( |
---|
1598 | rtems_device_major_number major, |
---|
1599 | rtems_device_minor_number unused, |
---|
1600 | void *arg |
---|
1601 | ) |
---|
1602 | { |
---|
1603 | /* Device Semaphore created with count = 1 */ |
---|
1604 | if ( rtems_semaphore_create(rtems_build_name('G', 'R', 'T', 'M'), |
---|
1605 | 1, |
---|
1606 | RTEMS_FIFO|RTEMS_NO_INHERIT_PRIORITY|RTEMS_LOCAL|RTEMS_NO_PRIORITY_CEILING, |
---|
1607 | 0, |
---|
1608 | &grtm_dev_sem) != RTEMS_SUCCESSFUL ) { |
---|
1609 | return RTEMS_INTERNAL_ERROR; |
---|
1610 | } |
---|
1611 | |
---|
1612 | return RTEMS_SUCCESSFUL; |
---|
1613 | } |
---|