]>
Commit | Line | Data |
---|---|---|
327f7a02 WD |
1 | /********************************************************* |
2 | * $Id | |
3 | * | |
4 | * copyright @ Motorola, 1999 | |
5 | *********************************************************/ | |
6 | #include "i2o.h" | |
7 | ||
8 | extern unsigned int load_runtime_reg( unsigned int eumbbar, unsigned int reg ); | |
9 | #pragma Alias( load_runtime_reg, "load_runtime_reg" ); | |
10 | ||
11 | extern void store_runtime_reg( unsigned int eumbbar, unsigned int reg, unsigned int val ); | |
12 | #pragma Alias( store_runtime_reg, "store_runtime_reg" ); | |
13 | ||
14 | typedef struct _fifo_stat | |
15 | { | |
16 | QUEUE_SIZE qsz; | |
17 | unsigned int qba; | |
18 | } FIFOSTAT; | |
19 | ||
20 | FIFOSTAT fifo_stat = { QSIZE_4K, 0xffffffff }; | |
21 | ||
22 | /********************************************************************************** | |
23 | * function: I2OMsgEnable | |
24 | * | |
25 | * description: Enable the interrupt associated with in/out bound msg | |
26 | * return I2OSUCCESS if no error, otherwise return I2OMSGINVALID. | |
27 | * | |
28 | * All previously enabled interrupts are preserved. | |
29 | * note: | |
30 | * Inbound message interrupt generated by PCI master and serviced by local processor | |
31 | * Outbound message interrupt generated by local processor and serviced by PCI master | |
32 | * | |
33 | * local processor needs to enable its inbound interrupts it wants to handle(LOCAL) | |
34 | * PCI master needs to enable the outbound interrupts of devices it wants to handle(REMOTE) | |
35 | ************************************************************************************/ | |
36 | I2OSTATUS I2OMsgEnable ( LOCATION loc, /* REMOTE/LOCAL */ | |
8bde7f77 WD |
37 | unsigned int base, /* pcsrbar/eumbbar */ |
38 | unsigned char n ) /* b'1' - msg 0 | |
39 | * b'10'- msg 1 | |
40 | * b'11'- both | |
327f7a02 WD |
41 | */ |
42 | { | |
43 | unsigned int reg, val; | |
44 | if ( ( n & 0x3 ) == 0 ) | |
45 | { | |
46 | /* neither msg 0, nor msg 1 */ | |
47 | return I2OMSGINVALID; | |
48 | } | |
49 | ||
50 | n = (~n) & 0x3; | |
51 | /* LOCATION - REMOTE : enable outbound message of device, pcsrbar as base | |
52 | * LOCAL : enable local inbound message, eumbbar as base | |
53 | */ | |
54 | reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); | |
55 | val = load_runtime_reg( base, reg ); | |
56 | ||
57 | val &= 0xfffffffc; /* masked out the msg interrupt bits */ | |
58 | val |= n; /* LSB are the one we want */ | |
59 | store_runtime_reg( base, reg, val ); | |
60 | ||
61 | return I2OSUCCESS; | |
62 | } | |
63 | ||
64 | /********************************************************************************* | |
65 | * function: I2OMsgDisable | |
66 | * | |
67 | * description: Disable the interrupt associated with in/out bound msg | |
68 | * Other previously enabled interrupts are preserved. | |
69 | * return I2OSUCCESS if no error otherwise return I2OMSGINVALID | |
70 | * | |
71 | * note: | |
72 | * local processor needs to disable its inbound interrupts it is not interested(LOCAL) | |
73 | * PCI master needs to disable outbound interrupts of devices it is not interested(REMOTE) | |
74 | *********************************************************************************/ | |
75 | I2OSTATUS I2OMsgDisable( LOCATION loc, /* REMOTE/LOCAL */ | |
8bde7f77 WD |
76 | unsigned int base, /* pcsrbar/eumbbar */ |
77 | unsigned char n ) /* b'1' - msg 0 | |
327f7a02 WD |
78 | * b'10'- msg 1 |
79 | * b'11'- both | |
80 | */ | |
81 | { | |
82 | unsigned int reg, val; | |
83 | ||
84 | if ( ( n & 0x3 ) == 0 ) | |
85 | { | |
86 | /* neither msg 0, nor msg 1 */ | |
87 | return I2OMSGINVALID; | |
88 | } | |
89 | ||
90 | /* LOCATION - REMOTE : disable outbound message interrupt of device, pcsrbar as base | |
91 | * LOCAL : disable local inbound message interrupt, eumbbar as base | |
92 | */ | |
93 | reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); | |
94 | val = load_runtime_reg( base, reg ); | |
95 | ||
96 | val &= 0xfffffffc; /* masked out the msg interrupt bits */ | |
97 | val |= ( n & 0x3 ); | |
98 | store_runtime_reg( base, reg, val ); | |
99 | ||
100 | return I2OSUCCESS; | |
101 | ||
102 | } | |
103 | ||
104 | /************************************************************************** | |
105 | * function: I2OMsgGet | |
106 | * | |
107 | * description: Local processor reads the nth Msg register from its inbound msg, | |
108 | * or a PCI Master reads nth outbound msg from device | |
109 | * | |
110 | * return I2OSUCCESS if no error, otherwise return I2OMSGINVALID. | |
111 | * | |
112 | * note: | |
113 | * If it is not local, pcsrbar must be passed to the function. Otherwise eumbbar is passed. | |
114 | * If it is remote, outbound msg on the device is read; otherwise local inbound msg is read | |
115 | *************************************************************************/ | |
116 | I2OSTATUS I2OMsgGet ( LOCATION loc, /* REMOTE/LOCAL */ | |
8bde7f77 WD |
117 | unsigned int base, /*pcsrbar/eumbbar */ |
118 | unsigned int n, /* 0 or 1 */ | |
119 | unsigned int *msg ) | |
327f7a02 WD |
120 | { |
121 | if ( n >= I2O_NUM_MSG || msg == 0 ) | |
122 | { | |
123 | return I2OMSGINVALID; | |
124 | } | |
125 | ||
126 | if ( loc == REMOTE ) | |
127 | { | |
128 | /* read the outbound msg of the device, pcsrbar as base */ | |
129 | *msg = load_runtime_reg( base, I2O_OMR0+n*I2O_REG_OFFSET ); | |
130 | } | |
131 | else | |
132 | { | |
133 | /* read the inbound msg sent by PCI master, eumbbar as base */ | |
134 | *msg = load_runtime_reg( base, I2O_IMR0+n*I2O_REG_OFFSET ); | |
135 | } | |
136 | ||
137 | return I2OSUCCESS; | |
138 | } | |
139 | ||
140 | /*************************************************************** | |
141 | * function: I2OMsgPost | |
142 | * | |
143 | * description: Kahlua writes to its nth outbound msg register | |
144 | * PCI master writes to nth inbound msg register of device | |
145 | * | |
146 | * return I2OSUCCESS if no error, otherwise return I2OMSGINVALID. | |
147 | * | |
148 | * note: | |
149 | * If it is not local, pcsrbar must be passed to the function. Otherwise eumbbar is passed. | |
150 | * | |
151 | * If it is remote, inbound msg on the device is written; otherwise local outbound msg is written | |
152 | ***************************************************************/ | |
153 | I2OSTATUS I2OMsgPost( LOCATION loc, /* REMOTE/LOCAL */ | |
8bde7f77 WD |
154 | unsigned int base, /*pcsrbar/eumbbar */ |
155 | unsigned int n, /* 0 or 1 */ | |
156 | unsigned int msg ) | |
327f7a02 WD |
157 | { |
158 | if ( n >= I2O_NUM_MSG ) | |
159 | { | |
160 | return I2OMSGINVALID; | |
161 | } | |
162 | ||
163 | if ( loc == REMOTE ) | |
164 | { | |
165 | /* write to the inbound msg register of the device, pcsrbar as base */ | |
166 | store_runtime_reg( base, I2O_IMR0+n*I2O_REG_OFFSET, msg ); | |
167 | } | |
168 | else | |
169 | { | |
170 | /* write to the outbound msg register for PCI master to read, eumbbar as base */ | |
171 | store_runtime_reg( base, I2O_OMR0+n*I2O_REG_OFFSET, msg ); | |
172 | } | |
173 | ||
174 | return I2OSUCCESS; | |
175 | } | |
176 | ||
177 | /*********************************************************************** | |
178 | * function: I2ODBEnable | |
179 | * | |
180 | * description: Local processor enables it's inbound doorbell interrupt | |
181 | * PCI master enables outbound doorbell interrupt of devices | |
182 | * Other previously enabled interrupts are preserved. | |
183 | * Return I2OSUCCESS if no error otherwise return I2ODBINVALID | |
184 | * | |
185 | * note: | |
186 | * In DoorBell interrupt is generated by PCI master and serviced by local processor | |
187 | * Out Doorbell interrupt is generated by local processor and serviced by PCI master | |
188 | * | |
189 | * Out Doorbell interrupt is generated by local processor and serviced by PCI master | |
190 | * PCI master needs to enable the outbound doorbell interrupts of device it wants to handle | |
191 | **********************************************************************/ | |
192 | I2OSTATUS I2ODBEnable( LOCATION loc, /* REMOTE/LOCAL */ | |
8bde7f77 WD |
193 | unsigned int base, /* pcsrbar/eumbbar */ |
194 | unsigned int in_db ) /* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ | |
327f7a02 WD |
195 | { |
196 | ||
197 | /* LOCATION - REMOTE : PCI master initializes outbound doorbell message of device | |
198 | * LOCAL : Kahlua initializes its inbound doorbell message | |
199 | */ | |
200 | unsigned int val; | |
201 | ||
202 | if ( loc == LOCAL && ( in_db & 0x3 ) == 0 ) | |
203 | { | |
204 | return I2ODBINVALID; | |
205 | } | |
206 | ||
207 | if ( loc == REMOTE ) | |
208 | { | |
209 | /* pcsrbar is base */ | |
210 | val = load_runtime_reg( base, I2O_OMIMR ); | |
211 | val &= 0xfffffff7; | |
8bde7f77 | 212 | store_runtime_reg( base, I2O_OMIMR , val ); |
327f7a02 WD |
213 | } |
214 | else | |
215 | { | |
216 | /* eumbbar is base */ | |
217 | val = load_runtime_reg( base, I2O_IMIMR); | |
8bde7f77 WD |
218 | in_db = ( (~in_db) & 0x3 ) << 3; |
219 | val = ( val & 0xffffffe7) | in_db; | |
220 | store_runtime_reg( base, I2O_IMIMR, val ); | |
327f7a02 WD |
221 | } |
222 | ||
223 | return I2OSUCCESS; | |
224 | } | |
225 | ||
226 | /********************************************************************************** | |
227 | * function: I2ODBDisable | |
228 | * | |
229 | * description: local processor disables its inbound DoorBell Interrupt | |
230 | * PCI master disables outbound DoorBell interrupt of device | |
231 | * Other previously enabled interrupts are preserved. | |
232 | * return I2OSUCCESS if no error.Otherwise return I2ODBINVALID | |
233 | * | |
234 | * note: | |
235 | * local processor needs to disable its inbound doorbell interrupts it is not interested | |
236 | * | |
237 | * PCI master needs to disable outbound doorbell interrupts of device it is not interested | |
238 | ************************************************************************************/ | |
239 | I2OSTATUS I2ODBDisable( LOCATION loc, /* REMOTE/LOCAL */ | |
8bde7f77 WD |
240 | unsigned int base, /* pcsrbar/eumbbar */ |
241 | unsigned int in_db ) /* when LOCAL, I2O_IN_DB, MC, I2O_IN_DB|MC */ | |
327f7a02 WD |
242 | { |
243 | /* LOCATION - REMOTE : handle device's out bound message initialization | |
244 | * LOCAL : handle local in bound message initialization | |
245 | */ | |
246 | unsigned int val; | |
247 | ||
248 | if ( loc == LOCAL && ( in_db & 0x3 ) == 0 ) | |
249 | { | |
250 | return I2ODBINVALID; | |
251 | } | |
252 | ||
253 | if ( loc == REMOTE ) | |
254 | { | |
255 | /* pcsrbar is the base */ | |
256 | val = load_runtime_reg( base, I2O_OMIMR ); | |
257 | val |= 0x8; | |
8bde7f77 | 258 | store_runtime_reg( base, I2O_OMIMR, val ); |
327f7a02 WD |
259 | } |
260 | else | |
261 | { | |
262 | val = load_runtime_reg( base, I2O_IMIMR); | |
8bde7f77 WD |
263 | in_db = ( in_db & 0x3 ) << 3; |
264 | val |= in_db; | |
265 | store_runtime_reg( base, I2O_IMIMR, val ); | |
327f7a02 WD |
266 | } |
267 | ||
268 | return I2OSUCCESS; | |
269 | } | |
270 | ||
271 | /********************************************************************************** | |
272 | * function: I2ODBGet | |
273 | * | |
274 | * description: Local processor reads its in doorbell register, | |
275 | * PCI master reads the outdoorbell register of device. | |
276 | * After a doorbell register is read, the whole register will be cleared. | |
277 | * Otherwise, HW keeps generating interrupt. | |
278 | * | |
279 | * note: | |
280 | * If it is not local, pcsrbar must be passed to the function. | |
281 | * Otherwise eumbbar is passed. | |
282 | * | |
283 | * If it is remote, out doorbell register on the device is read. | |
284 | * Otherwise local in doorbell is read | |
285 | * | |
286 | * If the register is not cleared by write to it, any remaining bit of b'1's | |
287 | * will cause interrupt pending. | |
288 | *********************************************************************************/ | |
289 | unsigned int I2ODBGet( LOCATION loc, /* REMOTE/LOCAL */ | |
8bde7f77 | 290 | unsigned int base) /* pcsrbar/eumbbar */ |
327f7a02 WD |
291 | { |
292 | unsigned int msg, val; | |
293 | ||
294 | if ( loc == REMOTE ) | |
295 | { | |
296 | /* read outbound doorbell register of device, pcsrbar is the base */ | |
8bde7f77 WD |
297 | val = load_runtime_reg( base, I2O_ODBR ); |
298 | msg = val & 0xe0000000; | |
299 | store_runtime_reg( base, I2O_ODBR, val ); /* clear the register */ | |
327f7a02 WD |
300 | } |
301 | else | |
302 | { | |
303 | /* read the inbound doorbell register, eumbbar is the base */ | |
8bde7f77 WD |
304 | val = load_runtime_reg( base, I2O_IDBR ); |
305 | store_runtime_reg( base, I2O_IDBR, val ); /* clear the register */ | |
327f7a02 WD |
306 | msg = val; |
307 | } | |
308 | ||
309 | return msg; | |
310 | } | |
311 | ||
312 | /********************************************************************** | |
313 | * function: I2ODBPost | |
314 | * | |
315 | * description: local processor writes to a outbound doorbell register, | |
316 | * PCI master writes to the inbound doorbell register of device | |
317 | * | |
318 | * note: | |
319 | * If it is not local, pcsrbar must be passed to the function. | |
320 | * Otherwise eumbbar is passed. | |
321 | * | |
322 | * If it is remote, in doorbell register on the device is written. | |
323 | * Otherwise local out doorbell is written | |
324 | *********************************************************************/ | |
325 | void I2ODBPost( LOCATION loc, /* REMOTE/LOCAL */ | |
8bde7f77 WD |
326 | unsigned int base, /* pcsrbar/eumbbar */ |
327 | unsigned int msg ) /* in / out */ | |
327f7a02 WD |
328 | { |
329 | if ( loc == REMOTE ) | |
330 | { | |
331 | /* write to inbound doorbell register of device, pcsrbar is the base */ | |
332 | store_runtime_reg( base, I2O_IDBR, msg ); | |
333 | } | |
334 | else | |
335 | { | |
336 | /* write to local outbound doorbell register, eumbbar is the base */ | |
337 | store_runtime_reg( base, I2O_ODBR, msg & 0x1fffffff ); | |
338 | } | |
339 | ||
340 | } | |
341 | ||
342 | /******************************************************************** | |
343 | * function: I2OOutMsgStatGet | |
344 | * | |
345 | * description: PCI master reads device's outbound msg unit interrupt status. | |
346 | * Reading an interrupt status register, | |
347 | * the register will be cleared. | |
348 | * | |
349 | * The value of the status register is AND with the outbound | |
350 | * interrupt mask and result is returned. | |
351 | * | |
352 | * note: | |
353 | * pcsrbar must be passed to the function. | |
354 | ********************************************************************/ | |
355 | I2OSTATUS I2OOutMsgStatGet( unsigned int pcsrbar, I2OOMSTAT *val ) | |
356 | { | |
357 | unsigned int stat; | |
358 | unsigned int mask; | |
359 | ||
360 | if ( val == 0 ) | |
361 | { | |
362 | return I2OINVALID; | |
363 | } | |
364 | ||
365 | /* read device's outbound status */ | |
366 | stat = load_runtime_reg( pcsrbar, I2O_OMISR ); | |
367 | mask = load_runtime_reg( pcsrbar, I2O_OMIMR ); | |
368 | store_runtime_reg( pcsrbar, I2O_OMISR, stat & 0xffffffd7); | |
369 | ||
370 | stat &= mask; | |
371 | val->rsvd0 = ( stat & 0xffffffc0 ) >> 6; | |
372 | val->opqi = ( stat & 0x00000020 ) >> 5; | |
373 | val->rsvd1 = ( stat & 0x00000010 ) >> 4; | |
374 | val->odi = ( stat & 0x00000008 ) >> 3; | |
375 | val->rsvd2 = ( stat & 0x00000004 ) >> 2; | |
376 | val->om1i = ( stat & 0x00000002 ) >> 1; | |
377 | val->om0i = ( stat & 0x00000001 ); | |
378 | ||
379 | return I2OSUCCESS; | |
380 | } | |
381 | ||
382 | /******************************************************************** | |
383 | * function: I2OInMsgStatGet | |
384 | * | |
385 | * description: Local processor reads its inbound msg unit interrupt status. | |
386 | * Reading an interrupt status register, | |
387 | * the register will be cleared. | |
388 | * | |
389 | * The inbound msg interrupt status is AND with the inbound | |
390 | * msg interrupt mask and result is returned. | |
391 | * | |
392 | * note: | |
393 | * eumbbar must be passed to the function. | |
394 | ********************************************************************/ | |
395 | I2OSTATUS I2OInMsgStatGet(unsigned int eumbbar, I2OIMSTAT *val) | |
396 | { | |
397 | unsigned int stat; | |
398 | unsigned int mask; | |
399 | ||
400 | if ( val == 0 ) | |
401 | { | |
402 | return I2OINVALID; | |
403 | } | |
404 | ||
405 | /* read device's outbound status */ | |
406 | stat = load_runtime_reg( eumbbar, I2O_OMISR ); | |
407 | mask = load_runtime_reg( eumbbar, I2O_OMIMR ); | |
408 | store_runtime_reg( eumbbar, I2O_OMISR, stat & 0xffffffe7 ); | |
409 | ||
410 | stat &= mask; | |
411 | val->rsvd0 = ( stat & 0xfffffe00 ) >> 9; | |
412 | val->ofoi = ( stat & 0x00000100 ) >> 8; | |
413 | val->ipoi = ( stat & 0x00000080 ) >> 7; | |
414 | val->rsvd1 = ( stat & 0x00000040 ) >> 6; | |
415 | val->ipqi = ( stat & 0x00000020 ) >> 5; | |
416 | val->mci = ( stat & 0x00000010 ) >> 4; | |
417 | val->idi = ( stat & 0x00000008 ) >> 3; | |
418 | val->rsvd2 = ( stat & 0x00000004 ) >> 2; | |
419 | val->im1i = ( stat & 0x00000002 ) >> 1; | |
420 | val->im0i = ( stat & 0x00000001 ); | |
421 | ||
422 | return I2OSUCCESS; | |
423 | ||
424 | } | |
425 | ||
426 | /*********************************************************** | |
427 | * function: I2OFIFOInit | |
428 | * | |
429 | * description: Configure the I2O FIFO, including QBAR, | |
430 | * IFHPR/IFTPR, IPHPR/IPTPR, OFHPR/OFTPR, | |
431 | * OPHPR/OPTPR, MUCR. | |
432 | * | |
433 | * return I2OSUCCESS if no error, | |
434 | * otherwise return I2OQUEINVALID | |
435 | * | |
436 | * note: It is NOT this driver's responsibility of initializing | |
437 | * MFA blocks, i.e., FIFO queue itself. The MFA blocks | |
438 | * must be initialized before I2O unit can be used. | |
439 | ***********************************************************/ | |
440 | I2OSTATUS I2OFIFOInit( unsigned int eumbbar, | |
441 | QUEUE_SIZE sz, /* value of CQS of MUCR */ | |
442 | unsigned int qba) /* queue base address that must be aligned at 1M */ | |
443 | { | |
444 | ||
445 | if ( ( qba & 0xfffff ) != 0 ) | |
446 | { | |
447 | /* QBA must be aligned at 1Mbyte boundary */ | |
448 | return I2OQUEINVALID; | |
449 | } | |
450 | ||
451 | store_runtime_reg( eumbbar, I2O_QBAR, qba ); | |
452 | store_runtime_reg( eumbbar, I2O_MUCR, (unsigned int)sz ); | |
453 | store_runtime_reg( eumbbar, I2O_IFHPR, qba ); | |
454 | store_runtime_reg( eumbbar, I2O_IFTPR, qba ); | |
455 | store_runtime_reg( eumbbar, I2O_IPHPR, qba + 1 * ( sz << 11 )); | |
456 | store_runtime_reg( eumbbar, I2O_IPTPR, qba + 1 * ( sz << 11 )); | |
457 | store_runtime_reg( eumbbar, I2O_OFHPR, qba + 2 * ( sz << 11 )); | |
458 | store_runtime_reg( eumbbar, I2O_OFTPR, qba + 2 * ( sz << 11 )); | |
459 | store_runtime_reg( eumbbar, I2O_OPHPR, qba + 3 * ( sz << 11 )); | |
460 | store_runtime_reg( eumbbar, I2O_OPTPR, qba + 3 * ( sz << 11 )); | |
461 | ||
462 | fifo_stat.qsz = sz; | |
463 | fifo_stat.qba = qba; | |
464 | ||
465 | return I2OSUCCESS; | |
466 | } | |
467 | ||
468 | /************************************************** | |
469 | * function: I2OFIFOEnable | |
470 | * | |
471 | * description: Enable the circular queue | |
472 | * return I2OSUCCESS if no error. | |
473 | * Otherwise I2OQUEINVALID is returned. | |
474 | * | |
475 | * note: | |
476 | *************************************************/ | |
477 | I2OSTATUS I2OFIFOEnable( unsigned int eumbbar ) | |
478 | { | |
479 | unsigned int val; | |
480 | ||
481 | if ( fifo_stat.qba == 0xfffffff ) | |
482 | { | |
483 | return I2OQUEINVALID; | |
484 | } | |
485 | ||
486 | val = load_runtime_reg( eumbbar, I2O_MUCR ); | |
487 | store_runtime_reg( eumbbar, I2O_MUCR, val | 0x1 ); | |
488 | ||
489 | return I2OSUCCESS; | |
490 | } | |
491 | ||
492 | /************************************************** | |
493 | * function: I2OFIFODisable | |
494 | * | |
495 | * description: Disable the circular queue | |
496 | * | |
497 | * note: | |
498 | *************************************************/ | |
499 | void I2OFIFODisable( unsigned int eumbbar ) | |
500 | { | |
501 | if ( fifo_stat.qba == 0xffffffff ) | |
502 | { | |
503 | /* not enabled */ | |
504 | return; | |
505 | } | |
506 | ||
507 | unsigned int val = load_runtime_reg( eumbbar, I2O_MUCR ); | |
508 | store_runtime_reg( eumbbar, I2O_MUCR, val & 0xfffffffe ); | |
509 | } | |
510 | ||
511 | /**************************************************** | |
512 | * function: I2OFIFOAlloc | |
513 | * | |
514 | * description: Allocate a free MFA from free FIFO. | |
515 | * return I2OSUCCESS if no error. | |
516 | * return I2OQUEEMPTY if no more free MFA. | |
517 | * return I2OINVALID on other errors. | |
518 | * | |
519 | * A free MFA must be allocated before a | |
520 | * message can be posted. | |
521 | * | |
522 | * note: | |
523 | * PCI Master allocates a free MFA from inbound queue of device | |
524 | * (pcsrbar is the base,) through the inbound queue port of device | |
525 | * while local processor allocates a free MFA from its outbound | |
526 | * queue (eumbbar is the base.) | |
527 | * | |
528 | ****************************************************/ | |
529 | I2OSTATUS I2OFIFOAlloc( LOCATION loc, | |
8bde7f77 WD |
530 | unsigned int base, |
531 | void **pMsg ) | |
327f7a02 WD |
532 | { |
533 | I2OSTATUS stat = I2OSUCCESS; | |
534 | void *pHdr, *pTil; | |
535 | ||
536 | if ( pMsg == 0 || *pMsg == 0 || fifo_stat.qba == 0xffffffff ) | |
537 | { | |
538 | /* not configured */ | |
539 | return I2OQUEINVALID; | |
540 | } | |
541 | ||
542 | if ( loc == REMOTE ) | |
543 | { | |
544 | /* pcsrbar is the base and read the inbound free tail ptr */ | |
545 | pTil = (void *)load_runtime_reg( base, I2O_IFQPR ); | |
8bde7f77 WD |
546 | if ( ( (unsigned int)pTil & 0xFFFFFFF ) == 0xFFFFFFFF ) |
547 | { | |
327f7a02 | 548 | stat = I2OQUEEMPTY; |
8bde7f77 | 549 | } |
327f7a02 | 550 | else |
8bde7f77 | 551 | { |
327f7a02 WD |
552 | *pMsg = pTil; |
553 | } | |
554 | } | |
555 | else | |
556 | { | |
557 | /* eumbbar is the base and read the outbound free tail ptr */ | |
558 | pHdr = (void *)load_runtime_reg( base, I2O_OFHPR ); /* queue head */ | |
559 | pTil = (void *)load_runtime_reg( base, I2O_OFTPR ); /* queue tail */ | |
560 | ||
561 | /* check underflow */ | |
562 | if ( pHdr == pTil ) | |
563 | { | |
564 | /* hdr and til point to the same fifo item, no free MFA */ | |
8bde7f77 | 565 | stat = I2OQUEEMPTY; |
327f7a02 WD |
566 | } |
567 | else | |
568 | { | |
569 | /* update OFTPR */ | |
570 | *pMsg = (void *)(*(unsigned char *)pTil); | |
571 | pTil = (void *)((unsigned int)pTil + 4); | |
572 | if ( (unsigned int)pTil == fifo_stat.qba + ( 4 * ( fifo_stat.qsz << 11 ) ) ) | |
573 | { | |
574 | /* reach the upper limit */ | |
575 | pTil = (void *)(fifo_stat.qba + ( 3 * (fifo_stat.qsz << 11) )); | |
576 | } | |
577 | store_runtime_reg( base, I2O_OFTPR, (unsigned int)pTil ); | |
578 | } | |
579 | } | |
580 | ||
581 | return stat; | |
582 | } | |
583 | ||
584 | /****************************************************** | |
585 | * function: I2OFIFOFree | |
586 | * | |
587 | * description: Free a used MFA back to free queue after | |
588 | * use. | |
589 | * return I2OSUCCESS if no error. | |
590 | * return I2OQUEFULL if inbound free queue | |
591 | * overflow | |
592 | * | |
593 | * note: PCI Master frees a MFA into device's outbound queue | |
594 | * (OFQPR) while local processor frees a MFA into its | |
595 | * inbound queue (IFHPR). | |
596 | *****************************************************/ | |
597 | I2OSTATUS I2OFIFOFree( LOCATION loc, | |
598 | unsigned int base, | |
599 | void *pMsg ) | |
600 | { | |
601 | void **pHdr, **pTil; | |
602 | I2OSTATUS stat = I2OSUCCESS; | |
603 | ||
604 | if ( fifo_stat.qba == 0xffffffff || pMsg == 0 ) | |
605 | { | |
606 | return I2OQUEINVALID; | |
607 | } | |
608 | ||
609 | if ( loc == REMOTE ) | |
610 | { | |
611 | /* pcsrbar is the base */ | |
612 | store_runtime_reg( base, I2O_OFQPR, (unsigned int)pMsg ); | |
613 | } | |
614 | else | |
615 | { | |
616 | /* eumbbar is the base */ | |
617 | pHdr = (void **)load_runtime_reg( base, I2O_IFHPR ); | |
8bde7f77 | 618 | pTil = (void **)load_runtime_reg( base, I2O_IFTPR ); |
327f7a02 WD |
619 | |
620 | /* store MFA */ | |
621 | *pHdr = pMsg; | |
622 | ||
623 | /* update IFHPR */ | |
624 | pHdr += 4; | |
625 | ||
626 | if ( (unsigned int)pHdr == fifo_stat.qba + ( fifo_stat.qsz << 11 ) ) | |
627 | { | |
628 | /* reach the upper limit */ | |
629 | pHdr = (void **)fifo_stat.qba; | |
630 | } | |
631 | ||
632 | /* check inbound free queue overflow */ | |
633 | if ( pHdr != pTil ) | |
634 | { | |
635 | store_runtime_reg( base, I2O_OPHPR, (unsigned int)pHdr); | |
8bde7f77 | 636 | } |
327f7a02 WD |
637 | else |
638 | { | |
639 | stat = I2OQUEFULL; | |
640 | } | |
641 | ||
642 | } | |
643 | ||
644 | return stat; | |
645 | ||
646 | } | |
647 | ||
648 | /********************************************* | |
649 | * function: I2OFIFOPost | |
650 | * | |
651 | * description: Post a msg into FIFO post queue | |
652 | * the value of msg must be the one | |
653 | * returned by I2OFIFOAlloc | |
654 | * | |
655 | * note: PCI Master posts a msg into device's inbound queue | |
656 | * (IFQPR) while local processor post a msg into device's | |
657 | * outbound queue (OPHPR) | |
658 | *********************************************/ | |
659 | I2OSTATUS I2OFIFOPost( LOCATION loc, | |
660 | unsigned int base, | |
661 | void *pMsg ) | |
662 | { | |
663 | void **pHdr, **pTil; | |
664 | I2OSTATUS stat = I2OSUCCESS; | |
665 | ||
666 | if ( fifo_stat.qba == 0xffffffff || pMsg == 0 ) | |
667 | { | |
668 | return I2OQUEINVALID; | |
669 | } | |
670 | ||
671 | if ( loc == REMOTE ) | |
672 | { | |
673 | /* pcsrbar is the base */ | |
674 | store_runtime_reg( base, I2O_IFQPR, (unsigned int)pMsg ); | |
675 | } | |
676 | else | |
677 | { | |
678 | /* eumbbar is the base */ | |
679 | pHdr = (void **)load_runtime_reg( base, I2O_OPHPR ); | |
8bde7f77 | 680 | pTil = (void **)load_runtime_reg( base, I2O_OPTPR ); |
327f7a02 WD |
681 | |
682 | /* store MFA */ | |
683 | *pHdr = pMsg; | |
684 | ||
685 | /* update IFHPR */ | |
686 | pHdr += 4; | |
687 | ||
688 | if ( (unsigned int)pHdr == fifo_stat.qba + 3 * ( fifo_stat.qsz << 11 ) ) | |
689 | { | |
690 | /* reach the upper limit */ | |
691 | pHdr = (void **)(fifo_stat.qba + 2 * ( fifo_stat.qsz << 11 ) ); | |
692 | } | |
693 | ||
694 | /* check post queue overflow */ | |
695 | if ( pHdr != pTil ) | |
696 | { | |
697 | store_runtime_reg( base, I2O_OPHPR, (unsigned int)pHdr); | |
8bde7f77 | 698 | } |
327f7a02 WD |
699 | else |
700 | { | |
701 | stat = I2OQUEFULL; | |
702 | } | |
703 | } | |
704 | ||
705 | return stat; | |
706 | } | |
707 | ||
708 | /************************************************ | |
709 | * function: I2OFIFOGet | |
710 | * | |
711 | * description: Read a msg from FIFO | |
712 | * This function should be called | |
713 | * only when there is a corresponding | |
714 | * msg interrupt. | |
715 | * | |
716 | * note: PCI Master reads a msg from device's outbound queue | |
717 | * (OFQPR) while local processor reads a msg from device's | |
718 | * inbound queue (IPTPR) | |
719 | ************************************************/ | |
720 | I2OSTATUS I2OFIFOGet( LOCATION loc, | |
721 | unsigned int base, | |
722 | void **pMsg ) | |
723 | { | |
724 | I2OSTATUS stat = I2OSUCCESS; | |
725 | void *pHdr, *pTil; | |
726 | ||
727 | if ( pMsg == 0 || *pMsg == 0 || fifo_stat.qba == 0xffffffff ) | |
728 | { | |
729 | /* not configured */ | |
730 | return I2OQUEINVALID; | |
731 | } | |
732 | ||
733 | if ( loc == REMOTE ) | |
734 | { | |
735 | /* pcsrbar is the base */ | |
736 | pTil = (void *)load_runtime_reg( base, I2O_OFQPR ); | |
8bde7f77 WD |
737 | if ( ( (unsigned int)pTil & 0xFFFFFFF ) == 0xFFFFFFFF ) |
738 | { | |
327f7a02 | 739 | stat = I2OQUEEMPTY; |
8bde7f77 | 740 | } |
327f7a02 | 741 | else |
8bde7f77 | 742 | { |
327f7a02 WD |
743 | *pMsg = pTil; |
744 | } | |
745 | } | |
746 | else | |
747 | { | |
748 | /* eumbbar is the base and read the outbound free tail ptr */ | |
749 | pHdr = (void *)load_runtime_reg( base, I2O_IPHPR ); /* queue head */ | |
750 | pTil = (void *)load_runtime_reg( base, I2O_IPTPR ); /* queue tail */ | |
751 | ||
752 | /* check underflow */ | |
753 | if ( pHdr == pTil ) | |
754 | { | |
755 | /* no free MFA */ | |
8bde7f77 | 756 | stat = I2OQUEEMPTY; |
327f7a02 WD |
757 | } |
758 | else | |
759 | { | |
760 | /* update OFTPR */ | |
761 | *pMsg = (void *)(*(unsigned char *)pTil); | |
762 | pTil = (void *)((unsigned int)pTil + 4); | |
763 | if ( (unsigned int)pTil == fifo_stat.qba + 2 * ( fifo_stat.qsz << 11 ) ) | |
764 | { | |
765 | /* reach the upper limit */ | |
766 | pTil = (void *)(fifo_stat.qba + 1 * (fifo_stat.qsz << 11) ); | |
767 | } | |
768 | ||
769 | store_runtime_reg( base, I2O_IPTPR, (unsigned int)pTil ); | |
770 | } | |
771 | } | |
772 | ||
773 | return stat; | |
774 | } | |
775 | ||
776 | /******************************************************** | |
777 | * function: I2OIOP | |
778 | * | |
779 | * description: Get the I2O PCI configuration identification | |
780 | * register. | |
781 | * | |
782 | * note: PCI master should pass pcsrbar while local processor | |
783 | * should pass eumbbar. | |
784 | *********************************************************/ | |
785 | I2OSTATUS I2OPCIConfigGet( LOCATION loc, | |
8bde7f77 WD |
786 | unsigned int base, |
787 | I2OIOP * val) | |
327f7a02 WD |
788 | { |
789 | unsigned int tmp; | |
790 | if ( val == 0 ) | |
791 | { | |
792 | return I2OINVALID; | |
793 | } | |
794 | tmp = load_runtime_reg( base, PCI_CFG_CLA ); | |
795 | val->base_class = ( tmp & 0xFF) << 16; | |
796 | tmp = load_runtime_reg( base, PCI_CFG_SCL ); | |
797 | val->sub_class= ( (tmp & 0xFF) << 8 ); | |
798 | tmp = load_runtime_reg( base, PCI_CFG_PIC ); | |
799 | val->prg_code = (tmp & 0xFF); | |
800 | return I2OSUCCESS; | |
801 | } | |
802 | ||
803 | /********************************************************* | |
804 | * function: I2OFIFOIntEnable | |
805 | * | |
806 | * description: Enable the circular post queue interrupt | |
807 | * | |
808 | * note: | |
809 | * PCI master enables outbound FIFO interrupt of device | |
810 | * pscrbar is the base | |
811 | * Device enables its inbound FIFO interrupt | |
812 | * eumbbar is the base | |
813 | *******************************************************/ | |
814 | void I2OFIFOIntEnable( LOCATION loc, unsigned int base ) | |
815 | { | |
816 | unsigned int reg, val; | |
817 | ||
818 | /* LOCATION - REMOTE : enable outbound message of device, pcsrbar as base | |
819 | * LOCAL : enable local inbound message, eumbbar as base | |
820 | */ | |
821 | reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); | |
822 | val = load_runtime_reg( base, reg ); | |
823 | ||
824 | val &= 0xffffffdf; /* clear the msg interrupt bits */ | |
825 | store_runtime_reg( base, reg, val ); | |
826 | ||
827 | } | |
828 | ||
829 | /**************************************************** | |
830 | * function: I2OFIFOIntDisable | |
831 | * | |
832 | * description: Disable the circular post queue interrupt | |
833 | * | |
834 | * note: | |
835 | * PCI master disables outbound FIFO interrupt of device | |
836 | * (pscrbar is the base) | |
837 | * Device disables its inbound FIFO interrupt | |
838 | * (eumbbar is the base) | |
839 | *****************************************************/ | |
840 | void I2OFIFOIntDisable( LOCATION loc, unsigned int base ) | |
841 | { | |
842 | ||
843 | /* LOCATION - REMOTE : disable outbound message interrupt of device, pcsrbar as base | |
844 | * LOCAL : disable local inbound message interrupt, eumbbar as base | |
845 | */ | |
846 | unsigned int reg = ( loc == REMOTE ? I2O_OMIMR : I2O_IMIMR ); | |
847 | unsigned int val = load_runtime_reg( base, reg ); | |
848 | ||
849 | val |= 0x00000020; /* masked out the msg interrupt bits */ | |
850 | store_runtime_reg( base, reg, val ); | |
851 | ||
852 | } | |
853 | ||
854 | /********************************************************* | |
855 | * function: I2OFIFOOverflowIntEnable | |
856 | * | |
857 | * description: Enable the circular queue overflow interrupt | |
858 | * | |
859 | * note: | |
860 | * Device enables its inbound FIFO post overflow interrupt | |
861 | * and outbound free overflow interrupt. | |
862 | * eumbbar is the base | |
863 | *******************************************************/ | |
864 | void I2OFIFOOverflowIntEnable( unsigned int eumbbar ) | |
865 | { | |
866 | unsigned int val = load_runtime_reg( eumbbar, I2O_IMIMR ); | |
867 | ||
868 | val &= 0xfffffe7f; /* clear the two overflow interrupt bits */ | |
869 | store_runtime_reg( eumbbar, I2O_IMIMR, val ); | |
870 | ||
871 | } | |
872 | ||
873 | /**************************************************** | |
874 | * function: I2OFIFOOverflowIntDisable | |
875 | * | |
876 | * description: Disable the circular queue overflow interrupt | |
877 | * | |
878 | * note: | |
879 | * Device disables its inbound post FIFO overflow interrupt | |
880 | * and outbound free FIFO overflow interrupt | |
881 | * (eumbbar is the base) | |
882 | *****************************************************/ | |
883 | void I2OFIFOOverflowIntDisable( unsigned int eumbbar ) | |
884 | { | |
885 | ||
886 | unsigned int val = load_runtime_reg( eumbbar, I2O_IMIMR ); | |
887 | ||
888 | val |= 0x00000180; /* masked out the msg overflow interrupt bits */ | |
889 | store_runtime_reg( eumbbar, I2O_IMIMR, val ); | |
890 | } |