]>
Commit | Line | Data |
---|---|---|
327f7a02 WD |
1 | /************************************************************ |
2 | * | |
3 | * copyright @ Motorola, 1999 | |
4 | * | |
5 | * App. API | |
6 | * | |
7 | * App. API are the APIs Kernel provides for the application | |
8 | * level program | |
9 | * | |
10 | ************************************************************/ | |
11 | #include "dma_export.h" | |
12 | #include "dma.h" | |
13 | ||
14 | /* Define a macro to use an optional application-layer print function, if | |
15 | * one was passed to the library during initialization. If there was no | |
16 | * function pointer passed, this protects against referencing a NULL pointer. | |
17 | * Also define The global variable that holds the passed pointer. | |
18 | */ | |
19 | #define PRINT if ( app_print ) app_print | |
20 | static int (*app_print)(char *,...); | |
21 | ||
22 | /* Set by call to get_eumbbar during DMA_Initialize. | |
23 | * This could be globally available to the library, but there is | |
24 | * an advantage to passing it as a parameter: it is already in a register | |
25 | * and doesn't have to be loaded from memory. Also, that is the way the | |
26 | * library was already implemented and I don't want to change it without | |
27 | * a more detailed analysis. | |
28 | * It is being set as a global variable during initialization to hide it from | |
29 | * the DINK application layer, because it is Kahlua-specific. I think that | |
30 | * get_eumbbar, load_runtime_reg, and store_runtime_reg should be defined in | |
31 | * a Kahlua-specific library dealing with the embedded utilities memory block. | |
32 | * Right now, get_eumbbar is defined in dink32/kahlua.s. The other two are | |
33 | * defined in dink32/drivers/i2c/i2c2.s, drivers/dma/dma2.s, etc. | |
34 | */ | |
35 | static unsigned int Global_eumbbar = 0; | |
36 | extern unsigned int get_eumbbar(); | |
37 | ||
38 | ||
39 | extern unsigned int load_runtime_reg( unsigned int eumbbar, unsigned int reg ); | |
40 | #pragma Alias( load_runtime_reg, "load_runtime_reg" ); | |
41 | ||
42 | extern void store_runtime_reg( unsigned int eumbbar, unsigned int reg, unsigned int val ); | |
43 | #pragma Alias( store_runtime_reg, "store_runtime_reg" ); | |
44 | ||
45 | unsigned int dma_reg_tb[][14] = { | |
46 | /* local DMA registers */ | |
47 | { | |
48 | /* DMA_0_MR */ 0x00001100, | |
49 | /* DMA_0_SR */ 0x00001104, | |
50 | /* DMA_0_CDAR */ 0x00001108, | |
51 | /* DMA_0_SAR */ 0x00001110, | |
52 | /* DMA_0_DAR */ 0x00001118, | |
53 | /* DMA_0_BCR */ 0x00001120, | |
54 | /* DMA_0_NDAR */ 0x00001124, | |
55 | /* DMA_1_MR */ 0x00001200, | |
56 | /* DMA_1_SR */ 0x00001204, | |
57 | /* DMA_1_CDAR */ 0x00001208, | |
58 | /* DMA_1_SAR */ 0x00001210, | |
59 | /* DMA_1_DAR */ 0x00001218, | |
60 | /* DMA_1_BCR */ 0x00001220, | |
61 | /* DMA_1_NDAR */ 0x00001224, | |
62 | }, | |
63 | /* remote DMA registers */ | |
64 | { | |
65 | /* DMA_0_MR */ 0x00000100, | |
66 | /* DMA_0_SR */ 0x00000104, | |
67 | /* DMA_0_CDAR */ 0x00000108, | |
68 | /* DMA_0_SAR */ 0x00000110, | |
69 | /* DMA_0_DAR */ 0x00000118, | |
70 | /* DMA_0_BCR */ 0x00000120, | |
71 | /* DMA_0_NDAR */ 0x00000124, | |
72 | /* DMA_1_MR */ 0x00000200, | |
73 | /* DMA_1_SR */ 0x00000204, | |
74 | /* DMA_1_CDAR */ 0x00000208, | |
75 | /* DMA_1_SAR */ 0x00000210, | |
76 | /* DMA_1_DAR */ 0x00000218, | |
77 | /* DMA_1_BCR */ 0x00000220, | |
78 | /* DMA_1_NDAR */ 0x00000224, | |
79 | }, | |
80 | }; | |
81 | ||
82 | /* API functions */ | |
83 | ||
84 | /* Initialize DMA unit with the following: | |
85 | * optional pointer to application layer print function | |
86 | * | |
87 | * These parameters may be added: | |
88 | * ??? | |
89 | * Interrupt enables, modes, etc. are set for each transfer. | |
90 | * | |
91 | * This function must be called before DMA unit can be used. | |
92 | */ | |
93 | extern | |
94 | DMA_Status DMA_Initialize( int (*p)(char *,...)) | |
95 | { | |
96 | DMAStatus status; | |
97 | /* establish the pointer, if there is one, to the application's "printf" */ | |
98 | app_print = p; | |
99 | ||
100 | /* If this is the first call, get the embedded utilities memory block | |
101 | * base address. I'm not sure what to do about error handling here: | |
102 | * if a non-zero value is returned, accept it. | |
103 | */ | |
104 | if ( Global_eumbbar == 0) | |
105 | Global_eumbbar = get_eumbbar(); | |
106 | if ( Global_eumbbar == 0) | |
107 | { | |
108 | PRINT( "DMA_Initialize: can't find EUMBBAR\n" ); | |
109 | return DMA_ERROR; | |
110 | } | |
111 | ||
112 | return DMA_SUCCESS; | |
113 | } | |
114 | ||
115 | ||
116 | /* Perform the DMA transfer, only direct mode is currently implemented. | |
117 | * At this point, I think it would be better to define a different | |
118 | * function for chaining mode. | |
119 | * Also, I'm not sure if it is appropriate to have the "generic" API | |
120 | * accept snoop and int_steer parameters. The DINK user interface allows | |
121 | * them, so for now I'll leave them. | |
122 | * | |
123 | * int_steer controls DMA interrupt steering to PCI or local processor | |
124 | * type is the type of transfer: M2M, M2P, P2M, P2P | |
125 | * source is the source address of the data | |
126 | * dest is the destination address of the data | |
127 | * len is the length of data to transfer | |
128 | * channel is the DMA channel to use for the transfer | |
129 | * snoop is the snoop enable control | |
130 | */ | |
131 | extern DMA_Status DMA_direct_transfer( DMA_INTERRUPT_STEER int_steer, | |
8bde7f77 WD |
132 | DMA_TRANSFER_TYPE type, |
133 | unsigned int source, | |
134 | unsigned int dest, | |
135 | unsigned int len, | |
136 | DMA_CHANNEL channel, | |
137 | DMA_SNOOP_MODE snoop) | |
327f7a02 WD |
138 | { |
139 | DMA_MR md; | |
140 | DMA_CDAR cdar; | |
141 | /* it's inappropriate for curr to be a struct, but I'll leave it */ | |
142 | DMA_CURR curr; | |
143 | ||
144 | DMAStatus stat; | |
145 | ||
146 | /* The rest of this code was moved from device.c test_dma to here. | |
147 | * It needs to be cleaned up and validated, but at least it is removed | |
148 | * from the application and API. Most of the mode is left hard coded. | |
149 | * This should be changed after the final API is defined and the user | |
150 | * application has a way to control the transfer. | |
151 | * | |
152 | */ | |
153 | ||
154 | if ( DMA_Get_Mode( LOCAL, Global_eumbbar, channel, &md ) != DMASUCCESS ) | |
155 | { | |
156 | return DMA_ERROR; | |
157 | } | |
158 | ||
159 | md.irqs = int_steer; | |
160 | md.pde = 0; | |
161 | md.dahts = 3; /* 8 - byte */ | |
162 | md.sahts = 3; /* 8 - byte */ | |
163 | md.dahe = 0; | |
164 | md.sahe = 0; | |
165 | md.prc = 0; | |
166 | /* if steering interrupts to local processor, use polling mode */ | |
167 | if ( int_steer == DMA_INT_STEER_PCI ) | |
168 | { | |
169 | md.eie = 1; | |
170 | md.eotie = 1; | |
171 | } else { | |
172 | md.eie = 0; | |
173 | md.eotie = 0; | |
174 | } | |
175 | md.dl = 0; | |
176 | md.ctm = 1; /* direct mode */ | |
177 | md.cc = 0; | |
178 | ||
179 | /* validate the length range */ | |
180 | if (len > 0x3ffffff ) | |
181 | { | |
182 | PRINT( "dev DMA: length of transfer too large: %d\n", len ); | |
183 | return DMA_ERROR; | |
184 | } | |
185 | ||
186 | /* inappropriate to use a struct, but leave as is for now */ | |
187 | curr.src_addr = source; | |
188 | curr.dest_addr = dest; | |
189 | curr.byte_cnt = len; | |
190 | ||
191 | (void)DMA_Poke_Desp( LOCAL, Global_eumbbar, channel, &cdar ); | |
192 | cdar.snen = snoop; | |
193 | cdar.ctt = type; | |
194 | ||
195 | if ( ( stat = DMA_Bld_Desp( LOCAL, Global_eumbbar, channel, cdar )) | |
196 | != DMASUCCESS || | |
197 | ( stat = DMA_Bld_Curr( LOCAL, Global_eumbbar, channel, curr )) | |
198 | != DMASUCCESS || | |
199 | ( stat = DMA_Set_Mode( LOCAL, Global_eumbbar, channel, md )) | |
200 | != DMASUCCESS || | |
201 | ( stat = DMA_Start( LOCAL, Global_eumbbar, channel )) | |
202 | != DMASUCCESS ) | |
203 | { | |
204 | if ( stat == DMACHNBUSY ) | |
205 | { | |
206 | PRINT( "dev DMA: channel %d busy.\n", channel ); | |
207 | } | |
208 | else | |
209 | { | |
210 | PRINT( "dev DMA: invalid channel request.\n", channel ); | |
211 | } | |
212 | ||
213 | return DMA_ERROR; | |
214 | } | |
215 | ||
216 | /* Since we are interested at the DMA performace right now, | |
217 | we are going to do as less as possible to burden the | |
218 | 603e core. | |
219 | ||
220 | if you have epic enabled or don't care the return from | |
221 | DMA operation, you can just return SUCCESS. | |
222 | ||
223 | if you don't have epic enabled and care the DMA result, | |
224 | you can use the polling method below. | |
225 | ||
226 | Note: I'll attempt to activate the code for handling polling. | |
227 | */ | |
228 | ||
229 | #if 0 | |
230 | /* if steering interrupt to local processor, let it handle results */ | |
231 | if ( int_steer == DMA_INT_STEER_LOCAL ) | |
232 | { | |
233 | return DMA_SUCCESS; | |
234 | } | |
235 | ||
236 | /* polling since interrupt goes to PCI */ | |
237 | do | |
238 | { | |
239 | stat = DMA_ISR( Global_eumbbar, channel, dma_error_func, | |
240 | dma_error_func, dma_error_func, dma_error_func ); | |
241 | } | |
242 | while ( stat == DMANOEVENT ); | |
243 | #endif | |
244 | ||
245 | return DMA_SUCCESS; | |
246 | } | |
247 | ||
248 | /* DMA library internal functions */ | |
249 | ||
250 | /** | |
251 | * Note: | |
252 | * | |
253 | * In all following functions, the host (KAHLUA) processor has a | |
254 | * choice of accessing on board local DMA (LOCAL), | |
255 | * or DMA on a distributed KAHLUA (REMOTE). In either case, | |
256 | * the caller shall pass the configured embedded utility memory | |
257 | * block base address relative to the DMA. If LOCAL DMA is used, | |
258 | * this parameter shall be EUMBBAR, if REMOTE is used, the | |
259 | * parameter shall be the corresponding PCSRBAR. | |
260 | **/ | |
261 | ||
262 | /************************************************************** | |
263 | * function: DMA_Get_Stat | |
264 | * | |
265 | * description: return the content of status register of | |
266 | * the given DMA channel | |
267 | * | |
268 | * if error, reserved0 field all 1s. | |
269 | **************************************************************/ | |
270 | static | |
271 | DMAStatus DMA_Get_Stat( LOCATION host, unsigned int eumbbar, unsigned int channel, DMA_SR *stat ) | |
272 | { | |
273 | unsigned int tmp; | |
274 | ||
275 | if ( channel != 0 && channel != 1 || stat == 0 ) | |
276 | { | |
277 | return DMAINVALID; | |
278 | } | |
279 | ||
280 | tmp = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SR_REG] ); | |
281 | #ifdef DMADBG0 | |
282 | PRINT( "%s(%d): %s DMA %d (0x%08x) stat = 0x%08x\n", __FILE__, __LINE__, | |
283 | ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SR_REG], tmp ); | |
284 | #endif | |
285 | ||
286 | stat->reserved0 = ( tmp & 0xffffff00 ) >> 8; | |
287 | stat->lme = ( tmp & 0x00000080 ) >> 7; | |
288 | stat->reserved1 = ( tmp & 0x00000060 ) >> 5; | |
289 | stat->pe = ( tmp & 0x00000010 ) >> 4; | |
290 | stat->reserved2 = ( tmp & 0x00000008 ) >> 3; | |
291 | stat->cb = ( tmp & 0x00000004 ) >> 2; | |
292 | stat->eosi = ( tmp & 0x00000002 ) >> 1; | |
293 | stat->eocai = ( tmp & 0x00000001 ); | |
294 | ||
295 | return DMASUCCESS; | |
296 | } | |
297 | ||
298 | /************************************************************** | |
299 | * function: DMA_Get_Mode | |
300 | * | |
301 | * description: return the content of mode register of the | |
302 | * given DMA channel | |
303 | * | |
304 | * if error, return DMAINVALID, otherwise return | |
305 | * DMASUCCESS | |
306 | **************************************************************/ | |
307 | static | |
308 | DMAStatus DMA_Get_Mode( LOCATION host, unsigned eumbbar, unsigned int channel, DMA_MR *mode ) | |
309 | { | |
310 | unsigned int tmp; | |
311 | if ( channel != 0 && channel != 1 || mode == 0 ) | |
312 | { | |
313 | return DMAINVALID; | |
314 | } | |
315 | ||
316 | tmp = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_MR_REG] ); | |
317 | ||
318 | #ifdef DMADBG0 | |
319 | PRINT( "%s(%d): %s DMA %d (0x%08x) mode = 0x%08x\n", __FILE__, __LINE__, | |
320 | ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_MR_REG], tmp ); | |
321 | #endif | |
322 | ||
323 | mode->reserved0 = (tmp & 0xfff00000) >> 20; | |
324 | mode->irqs = (tmp & 0x00080000) >> 19; | |
325 | mode->pde = (tmp & 0x00040000) >> 18; | |
326 | mode->dahts = (tmp & 0x00030000) >> 16; | |
327 | mode->sahts = (tmp & 0x0000c000) >> 14; | |
328 | mode->dahe = (tmp & 0x00002000) >> 13; | |
329 | mode->sahe = (tmp & 0x00001000) >> 12; | |
330 | mode->prc = (tmp & 0x00000c00) >> 10; | |
331 | mode->reserved1 = (tmp & 0x00000200) >> 9; | |
332 | mode->eie = (tmp & 0x00000100) >> 8; | |
333 | mode->eotie = (tmp & 0x00000080) >> 7; | |
334 | mode->reserved2 = (tmp & 0x00000070) >> 4; | |
335 | mode->dl = (tmp & 0x00000008) >> 3; | |
336 | mode->ctm = (tmp & 0x00000004) >> 2; | |
337 | mode->cc = (tmp & 0x00000002) >> 1; | |
338 | mode->cs = (tmp & 0x00000001); | |
339 | ||
340 | return DMASUCCESS; | |
341 | } | |
342 | ||
343 | /************************************************************** | |
344 | * function: DMA_Set_Mode | |
345 | * | |
346 | * description: Set a new mode to a given DMA channel | |
347 | * | |
348 | * note: It is not a good idea of changing the DMA mode during | |
349 | * the middle of a transaction. | |
350 | **************************************************************/ | |
351 | static | |
352 | DMAStatus DMA_Set_Mode( LOCATION host, unsigned eumbbar, unsigned int channel, DMA_MR mode ) | |
353 | { | |
354 | unsigned int tmp; | |
355 | if ( channel != 0 && channel != 1 ) | |
356 | { | |
357 | return DMAINVALID; | |
358 | } | |
359 | ||
360 | tmp = ( mode.reserved0 & 0xfff ) << 20; | |
361 | tmp |= ( ( mode.irqs & 0x1 ) << 19); | |
362 | tmp |= ( ( mode.pde & 0x1 ) << 18 ); | |
363 | tmp |= ( ( mode.dahts & 0x3 ) << 16 ); | |
364 | tmp |= ( ( mode.sahts & 0x3 ) << 14 ); | |
365 | tmp |= ( ( mode.dahe & 0x1 ) << 13 ); | |
366 | tmp |= ( ( mode.sahe & 0x1 ) << 12 ); | |
367 | tmp |= ( ( mode.prc & 0x3 ) << 10 ); | |
368 | tmp |= ( ( mode.reserved1 & 0x1 ) << 9 ); | |
369 | tmp |= ( ( mode.eie & 0x1 ) << 8 ); | |
370 | tmp |= ( ( mode.eotie & 0x1 ) << 7 ); | |
371 | tmp |= ( ( mode.reserved2 & 0x7 ) << 4 ); | |
372 | tmp |= ( ( mode.dl & 0x1 ) << 3 ); | |
373 | tmp |= ( ( mode.ctm & 0x1 ) << 2 ); | |
374 | tmp |= ( ( mode.cc & 0x1 ) << 1 ) ; | |
375 | tmp |= ( mode.cs & 0x1 ); | |
376 | ||
377 | store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], tmp ); | |
378 | return DMASUCCESS; | |
379 | } | |
380 | ||
381 | /************************************************************ | |
382 | * function: DMA_Start | |
383 | * | |
384 | * description: start a given DMA channel transaction | |
385 | * return DMASUCCESS if success otherwise return | |
386 | * DMAStatus value | |
387 | * | |
388 | * note: this function will clear DMA_MR(CC) first, then | |
389 | * set DMA_MR(CC). | |
390 | ***********************************************************/ | |
391 | static | |
392 | DMAStatus DMA_Start( LOCATION host, unsigned int eumbbar, unsigned int channel ) | |
393 | { | |
394 | DMA_SR stat; | |
395 | unsigned int mode; | |
396 | ||
397 | if ( channel != 0 && channel != 1 ) | |
398 | { | |
399 | return DMAINVALID; | |
400 | } | |
401 | ||
402 | if ( DMA_Get_Stat( host, eumbbar, channel, &stat ) != DMASUCCESS ) | |
403 | { | |
404 | return DMAINVALID; | |
405 | } | |
406 | ||
407 | if ( stat.cb == 1 ) | |
408 | { | |
409 | /* DMA is not free */ | |
410 | return DMACHNBUSY; | |
411 | } | |
412 | ||
413 | mode = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG] ); | |
414 | /* clear DMA_MR(CS) */ | |
415 | mode &= 0xfffffffe; | |
416 | store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode ); | |
417 | ||
418 | /* set DMA_MR(CS) */ | |
419 | mode |= CS; | |
420 | store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode ); | |
421 | return DMASUCCESS; | |
422 | } | |
423 | ||
424 | /*********************************************************** | |
425 | * function: DMA_Halt | |
426 | * | |
427 | * description: halt the current dma transaction on the specified | |
428 | * channel. | |
429 | * return DMASUCCESS if success otherwise return DMAINVALID | |
430 | * | |
431 | * note: if the specified DMA channel is idle, nothing happens | |
432 | *************************************************************/ | |
433 | static | |
434 | DMAStatus DMA_Halt( LOCATION host, unsigned int eumbbar, unsigned int channel ) | |
435 | { | |
436 | unsigned int mode; | |
437 | if ( channel != 0 && channel != 1 ) | |
438 | { | |
439 | return DMAINVALID; | |
440 | } | |
441 | ||
442 | mode = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG]); | |
443 | ||
444 | /* clear DMA_MR(CS) */ | |
445 | mode &= 0xfffffffe; | |
446 | store_runtime_reg(eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG + DMA_MR_REG], mode ); | |
447 | return DMASUCCESS; | |
448 | } | |
449 | ||
450 | /************************************************************* | |
451 | * function: DMA_Chn_Cnt | |
452 | * | |
453 | * description: set the DMA_MR(CC) bit for a given channel | |
454 | * that is in chaining mode. | |
455 | * return DMASUCCESS if successfule, otherwise return | |
456 | * DMAINVALID. | |
457 | * | |
458 | * note: if the given channel is not in chaining mode, nothing | |
459 | * happen. | |
460 | * | |
461 | *************************************************************/ | |
462 | static | |
463 | DMAStatus DMA_Chn_Cnt( LOCATION host, unsigned int eumbbar, unsigned int channel ) | |
464 | { | |
465 | DMA_MR mode; | |
466 | if ( channel != 0 && channel != 1 ) | |
467 | { | |
468 | return DMAINVALID; | |
469 | } | |
470 | ||
471 | if ( DMA_Get_Mode( host, eumbbar, channel, &mode ) != DMASUCCESS ) | |
472 | { | |
473 | return DMAINVALID; | |
474 | } | |
475 | ||
476 | if ( mode.ctm == 0 ) | |
477 | { | |
478 | /* either illegal mode or not chaining mode */ | |
479 | return DMAINVALID; | |
480 | } | |
481 | ||
482 | mode.cc = 1; | |
483 | return DMA_Set_Mode( host, eumbbar, channel, mode ); | |
484 | } | |
485 | ||
486 | /************************************************************** | |
487 | * function: DMA_Bld_Desp | |
488 | * | |
489 | * description: set current descriptor address register | |
490 | * according to the desp for a given channel | |
491 | * | |
492 | * if the given channel is busy return DMACHNBUSY | |
493 | * and no change made, otherwise return DMASUCCESS. | |
494 | * | |
495 | * note: | |
496 | **************************************************************/ | |
497 | static | |
498 | DMAStatus DMA_Bld_Desp( LOCATION host, | |
499 | unsigned int eumbbar, | |
500 | unsigned int channel, | |
501 | DMA_CDAR desp ) | |
502 | { | |
503 | DMA_SR status; | |
504 | unsigned int temp; | |
505 | ||
506 | if ( channel != 0 && channel != 1 ) | |
507 | { | |
508 | /* channel number out of range */ | |
509 | return DMAINVALID; | |
510 | } | |
511 | ||
512 | if ( DMA_Get_Stat( host, eumbbar, channel, &status ) != DMASUCCESS ) | |
513 | { | |
514 | return DMAINVALID; | |
515 | } | |
516 | ||
517 | if ( status.cb == 1 ) | |
518 | { | |
519 | /* channel busy */ | |
520 | return DMACHNBUSY; | |
521 | } | |
522 | ||
523 | temp = ( desp.cda & 0x7ffffff ) << 5; | |
524 | temp |= (( desp.snen & 0x1 ) << 4 ); | |
525 | temp |= (( desp.eosie & 0x1 ) << 3 ); | |
526 | temp |= (( desp.ctt & 0x3 ) << 1 ); | |
527 | temp |= ( desp.eotd & 0x1 ); | |
528 | ||
529 | store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], temp ); | |
530 | ||
531 | #ifdef DMADBG0 | |
532 | PRINT( "%s(%d): %s DMA %d (0x%08x) cdar := 0x%08x\n", __FILE__, __LINE__, | |
533 | ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], temp ); | |
534 | #endif | |
535 | ||
536 | return DMASUCCESS; | |
537 | } | |
538 | ||
539 | /************************************************************** | |
540 | * function: DMA_Poke_Desp | |
541 | * | |
542 | * description: poke the current descriptor address register | |
543 | * for a given channel | |
544 | * | |
545 | * return DMASUCCESS if no error | |
546 | * | |
547 | * note: Due to the undeterministic parallellism of DMA operation, | |
548 | * the value returned by this function shall be taken as | |
549 | * the most recently used descriptor when the last time | |
550 | * DMA starts a chaining mode operation. | |
551 | **************************************************************/ | |
552 | static | |
553 | DMAStatus DMA_Poke_Desp( LOCATION host, | |
554 | unsigned int eumbbar, | |
555 | unsigned int channel, | |
556 | DMA_CDAR *desp ) | |
557 | { | |
558 | unsigned int cdar; | |
559 | if ( channel != 0 && channel != 1 || desp == 0 ) | |
560 | { | |
561 | return DMAINVALID; | |
562 | } | |
563 | ||
564 | cdar = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG] ); | |
565 | ||
566 | #ifdef DMADBG0 | |
567 | PRINT( "%s(%d): %s DMA %d (0x%08x) cdar : 0x%08x\n", __FILE__, __LINE__, | |
568 | ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], cdar ); | |
569 | #endif | |
570 | ||
571 | ||
572 | desp->cda = ( cdar & 0xffffffe0 ) >> 5; | |
573 | desp->snen = ( cdar & 0x00000010 ) >> 4; | |
574 | desp->eosie = ( cdar & 0x00000008 ) >> 3; | |
575 | desp->ctt = ( cdar & 0x00000006 ) >> 1; | |
576 | desp->eotd = ( cdar & 0x00000001 ); | |
577 | ||
578 | return DMASUCCESS; | |
579 | } | |
580 | ||
581 | /************************************************************** | |
582 | * function: DMA_Bld_Curr | |
583 | * | |
584 | * description: set current src, dest, byte count registers | |
585 | * according to the desp for a given channel | |
586 | * return DMASUCCESS if no error. | |
587 | * | |
588 | * note: | |
589 | **************************************************************/ | |
590 | static | |
591 | DMAStatus DMA_Bld_Curr( LOCATION host, | |
592 | unsigned int eumbbar, | |
593 | unsigned int channel, | |
594 | DMA_CURR desp ) | |
595 | { | |
596 | DMA_SR status; | |
597 | if ( channel != 0 && channel != 1 ) | |
598 | { | |
599 | /* channel number out of range */ | |
600 | return DMAINVALID; | |
601 | } | |
602 | ||
603 | if ( DMA_Get_Stat( host, eumbbar, channel, &status ) != DMASUCCESS ) | |
604 | { | |
605 | return DMAINVALID; | |
606 | } | |
607 | ||
608 | if ( status.cb == 1 ) | |
609 | { | |
610 | /* channel busy */ | |
611 | return DMACHNBUSY; | |
612 | } | |
613 | ||
614 | desp.byte_cnt &= 0x03ffffff; /* upper 6-bits are 0s */ | |
615 | ||
616 | store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SAR_REG], desp.src_addr ); | |
617 | #ifdef DMADBG0 | |
618 | PRINT( "%s(%d): %s DMA %d (0x%08x) src := 0x%08x\n", __FILE__, __LINE__, | |
619 | ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.src_addr ); | |
620 | #endif | |
621 | ||
622 | store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_DAR_REG], desp.dest_addr ); | |
623 | #ifdef DMADBG0 | |
624 | PRINT( "%s(%d): %s DMA %d (0x%08x) dest := 0x%08x\n", __FILE__, __LINE__, | |
625 | ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.dest_addr ); | |
626 | #endif | |
627 | ||
628 | store_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_BCR_REG], desp.byte_cnt ); | |
629 | #ifdef DMADBG0 | |
630 | PRINT( "%s(%d): %s DMA %d (0x%08x) count := 0x%08x\n", __FILE__, __LINE__, | |
631 | ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp.byte_cnt ); | |
632 | #endif | |
633 | ||
634 | ||
635 | return DMASUCCESS; | |
636 | ||
637 | } | |
638 | ||
639 | /************************************************************** | |
640 | * function: DMA_Poke_Curr | |
641 | * | |
642 | * description: poke the current src, dest, byte count registers | |
643 | * for a given channel. | |
644 | * | |
645 | * return DMASUCCESS if no error | |
646 | * | |
647 | * note: Due to the undeterministic parallelism, in chaining | |
648 | * mode, the value returned by this function shall | |
649 | * be taken as reference when the query is made rather | |
650 | * than the absolute snapshot when the value is returned. | |
651 | **************************************************************/ | |
652 | static | |
653 | DMAStatus DMA_Poke_Curr( LOCATION host, | |
654 | unsigned int eumbbar, | |
655 | unsigned int channel, | |
656 | DMA_CURR* desp ) | |
657 | { | |
658 | if ( channel != 0 && channel != 1 || desp == 0 ) | |
659 | { | |
660 | return DMAINVALID; | |
661 | } | |
662 | ||
663 | desp->src_addr = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_SAR_REG] ); | |
664 | #ifdef DMADBG0 | |
665 | PRINT( "%s(%d): %s DMA %d (0x%08x) src : 0x%08x\n", __FILE__, __LINE__, | |
666 | ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->src_addr ); | |
667 | #endif | |
668 | ||
669 | desp->dest_addr = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_DAR_REG] ); | |
670 | #ifdef DMADBG0 | |
671 | PRINT( "%s(%d): %s DMA %d (0x%08x) dest : 0x%08x\n", __FILE__, __LINE__, | |
672 | ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->dest_addr ); | |
673 | #endif | |
674 | ||
675 | desp->byte_cnt = load_runtime_reg( eumbbar, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_BCR_REG] ); | |
676 | #ifdef DMADBG0 | |
677 | PRINT( "%s(%d): %s DMA %d (0x%08x) count : 0x%08x\n", __FILE__, __LINE__, | |
678 | ( host == LOCAL ? "local" : "remote" ), channel, dma_reg_tb[host][channel*NUM_DMA_REG+DMA_CDAR_REG], desp->byte_cnt ); | |
679 | #endif | |
680 | ||
681 | ||
682 | return DMASUCCESS; | |
683 | } | |
684 | ||
685 | /***************************************************************** | |
686 | * function: dma_error_func | |
687 | * | |
688 | * description: display the error information | |
689 | * | |
690 | * note: This seems like a highly convoluted way to handle messages, | |
691 | * but I'll leave it as it was in device.c when I moved it into the | |
692 | * DMA library source. | |
693 | ****************************************************************/ | |
694 | static | |
695 | DMAStatus dma_error_func( unsigned int eumbbar, unsigned int chn, DMAStatus err) | |
696 | { | |
697 | unsigned char *msg[] = | |
698 | { | |
699 | "Local Memory Error", | |
700 | "PCI Error", | |
701 | "Channel Busy", | |
702 | "End-of-Segment Interrupt", | |
703 | "End-of-Chain/Direct Interrupt", | |
704 | }; | |
705 | ||
706 | if ( err >= DMALMERROR && err <= DMAEOCAINT ) | |
707 | { | |
708 | PRINT( "DMA Status: channel %d %s\n", chn, msg[err-DMASUCCESS-1] ); | |
709 | } | |
710 | ||
711 | return err; | |
712 | ||
713 | } | |
714 | ||
715 | /************************************************************* | |
716 | * function: DMA_ISR | |
717 | * | |
718 | * description: DMA interrupt service routine | |
719 | * return DMAStatus value based on | |
720 | * the status | |
721 | * | |
722 | *************************************************************/ | |
723 | static | |
724 | DMAStatus DMA_ISR( unsigned int eumbbar, | |
725 | unsigned int channel, | |
726 | DMAStatus (*lme_func)( unsigned int, unsigned int, DMAStatus ), | |
727 | DMAStatus (*pe_func) ( unsigned int, unsigned int, DMAStatus ), | |
728 | DMAStatus (*eosi_func)( unsigned int, unsigned int, DMAStatus ), | |
729 | DMAStatus (*eocai_func)(unsigned int, unsigned int, DMAStatus )) | |
730 | { | |
731 | ||
732 | DMA_SR stat; | |
733 | DMAStatus rval = DMANOEVENT; | |
734 | unsigned int temp; | |
735 | ||
736 | if ( channel != 0 && channel != 1 ) | |
737 | { | |
738 | return DMAINVALID; | |
739 | } | |
740 | ||
741 | if ( DMA_Get_Stat( LOCAL, eumbbar, channel, &stat ) != DMASUCCESS ) | |
742 | { | |
743 | return DMAINVALID; | |
744 | } | |
745 | ||
746 | if ( stat.lme == 1 ) | |
747 | { | |
748 | /* local memory error */ | |
749 | rval = DMALMERROR; | |
750 | if ( lme_func != 0 ) | |
751 | { | |
752 | rval = (*lme_func)(eumbbar, channel, DMALMERROR ); | |
753 | } | |
754 | ||
755 | } | |
756 | else if ( stat.pe == 1 ) | |
757 | { | |
8bde7f77 | 758 | /* PCI error */ |
327f7a02 WD |
759 | rval = DMAPERROR; |
760 | if ( pe_func != 0 ) | |
761 | { | |
762 | rval = (*pe_func)(eumbbar, channel, DMAPERROR ); | |
763 | } | |
764 | ||
765 | } | |
766 | else if ( stat.eosi == 1 ) | |
767 | { | |
768 | /* end-of-segment interrupt */ | |
769 | rval = DMAEOSINT; | |
770 | if ( eosi_func != 0 ) | |
771 | { | |
772 | rval = (*eosi_func)(eumbbar, channel, DMAEOSINT ); | |
773 | } | |
774 | } | |
775 | else | |
776 | { | |
777 | /* End-of-chain/direct interrupt */ | |
778 | rval = DMAEOCAINT; | |
779 | if ( eocai_func != 0 ) | |
780 | { | |
781 | rval = (*eocai_func)(eumbbar, channel, DMAEOCAINT ); | |
782 | } | |
783 | } | |
784 | ||
785 | temp = ( stat.reserved0 & 0xffffff ) << 8; | |
8bde7f77 | 786 | temp |= ( ( stat.lme & 0x1 ) << 7 ); /* write one to clear */ |
327f7a02 WD |
787 | temp |= ( ( stat.reserved1 & 0x3 ) << 5 ); |
788 | temp |= ( ( stat.pe & 0x1 ) << 4 ); /* write one to clear */ | |
789 | temp |= ( ( stat.reserved2 & 0x1 ) << 3 ); | |
790 | temp |= ( ( stat.cb & 0x1 ) << 2 ); /* write one to clear */ | |
791 | temp |= ( ( stat.eosi & 0x1 ) << 1 ); /* write one to clear */ | |
792 | temp |= ( stat.eocai & 0x1 ); /* write one to clear */ | |
793 | ||
794 | store_runtime_reg( eumbbar, dma_reg_tb[LOCAL][channel*NUM_DMA_REG + DMA_SR_REG], temp ); | |
795 | ||
796 | #ifdef DMADBG0 | |
797 | PRINT( "%s(%d): DMA channel %d SR := 0x%08x\n", __FILE__, __LINE__, channel, temp ); | |
798 | #endif | |
799 | ||
800 | return rval; | |
801 | } |