|
|
1.1 root 1: /* $Id: sun-si.c,v 1.1 2005/02/17 12:19:17 fredette Exp $ */
2:
3: /* machine/sun/sun-si.c - Sun ncr5380-based SCSI implementation: */
4:
5: /*
6: * Copyright (c) 2004 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include <tme/common.h>
37: _TME_RCSID("$Id: sun-si.c,v 1.1 2005/02/17 12:19:17 fredette Exp $");
38:
39: /* includes: */
40: #include <tme/element.h>
41: #undef TME_BUS_VERSION
42: #define TME_BUS_VERSION TME_X_VERSION(0, 0)
43: #include <tme/generic/bus.h>
44:
45: /* macros: */
46:
47: /* controller types: */
48: #define TME_SUN_SI_TYPE_NULL (0)
49: #define TME_SUN_SI_TYPE_VME (1)
50: #define TME_SUN_SI_TYPE_ONBOARD (2)
51: #define TME_SUN_SI_TYPE_3E (3)
52: #define TME_SUN_SI_TYPE_COBRA (4)
53:
54: /* register offsets and sizes: */
55:
56: /* all controllers: */
57: #define TME_SUN_SI_REG_NCR5380 (0)
58: #define TME_SUN_SI_SIZ_NCR5380 (8)
59:
60: /* all controllers except onboard, and the Sun 3/E limits these to 16 bits: */
61: #define TME_SUN_SI_REG_DMA_ADDRESS (8)
62: #define TME_SUN_SI_REG_DMA_COUNT (12)
63:
64: /* Cobra controller only: */
65: #define TME_SUN_SI_REG_COBRA_FIFO_COUNT (16)
66: #define TME_SUN_SI_REG_COBRA_CSR (20)
67: #define TME_SIN_SI_REG_COBRA_BPR (24)
68:
69: /* onboard controller only: */
70: #define TME_SUN_SI_REG_ONBOARD_UDC_DATA (16)
71: #define TME_SUN_SI_REG_ONBOARD_UDC_ADDRESS (18)
72: #define TME_SUN_SI_REG_ONBOARD_FIFO_DATA (20)
73:
74: /* onboard and VME controllers only: */
75: #define TME_SUN_SI_REG_FIFO_COUNT_L (22)
76:
77: /* all controllers except for the Cobra: */
78: #define TME_SUN_SI_REG_CSR (24)
79:
80: /* 3/E controller only: */
81: #define TME_SUN_SI_REG_3E_IVEC (27)
82:
83: /* VME controller only: */
84: #define TME_SUN_SI_REG_VME_BPR_H (26)
85: #define TME_SUN_SI_REG_VME_BPR_L (28)
86: #define TME_SUN_SI_REG_VME_IV_AM (30)
87: #define TME_SUN_SI_REG_VME_FIFO_COUNT_H (32)
88:
89: #define TME_SUN_SI_SIZ_REGS (34)
90:
91: /* the 3/E includes a 64KB DMA buffer: */
92: #define TME_SUN_SI_3E_SIZ_DMA (0x10000)
93:
94: /* the bits in the Control/Status Register: */
95: #define TME_SUN_SI_CSR_ONBOARD_DMA_ACTIVE TME_BIT(15) /* onboard controller only */
96: #define TME_SUN_SI_CSR_DMA_CONFLICT TME_BIT(14) /* all controllers except for the 3/E */
97: #define TME_SUN_SI_CSR_DMA_BUS_ERROR TME_BIT(13) /* all controllers except for the 3/E */
98: #define TME_SUN_SI_CSR_VME_MODIFIED TME_BIT(12) /* VME controller only */
99: #define TME_SUN_SI_CSR_FIFO_FULL TME_BIT(11) /* all controllers except for the 3/E (and Cobra?) */
100: #define TME_SUN_SI_CSR_FIFO_EMPTY TME_BIT(10) /* all controllers except for the 3/E (and Cobra?) */
101: #define TME_SUN_SI_CSR_INT_NCR5380 TME_BIT(9) /* all controllers */
102: #define TME_SUN_SI_CSR_INT_DMA TME_BIT(8) /* all controllers except for the 3/E (and Cobra?) */
103: #define TME_SUN_SI_CSR_VME_LOB_MASK (0x00c0) /* VME controller only */
104: #define TME_SUN_SI_CSR_VME_BPCON TME_BIT(5) /* VME controller only */
105: #define TME_SUN_SI_CSR_DMA_ENABLE TME_BIT(4) /* all controllers except for onboard */
106: #define TME_SUN_SI_CSR_DMA_SEND TME_BIT(3) /* all controllers */
107: #define TME_SUN_SI_CSR_INT_ENABLE TME_BIT(2) /* all controllers */
108: #define TME_SUN_SI_CSR_RESET_FIFO TME_BIT(1) /* all controllers except for the 3/E */
109: #define TME_SUN_SI_CSR_3E_VCC TME_BIT(1) /* 3/E controller only */
110: #define TME_SUN_SI_CSR_RESET_CONTROLLER TME_BIT(0) /* all controllers */
111:
112: /* the read-only bits in the Control/Status Register: */
113: /* all controllers except for the 3/E: */
114: #define TME_SUN_SI_CSR_READONLY (~(TME_SUN_SI_CSR_VME_BPCON \
115: | TME_SUN_SI_CSR_DMA_ENABLE \
116: | TME_SUN_SI_CSR_DMA_SEND \
117: | TME_SUN_SI_CSR_INT_ENABLE \
118: | TME_SUN_SI_CSR_RESET_FIFO \
119: | TME_SUN_SI_CSR_RESET_CONTROLLER))
120: /* 3/E controller only: */
121: #define TME_SUN_SI_CSR_3E_READONLY (TME_SUN_SI_CSR_READONLY | TME_SUN_SI_CSR_3E_VCC)
122:
123: /* these get and put a 32-bit register: */
124: #define TME_SUN_SI_REG32_GET(sun_si, reg) \
125: tme_betoh_u32(*((tme_uint32_t *) &(sun_si)->tme_sun_si_regs[(reg)]))
126: #define TME_SUN_SI_REG32_PUT(sun_si, reg, val) \
127: (*((tme_uint32_t *) &(sun_si)->tme_sun_si_regs[(reg)]) = tme_htobe_u32(val))
128:
129: /* these get and put a 16-bit register: */
130: #define TME_SUN_SI_REG16_GET(sun_si, reg) \
131: tme_betoh_u16(*((tme_uint16_t *) &(sun_si)->tme_sun_si_regs[(reg)]))
132: #define TME_SUN_SI_REG16_PUT(sun_si, reg, val) \
133: (*((tme_uint16_t *) &(sun_si)->tme_sun_si_regs[(reg)]) = tme_htobe_u16(val))
134:
135: /* these get and put the CSR register: */
136: #define TME_SUN_SI_CSR_GET(sun_si) \
137: ((sun_si)->tme_sun_si_type == TME_SUN_SI_TYPE_COBRA \
138: ? TME_SUN_SI_REG32_GET(sun_si, TME_SUN_SI_REG_COBRA_CSR) \
139: : TME_SUN_SI_REG16_GET(sun_si, TME_SUN_SI_REG_CSR))
140: #define TME_SUN_SI_CSR_PUT(sun_si, csr) \
141: ((sun_si)->tme_sun_si_type == TME_SUN_SI_TYPE_COBRA \
142: ? TME_SUN_SI_REG32_PUT(sun_si, TME_SUN_SI_REG_COBRA_CSR, csr)\
143: : TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_CSR, csr))
144:
145: /* the callout flags: */
146: #define TME_SUN_SI_CALLOUT_CHECK (0)
147: #define TME_SUN_SI_CALLOUT_RUNNING TME_BIT(0)
148: #define TME_SUN_SI_CALLOUTS_MASK (-2)
149: #define TME_SUN_SI_CALLOUT_SIGNALS TME_BIT(1)
150: #define TME_SUN_SI_CALLOUT_INT TME_BIT(2)
151:
152: #if 1
153: #define TME_SUN_SI_DEBUG
154: #endif
155:
156: /* structures: */
157:
158: /* the controller: */
159: struct tme_sun_si {
160:
161: /* backpointer to our element: */
162: struct tme_element *tme_sun_si_element;
163:
164: /* the mutex protecting the card: */
165: tme_mutex_t tme_sun_si_mutex;
166:
167: /* the rwlock protecting the card: */
168: tme_rwlock_t tme_sun_si_rwlock;
169:
170: /* the bus connection for the card's registers: */
171: struct tme_bus_connection *tme_sun_si_conn_regs;
172:
173: /* the bus connection for the card's memory: */
174: struct tme_bus_connection *tme_sun_si_conn_memory;
175:
176: /* the bus connection for the card's ncr5380: */
177: struct tme_bus_connection *tme_sun_si_conn_ncr5380;
178:
179: /* the type of the si: */
180: tme_uint32_t tme_sun_si_type;
181:
182: /* the callout flags: */
183: int tme_sun_si_callout_flags;
184:
185: /* if our interrupt line is currently asserted: */
186: int tme_sun_si_last_int_asserted;
187:
188: /* it's easiest to just model the board registers as a chunk of memory: */
189: tme_uint8_t tme_sun_si_regs[TME_SUN_SI_SIZ_REGS];
190:
191: /* any outstanding NCR 5380 TLB entry: */
192: struct tme_bus_tlb *tme_sun_si_ncr5380_tlb;
193:
194: /* the 3/E DMA buffer: */
195: tme_uint8_t *tme_sun_si_3e_dma;
196:
197: /* the CSR last called out to the NCR 5380: */
198: tme_uint32_t tme_sun_si_csr_ncr5380;
199: };
200:
201: /* a sun_si internal bus connection: */
202: struct tme_sun_si_connection {
203:
204: /* the external bus connection: */
205: struct tme_bus_connection tme_sun_si_connection;
206:
207: /* this is nonzero if a TME_CONNECTION_BUS_GENERIC chip connection
208: is for the registers: */
209: unsigned int tme_sun_si_connection_regs;
210: };
211:
212: #ifdef TME_SUN_SI_DEBUG
213: void
214: _tme_sun_si_reg_put(struct tme_sun_si *sun_si,
215: int reg,
216: tme_uint32_t val_new,
217: unsigned int val_size)
218: {
219: const char *reg_name;
220: tme_uint32_t val_old;
221:
222: if (val_size == sizeof(tme_uint32_t)) {
223: val_old = TME_SUN_SI_REG32_GET(sun_si, reg);
224: TME_SUN_SI_REG32_PUT(sun_si, reg, val_new);
225: }
226: else {
227: assert (val_size == sizeof(tme_uint16_t));
228: val_old = TME_SUN_SI_REG16_GET(sun_si, reg);
229: TME_SUN_SI_REG16_PUT(sun_si, reg, val_new);
230: val_new &= 0xffff;
231: }
232:
233: if (val_new == val_old) {
234: return;
235: }
236:
237: /* try to get the name of this register: */
238: reg_name = NULL;
239: #define _TME_SUN_SI_REG_IS(_reg, type) (reg_name == NULL && reg == (_reg) && val_size == sizeof(type))
240: if (sun_si->tme_sun_si_type != TME_SUN_SI_TYPE_ONBOARD
241: && _TME_SUN_SI_REG_IS(TME_SUN_SI_REG_DMA_ADDRESS, tme_uint32_t)) {
242: reg_name = "dma_address";
243: }
244: if (sun_si->tme_sun_si_type != TME_SUN_SI_TYPE_ONBOARD
245: && _TME_SUN_SI_REG_IS(TME_SUN_SI_REG_DMA_COUNT, tme_uint32_t)) {
246: reg_name = "dma_count";
247: }
248: if ((sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_ONBOARD
249: || sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_VME)
250: && _TME_SUN_SI_REG_IS(TME_SUN_SI_REG_FIFO_COUNT_L, tme_uint16_t)) {
251: reg_name = "fifo_count_l";
252: }
253: if (sun_si->tme_sun_si_type != TME_SUN_SI_TYPE_COBRA
254: && _TME_SUN_SI_REG_IS(TME_SUN_SI_REG_CSR, tme_uint16_t)) {
255: reg_name = "CSR";
256: }
257: if (sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_VME) {
258: if (_TME_SUN_SI_REG_IS(TME_SUN_SI_REG_VME_BPR_H, tme_uint16_t)) {
259: reg_name = "bpr_h";
260: }
261: if (_TME_SUN_SI_REG_IS(TME_SUN_SI_REG_VME_BPR_L, tme_uint16_t)) {
262: reg_name = "bpr_l";
263: }
264: if (_TME_SUN_SI_REG_IS(TME_SUN_SI_REG_VME_FIFO_COUNT_H, tme_uint16_t)) {
265: reg_name = "fifo_count_h";
266: }
267: }
268: #undef _TME_SUN_SI_REG_IS
269: if (reg_name == NULL) {
270: reg_name = "???";
271: }
272: tme_log(&sun_si->tme_sun_si_element->tme_element_log_handle,
273: 100, TME_OK,
274: (&sun_si->tme_sun_si_element->tme_element_log_handle,
275: "%s old 0x%04x new 0x%04x",
276: reg_name,
277: val_old,
278: val_new));
279: }
280: #undef TME_SUN_SI_REG16_PUT
281: #define TME_SUN_SI_REG16_PUT(sun_si, reg, val) _tme_sun_si_reg_put((sun_si), (reg), (val), sizeof(tme_uint16_t))
282: #undef TME_SUN_SI_REG32_PUT
283: #define TME_SUN_SI_REG32_PUT(sun_si, reg, val) _tme_sun_si_reg_put((sun_si), (reg), (val), sizeof(tme_uint32_t))
284: #endif /* TME_SUN_SI_DEBUG */
285:
286: /* the sun_si callout function. it must be called with the mutex locked: */
287: static void
288: _tme_sun_si_callout(struct tme_sun_si *sun_si, int new_callouts)
289: {
290: struct tme_bus_connection *conn_ncr5380;
291: struct tme_bus_connection *conn_bus;
292: tme_uint32_t csr, csr_diff;
293: unsigned int signal, level;
294: int callouts, later_callouts;
295: int rc;
296: int int_asserted;
297:
298: /* add in any new callouts: */
299: sun_si->tme_sun_si_callout_flags |= new_callouts;
300:
301: /* if this function is already running in another thread, simply
302: return now. the other thread will do our work: */
303: if (sun_si->tme_sun_si_callout_flags & TME_SUN_SI_CALLOUT_RUNNING) {
304: return;
305: }
306:
307: /* callouts are now running: */
308: sun_si->tme_sun_si_callout_flags |= TME_SUN_SI_CALLOUT_RUNNING;
309:
310: /* assume that we won't need any later callouts: */
311: later_callouts = 0;
312:
313: /* loop while callouts are needed: */
314: for (; (callouts = sun_si->tme_sun_si_callout_flags) & TME_SUN_SI_CALLOUTS_MASK; ) {
315:
316: /* clear the needed callouts: */
317: sun_si->tme_sun_si_callout_flags = callouts & ~TME_SUN_SI_CALLOUTS_MASK;
318: callouts &= TME_SUN_SI_CALLOUTS_MASK;
319:
320: /* get the current CSR value: */
321: csr = TME_SUN_SI_CSR_GET(sun_si);
322:
323: /* get the next changed CSR bit to convert to a bus signal to the
324: NCR 5380: */
325: csr_diff = ((csr
326: ^ sun_si->tme_sun_si_csr_ncr5380)
327: & (TME_SUN_SI_CSR_RESET_CONTROLLER
328: | ((sun_si->tme_sun_si_type != TME_SUN_SI_TYPE_ONBOARD)
329: ? TME_SUN_SI_CSR_DMA_ENABLE
330: : 0)));
331: csr_diff = (csr_diff ^ (csr_diff - 1)) & csr_diff;
332:
333: /* if there is a changed CSR bit to call out: */
334: if (csr_diff != 0) {
335:
336: /* assume that if the signal's bit is set in the CSR, it will
337: be asserted: */
338: level = (csr & csr_diff) != 0;
339:
340: /* dispatch on the CSR bit: */
341: switch (csr_diff) {
342: default:
343: assert (FALSE);
344: /* FALLTHROUGH */
345:
346: case TME_SUN_SI_CSR_RESET_CONTROLLER:
347: signal = TME_BUS_SIGNAL_RESET;
348: level = !level;
349: break;
350:
351: case TME_SUN_SI_CSR_DMA_ENABLE:
352: signal = TME_BUS_SIGNAL_DACK;
353: break;
354: }
355:
356: /* create a real signal level value: */
357: level = (level
358: ? TME_BUS_SIGNAL_LEVEL_ASSERTED
359: : TME_BUS_SIGNAL_LEVEL_NEGATED);
360:
361: /* get this card's ncr5380 connection: */
362: conn_ncr5380 = sun_si->tme_sun_si_conn_ncr5380;
363:
364: /* unlock the mutex: */
365: tme_mutex_unlock(&sun_si->tme_sun_si_mutex);
366:
367: /* do the callout: */
368: rc = (conn_ncr5380 != NULL
369: ? ((*conn_ncr5380->tme_bus_signal)
370: (conn_ncr5380,
371: signal | level))
372: : TME_OK);
373:
374: /* lock the mutex: */
375: tme_mutex_lock(&sun_si->tme_sun_si_mutex);
376:
377: /* if the callout was unsuccessful, remember that at some later
378: time this callout should be attempted again: */
379: if (rc != TME_OK) {
380: later_callouts |= TME_SUN_SI_CALLOUT_SIGNALS;
381: }
382:
383: /* otherwise, the callout was successful: */
384: else {
385:
386: /* update the ncr5380 image of the CSR: */
387: sun_si->tme_sun_si_csr_ncr5380 =
388: ((sun_si->tme_sun_si_csr_ncr5380 & ~csr_diff)
389: | (csr & csr_diff));
390:
391: /* there may be more signals to call out, so attempt this
392: callout again now: */
393: sun_si->tme_sun_si_callout_flags |= TME_SUN_SI_CALLOUT_SIGNALS;
394: }
395: }
396:
397: /* get the current CSR value: */
398: csr = TME_SUN_SI_CSR_GET(sun_si);
399:
400: /* see if the interrupt signal should be asserted or negated. on
401: all controllers except for onboard, DMA must be enabled for the
402: interrupt signal to reach the CPU: */
403: int_asserted = ((csr & TME_SUN_SI_CSR_INT_ENABLE)
404: && (sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_ONBOARD
405: || (csr & TME_SUN_SI_CSR_DMA_ENABLE))
406: && (csr & (TME_SUN_SI_CSR_DMA_CONFLICT
407: | TME_SUN_SI_CSR_DMA_BUS_ERROR
408: | TME_SUN_SI_CSR_INT_NCR5380
409: | TME_SUN_SI_CSR_INT_DMA)));
410:
411: /* if the interrupt signal doesn't already have the right state: */
412: if (!int_asserted != !sun_si->tme_sun_si_last_int_asserted) {
413:
414: /* get our bus connection: */
415: conn_bus = sun_si->tme_sun_si_conn_regs;
416:
417: /* unlock our mutex: */
418: tme_mutex_unlock(&sun_si->tme_sun_si_mutex);
419:
420: /* call out the bus interrupt signal edge: */
421: rc = (conn_bus != NULL
422: ? ((*conn_bus->tme_bus_signal)
423: (conn_bus,
424: TME_BUS_SIGNAL_INT_UNSPEC
425: | (int_asserted
426: ? TME_BUS_SIGNAL_LEVEL_ASSERTED
427: : TME_BUS_SIGNAL_LEVEL_NEGATED)))
428: : TME_OK);
429:
430: /* lock our mutex: */
431: tme_mutex_lock(&sun_si->tme_sun_si_mutex);
432:
433: /* if this callout was successful, note the new state of the
434: interrupt signal: */
435: if (rc == TME_OK) {
436: sun_si->tme_sun_si_last_int_asserted = int_asserted;
437: }
438:
439: /* otherwise, remember that at some later time this callout
440: should be attempted again: */
441: else {
442: later_callouts |= TME_SUN_SI_CALLOUT_INT;
443: }
444: }
445: }
446:
447: /* put in any later callouts, and clear that callouts are running: */
448: sun_si->tme_sun_si_callout_flags = later_callouts;
449: }
450:
451: /* the 3/E DMA bus cycle handler: */
452: static int
453: _tme_sun_si_bus_cycle_3e_dma(void *_sun_si, struct tme_bus_cycle *cycle)
454: {
455: struct tme_sun_si *sun_si;
456:
457: /* recover our data structure: */
458: sun_si = (struct tme_sun_si *) _sun_si;
459:
460: /* run the cycle: */
461: tme_bus_cycle_xfer_memory(cycle,
462: sun_si->tme_sun_si_3e_dma,
463: TME_SUN_SI_3E_SIZ_DMA - 1);
464:
465: /* no faults: */
466: return (TME_OK);
467: }
468:
469: /* the sun_si bus cycle handler for the board registers: */
470: static int
471: _tme_sun_si_bus_cycle_regs(void *_sun_si,
472: struct tme_bus_cycle *cycle_init)
473: {
474: struct tme_sun_si *sun_si;
475: tme_uint32_t csr_old, csr_new, csr_diff, csr_mask;
476: tme_bus_addr_t address;
477: tme_uint8_t cycle_size;
478: tme_uint32_t csr;
479: tme_uint32_t dma_count;
480: int new_callouts;
481:
482: /* get the address and cycle size: */
483: address = cycle_init->tme_bus_cycle_address;
484: cycle_size = cycle_init->tme_bus_cycle_size;
485:
486: /* it appears that si hardware doesn't respond to a byte access
487: to its DMA count register. at least, SunOS' sc probe routine
488: seems to rely on this to distinguish an si from an sc: */
489: if (address == TME_SUN_SI_REG_DMA_COUNT
490: && cycle_size == sizeof(tme_uint8_t)) {
491: return (EINVAL);
492: }
493:
494: /* recover our data structure: */
495: sun_si = (struct tme_sun_si *) _sun_si;
496:
497: /* assume we won't need any new callouts: */
498: new_callouts = 0;
499:
500: /* lock the mutex: */
501: tme_mutex_lock(&sun_si->tme_sun_si_mutex);
502:
503: /* get the previous CSR value: */
504: csr_old = TME_SUN_SI_CSR_GET(sun_si);
505:
506: /* run the cycle: */
507: tme_bus_cycle_xfer_memory(cycle_init,
508: sun_si->tme_sun_si_regs,
509: TME_SUN_SI_SIZ_REGS - 1);
510:
511: #define _TME_SUN_SI_REG_IS(reg, type) TME_RANGES_OVERLAP(address, address + cycle_size - 1, (reg), (reg) + sizeof(type) - 1)
512:
513: /* if this was a write: */
514: if (cycle_init->tme_bus_cycle_type
515: == TME_BUS_CYCLE_WRITE) {
516:
517: /* if this is a VME controller: */
518: if (sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_VME) {
519:
520: /* if this was a write to the DMA count register: */
521: if (_TME_SUN_SI_REG_IS(TME_SUN_SI_REG_DMA_COUNT, tme_uint32_t)) {
522:
523: /* get the DMA count register: */
524: dma_count = TME_SUN_SI_REG32_GET(sun_si, TME_SUN_SI_REG_DMA_COUNT);
525:
526: /* copy the DMA count register to the FIFO count register: */
527: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_VME_FIFO_COUNT_H, (dma_count >> 16));
528: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_FIFO_COUNT_L, (dma_count & 0xffff));
529: }
530: }
531:
532: /* get the current CSR value, and put back any bits that
533: software can't change: */
534: csr_mask = (sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_3E
535: ? TME_SUN_SI_CSR_3E_READONLY
536: : TME_SUN_SI_CSR_READONLY);
537: csr_new = ((TME_SUN_SI_CSR_GET(sun_si)
538: & ~csr_mask)
539: | (csr_old
540: & csr_mask));
541:
542: /* get the sets of CSR bits that have changed: */
543: csr_diff = (csr_old ^ csr_new);
544:
545: /* if the FIFO is being reset: */
546: if (sun_si->tme_sun_si_type != TME_SUN_SI_TYPE_3E
547: && (csr_diff & TME_SUN_SI_CSR_RESET_FIFO)
548: && !(csr_new & TME_SUN_SI_CSR_RESET_FIFO)) {
549:
550: /* reset the FIFOs: */
551: TME_SUN_SI_REG32_PUT(sun_si, TME_SUN_SI_REG_DMA_ADDRESS, 0);
552: TME_SUN_SI_REG32_PUT(sun_si, TME_SUN_SI_REG_DMA_COUNT, 0);
553: switch (sun_si->tme_sun_si_type) {
554: default:
555: assert(FALSE);
556: /* FALLTHROUGH */
557: case TME_SUN_SI_TYPE_ONBOARD:
558: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_ONBOARD_FIFO_DATA, 0);
559: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_FIFO_COUNT_L, 0);
560: break;
561: case TME_SUN_SI_TYPE_VME:
562: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_FIFO_COUNT_L, 0);
563: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_VME_FIFO_COUNT_H, 0);
564: csr &= ~TME_SUN_SI_CSR_VME_LOB_MASK;
565: break;
566: case TME_SUN_SI_TYPE_COBRA:
567: abort();
568: break;
569: }
570: }
571:
572: /* if the CSR has changed at all: */
573: if (csr_new != csr_old) {
574:
575: /* put back the new CSR: */
576: tme_log(&sun_si->tme_sun_si_element->tme_element_log_handle,
577: 100, TME_OK,
578: (&sun_si->tme_sun_si_element->tme_element_log_handle,
579: "CSR now 0x%04x",
580: csr_new));
581: TME_SUN_SI_CSR_PUT(sun_si, csr_new);
582:
583: /* assume that we need to call out changes to bus signals and
584: our interrupt: */
585: new_callouts |= TME_SUN_SI_CALLOUT_INT | TME_SUN_SI_CALLOUT_SIGNALS;
586: }
587: }
588:
589: /* make any new callouts: */
590: _tme_sun_si_callout(sun_si, new_callouts);
591:
592: /* unlock the mutex: */
593: tme_mutex_unlock(&sun_si->tme_sun_si_mutex);
594:
595: /* no faults: */
596: return (TME_OK);
597: }
598:
599: /* the sun_si TLB filler for the board registers (and, on the 3/E, for
600: the board memory on the VME bus): */
601: static int
602: _tme_sun_si_tlb_fill_regs(struct tme_bus_connection *conn_bus,
603: struct tme_bus_tlb *tlb,
604: tme_bus_addr_t address, unsigned int cycles)
605: {
606: struct tme_sun_si *sun_si;
607: struct tme_bus_connection *conn_ncr5380;
608: tme_bus_addr_t address_regs;
609: struct tme_bus_tlb tlb_mapping;
610: int rc;
611:
612: /* recover our data structures: */
613: sun_si = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
614:
615: /* assume that the registers start at address zero: */
616: address_regs = 0;
617:
618: /* dispatch on the controller type: */
619: switch (sun_si->tme_sun_si_type) {
620:
621: case TME_SUN_SI_TYPE_3E:
622:
623: /* the board registers follow the DMA buffer: */
624: address_regs = TME_SUN_SI_3E_SIZ_DMA;
625:
626: /* if this address is in the DMA buffer: */
627: if (address < TME_SUN_SI_3E_SIZ_DMA) {
628:
629: /* initialize the TLB entry: */
630: tme_bus_tlb_initialize(tlb);
631:
632: /* this TLB entry covers this range: */
633: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, 0);
634: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_SUN_SI_3E_SIZ_DMA - 1);
635:
636: /* this TLB entry allows fast reading and writing: */
637: tlb->tme_bus_tlb_emulator_off_read = sun_si->tme_sun_si_3e_dma;
638: tlb->tme_bus_tlb_emulator_off_write = sun_si->tme_sun_si_3e_dma;
639:
640: /* allow reading and writing: */
641: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
642:
643: /* our bus cycle handler: */
644: tlb->tme_bus_tlb_cycle_private = sun_si;
645: tlb->tme_bus_tlb_cycle = _tme_sun_si_bus_cycle_3e_dma;
646:
647: return (TME_OK);
648: }
649: break;
650:
651: default:
652: break;
653: }
654:
655: /* offset the address: */
656: address -= address_regs;
657:
658: /* the address must be within range: */
659: assert(address < TME_SUN_SI_SIZ_REGS);
660:
661: /* if this address is in the NCR 5380 registers: */
662: if (address < TME_SUN_SI_SIZ_NCR5380) {
663:
664: /* get the NCR 5380 connection: */
665: conn_ncr5380 = sun_si->tme_sun_si_conn_ncr5380;
666:
667: /* call the NCR 5380 TLB fill function: */
668: rc = (conn_ncr5380 != NULL
669: ? (*conn_ncr5380->tme_bus_tlb_fill)(conn_ncr5380, tlb,
670: address, cycles)
671: : EINVAL);
672:
673: /* if that succeeded: */
674: if (rc == TME_OK) {
675:
676: /* create the mapping TLB entry: */
677: TME_ATOMIC_WRITE(tme_bus_addr_t,
678: tlb_mapping.tme_bus_tlb_addr_first,
679: (address_regs
680: + TME_SUN_SI_REG_NCR5380));
681: TME_ATOMIC_WRITE(tme_bus_addr_t,
682: tlb_mapping.tme_bus_tlb_addr_last,
683: (address_regs
684: + TME_SUN_SI_REG_NCR5380
685: + TME_SUN_SI_SIZ_NCR5380
686: - 1));
687: tlb_mapping.tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
688:
689: /* map the filled TLB entry: */
690: tme_bus_tlb_map(tlb, 0, &tlb_mapping, address_regs + TME_SUN_SI_REG_NCR5380);
691: }
692:
693: return (rc);
694: }
695:
696: /* initialize the TLB entry: */
697: tme_bus_tlb_initialize(tlb);
698:
699: /* this TLB entry covers this range: */
700: TME_ATOMIC_WRITE(tme_bus_addr_t,
701: tlb->tme_bus_tlb_addr_first,
702: (address_regs
703: + TME_SUN_SI_SIZ_NCR5380));
704: TME_ATOMIC_WRITE(tme_bus_addr_t,
705: tlb->tme_bus_tlb_addr_last,
706: (address_regs
707: + TME_SUN_SI_SIZ_REGS
708: - 1));
709:
710: /* our controller registers don't have read side-effects, so they
711: support fast reading: */
712: tlb->tme_bus_tlb_emulator_off_read = sun_si->tme_sun_si_regs - address_regs;
713:
714: /* allow reading and writing: */
715: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
716:
717: /* our bus cycle handler: */
718: tlb->tme_bus_tlb_cycle_private = sun_si;
719: tlb->tme_bus_tlb_cycle = _tme_sun_si_bus_cycle_regs;
720:
721: return (TME_OK);
722: }
723:
724: /* the interrupt acknowledge function for the VME and 3/E types: */
725: static int
726: _tme_sun_si_intack(struct tme_bus_connection *conn_bus, unsigned int signal, int *_vector)
727: {
728: struct tme_sun_si *sun_si;
729: int vector;
730:
731: /* recover our data structure: */
732: sun_si = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
733:
734: /* dispatch on the controller type: */
735: switch (sun_si->tme_sun_si_type) {
736: default:
737: assert (FALSE);
738: /* FALLTHROUGH */
739:
740: case TME_SUN_SI_TYPE_3E:
741: vector = sun_si->tme_sun_si_regs[TME_SUN_SI_REG_3E_IVEC];
742: break;
743:
744: case TME_SUN_SI_TYPE_VME:
745: vector = TME_SUN_SI_REG16_GET(sun_si, TME_SUN_SI_REG_VME_IV_AM) & 0xff;
746: break;
747: }
748:
749: /* return the interrupt vector: */
750: *_vector = vector;
751: return (TME_OK);
752: }
753:
754: /* the sun_si bus signal handler for the NCR 5380: */
755: static int
756: _tme_sun_si_bus_signal(struct tme_bus_connection *conn_bus,
757: unsigned int signal)
758: {
759: struct tme_sun_si *sun_si;
760: tme_uint32_t csr;
761:
762: /* this must be the unspecified interrupt signal: */
763: assert (TME_BUS_SIGNAL_WHICH(signal) == TME_BUS_SIGNAL_INT_UNSPEC);
764:
765: /* recover our data structures: */
766: sun_si = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
767:
768: /* lock our mutex: */
769: tme_mutex_lock(&sun_si->tme_sun_si_mutex);
770:
771: /* update the CSR value: */
772: csr = TME_SUN_SI_CSR_GET(sun_si);
773: csr = ((csr
774: & ~TME_SUN_SI_CSR_INT_NCR5380)
775: | (((signal & TME_BUS_SIGNAL_LEVEL_MASK)
776: == TME_BUS_SIGNAL_LEVEL_ASSERTED)
777: ? TME_SUN_SI_CSR_INT_NCR5380
778: : 0));
779: TME_SUN_SI_CSR_PUT(sun_si, csr);
780:
781: /* call out an interrupt change: */
782: _tme_sun_si_callout(sun_si, TME_SUN_SI_CALLOUT_INT);
783:
784: /* unlock our mutex: */
785: tme_mutex_unlock(&sun_si->tme_sun_si_mutex);
786:
787: return (TME_OK);
788: }
789:
790: /* the sun_si bus fault handler for the NCR 5380 DMA: */
791: static int
792: _tme_sun_si_bus_fault_handler(void *_sun_si,
793: struct tme_bus_tlb *tlb,
794: struct tme_bus_cycle *cycle,
795: int rc)
796: {
797: struct tme_sun_si *sun_si;
798:
799: /* recover our data structure: */
800: sun_si = (struct tme_sun_si *) _sun_si;
801:
802: /* lock our mutex: */
803: tme_mutex_lock(&sun_si->tme_sun_si_mutex);
804:
805: /* set a DMA bus error and call out an interrupt change: */
806: TME_SUN_SI_CSR_PUT(sun_si, TME_SUN_SI_CSR_GET(sun_si) | TME_SUN_SI_CSR_DMA_BUS_ERROR);
807: _tme_sun_si_callout(sun_si, TME_SUN_SI_CALLOUT_INT);
808:
809: /* unlock our mutex: */
810: tme_mutex_unlock(&sun_si->tme_sun_si_mutex);
811:
812: return (rc);
813: }
814:
815: /* the sun_si TLB filler for the NCR 5380 DMA: */
816: static int
817: _tme_sun_si_tlb_fill(struct tme_bus_connection *conn_bus,
818: struct tme_bus_tlb *tlb,
819: tme_bus_addr_t ncr5380_address,
820: unsigned int cycles)
821: {
822: struct tme_sun_si *sun_si;
823: tme_uint32_t csr;
824: tme_bus_addr_t dma_address;
825: tme_uint32_t dma_count;
826: tme_uint32_t bpr;
827: unsigned int bpr_count;
828: #if defined(TME_SUN_SI_STRICT_VME)
829: unsigned int bpr_i;
830: #endif /* defined(TME_SUN_SI_STRICT_VME) */
831: struct tme_bus_tlb tlb_mapping;
832: int rc;
833:
834: /* recover our data structures: */
835: sun_si = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
836:
837: /* assume that this call will succeed: */
838: rc = TME_OK;
839:
840: /* lock our mutex: */
841: tme_mutex_lock(&sun_si->tme_sun_si_mutex);
842:
843: /* if the NCR 5380 already has an outstanding TLB entry, and it
844: doesn't happen to be this TLB entry, invalidate it: */
845: if (sun_si->tme_sun_si_ncr5380_tlb != NULL
846: && (tlb == NULL
847: || (sun_si->tme_sun_si_ncr5380_tlb
848: != TME_ATOMIC_READ(struct tme_bus_tlb *,
849: tlb->tme_bus_tlb_backing_reservation)))) {
850: tme_bus_tlb_invalidate(sun_si->tme_sun_si_ncr5380_tlb);
851:
852: /* the NCR 5380 doesn't have any outstanding TLB entry: */
853: sun_si->tme_sun_si_ncr5380_tlb = NULL;
854: }
855:
856: /* get the CSR value: */
857: csr = TME_SUN_SI_CSR_GET(sun_si);
858:
859: /* assume that this is not an onboard controller, and get the DMA
860: address register, plus the NCR 5380 address, and the DMA count
861: register: */
862: dma_address = TME_SUN_SI_REG32_GET(sun_si, TME_SUN_SI_REG_DMA_ADDRESS) + ncr5380_address;
863: dma_count = TME_SUN_SI_REG32_GET(sun_si, TME_SUN_SI_REG_DMA_COUNT);
864:
865: /* dispatch on the controller type: */
866: switch (sun_si->tme_sun_si_type) {
867:
868: default:
869: assert(FALSE);
870: /* FALLTHROUGH */
871:
872: case TME_SUN_SI_TYPE_3E:
873:
874: /* mask the DMA address and count registers to 16 bits: */
875: dma_address &= 0xffff;
876: dma_count &= 0xffff;
877:
878: /* if the NCR 5380 has stopped doing DMA, or if it has exhausted
879: DMA, or if DMA is not enabled: */
880: if (cycles == TME_BUS_CYCLE_UNDEF
881: || ncr5380_address >= dma_count
882: || !(csr & TME_SUN_SI_CSR_DMA_ENABLE)) {
883:
884: /* if the NCR 5380 has stopped doing DMA, cap the DMA count and
885: address to the amount of DMA that was available, thus
886: cancelling the effect of the NCR 5380 prefetch. this
887: prevents the DMA count from going negative, confusing the Sun
888: PROM and probably SunOS. I'm guessing that all of the SCSI
889: devices ever used with Suns change information transfer phase
890: faster than the NCR 5380 prefetches a byte from DMA, which is
891: why this DMA-count-going-negative problem is never seen. since
892: our NCR 5380 is infinitely fast at prefetch, we have to deal: */
893: if (cycles == TME_BUS_CYCLE_UNDEF
894: && ncr5380_address > dma_count) {
895: assert (ncr5380_address == (dma_count + 1));
896: dma_address -= (ncr5380_address - dma_count);
897: ncr5380_address = dma_count;
898: }
899:
900: /* update the DMA address and count registers: */
901: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_DMA_ADDRESS + sizeof(tme_uint16_t),
902: dma_address);
903: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_DMA_COUNT + sizeof(tme_uint16_t),
904: dma_count - ncr5380_address);
905:
906: /* return EAGAIN to the NCR 5380, unless it was the NCR 5380
907: that stopped doing DMA: */
908: if (cycles != TME_BUS_CYCLE_UNDEF) {
909: rc = EAGAIN;
910: }
911: break;
912: }
913:
914: /* XXX does DMA wrap around in the 3/E DMA memory? */
915: dma_count = TME_MIN((TME_SUN_SI_3E_SIZ_DMA - dma_address), dma_count);
916:
917: /* initialize the TLB entry: */
918: tme_bus_tlb_initialize(tlb);
919:
920: /* this TLB entry covers this range: */
921: TME_ATOMIC_WRITE(tme_bus_addr_t,
922: tlb->tme_bus_tlb_addr_first,
923: 0);
924: TME_ATOMIC_WRITE(tme_bus_addr_t,
925: tlb->tme_bus_tlb_addr_last,
926: dma_count - 1);
927:
928: /* this TLB entry supports fast reading and writing: */
929: tlb->tme_bus_tlb_emulator_off_read = sun_si->tme_sun_si_3e_dma + dma_address;
930: tlb->tme_bus_tlb_emulator_off_write = sun_si->tme_sun_si_3e_dma + dma_address;
931:
932: /* allow reading and writing: */
933: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
934:
935: /* our bus cycle handler: */
936: tlb->tme_bus_tlb_cycle_private = sun_si;
937: tlb->tme_bus_tlb_cycle = _tme_sun_si_bus_cycle_3e_dma;
938:
939: /* unlock our mutex: */
940: tme_mutex_unlock(&sun_si->tme_sun_si_mutex);
941:
942: return (TME_OK);
943:
944: case TME_SUN_SI_TYPE_VME:
945:
946: /* if the NCR 5380 has stopped doing DMA, or if it has exhausted
947: DMA, or if DMA is not enabled: */
948: if (cycles == TME_BUS_CYCLE_UNDEF
949: || ncr5380_address >= dma_count
950: || ((csr
951: & (TME_SUN_SI_CSR_DMA_CONFLICT
952: | TME_SUN_SI_CSR_DMA_BUS_ERROR
953: | TME_SUN_SI_CSR_DMA_ENABLE))
954: != TME_SUN_SI_CSR_DMA_ENABLE)) {
955:
956: /* if the NCR 5380 has stopped doing DMA, cap the DMA count and
957: address to the amount of DMA that was available, thus
958: cancelling the effect of the NCR 5380 prefetch. this
959: prevents the DMA count from going negative, confusing the Sun
960: PROM and probably SunOS. I'm guessing that all of the SCSI
961: devices ever used with Suns change information transfer phase
962: faster than the NCR 5380 prefetches a byte from DMA, which is
963: why this DMA-count-going-negative problem is never seen. since
964: our NCR 5380 is infinitely fast at prefetch, we have to deal: */
965: if (cycles == TME_BUS_CYCLE_UNDEF
966: && ncr5380_address > dma_count) {
967: assert (ncr5380_address == (dma_count + 1));
968: dma_address -= (ncr5380_address - dma_count);
969: ncr5380_address = dma_count;
970: }
971:
972: /* update the DMA address and count registers: */
973: TME_SUN_SI_REG32_PUT(sun_si, TME_SUN_SI_REG_DMA_ADDRESS, dma_address);
974: TME_SUN_SI_REG32_PUT(sun_si, TME_SUN_SI_REG_DMA_COUNT, dma_count - ncr5380_address);
975: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_VME_FIFO_COUNT_H, ((dma_count - ncr5380_address) >> 16));
976: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_FIFO_COUNT_L, ((dma_count - ncr5380_address) & 0xffff));
977:
978: /* assume that our emulated byte pack is empty: */
979: bpr = 0;
980: bpr_count = 0;
981:
982: #ifdef TME_SUN_SI_STRICT_VME
983:
984: /* if the NCR 5380 was doing DMA writes to memory (i.e., it was
985: receiving): */
986: if (!(csr & TME_SUN_SI_CSR_DMA_SEND)) {
987:
988: /* calculate how many bytes must be left in the byte pack: */
989: bpr_count = ncr5380_address;
990: bpr_count &= ((csr & TME_SUN_SI_CSR_VME_BPCON)
991: ? (sizeof(tme_uint16_t) - 1)
992: : (sizeof(tme_uint32_t) - 1));
993:
994: /* get the byte pack contents from the memory that the NCR
995: 5380 DMA'ed into. this is why all DMA writes have to be to
996: fast memory under TME_SUN_SI_STRICT_VME - if you DMA to
997: memory with side-effects, we can't read the data back out
998: again without incurring more side-effects, and we don't
999: want to do a *full* emulation of the DMA engine: */
1000: for (bpr_i = bpr_count; bpr_i > 0; bpr_i--) {
1001: bpr = (bpr << 8) | sun_si->tme_sun_si_dma_buffer_write[ncr5380_address - bpr_i];
1002: }
1003:
1004: /* left-justify the byte pack: */
1005: bpr <<= ((((csr & TME_SUN_SI_CSR_VME_BPCON)
1006: ? sizeof(tme_uint16_t)
1007: : sizeof(tme_uint32_t))
1008: - bpr_count)
1009: * 8);
1010:
1011: }
1012:
1013: /* otherwise, the NCR 5380 was doing DMA reads to memory (i.e.,
1014: it was sending): */
1015: else {
1016:
1017: /* nothing to do. we don't emulate the byte pack for sending: */
1018: }
1019:
1020: #endif /* TME_SUN_SI_STRICT_VME */
1021:
1022: /* update the byte pack and the CSR: */
1023: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_VME_BPR_H, (bpr >> 16));
1024: TME_SUN_SI_REG16_PUT(sun_si, TME_SUN_SI_REG_VME_BPR_L, (bpr & 0xffff));
1025: TME_FIELD_MASK_DEPOSITU(csr, TME_SUN_SI_CSR_VME_LOB_MASK, bpr_count);
1026: TME_SUN_SI_CSR_PUT(sun_si, csr);
1027:
1028: /* return EAGAIN to the NCR 5380, unless it was the NCR 5380
1029: that stopped doing DMA: */
1030: if (cycles != TME_BUS_CYCLE_UNDEF) {
1031: rc = EAGAIN;
1032: }
1033: break;
1034: }
1035: break;
1036:
1037: case TME_SUN_SI_TYPE_ONBOARD:
1038: /* TBD */
1039: abort();
1040:
1041: case TME_SUN_SI_TYPE_COBRA:
1042: /* TBD */
1043: abort();
1044: }
1045:
1046: /* if DMA is not ready for some reason: */
1047: if (rc == EAGAIN) {
1048:
1049: /* invalidate any local TLB entry passed by the caller: */
1050: if (tlb != NULL) {
1051: tme_bus_tlb_invalidate(tlb);
1052: }
1053:
1054: /* if DMA is enabled: */
1055: if (csr & TME_SUN_SI_CSR_DMA_ENABLE) {
1056:
1057: /* set a DMA interrupt and call out an interrupt change: */
1058: TME_SUN_SI_CSR_PUT(sun_si, TME_SUN_SI_CSR_GET(sun_si) | TME_SUN_SI_CSR_INT_DMA);
1059: _tme_sun_si_callout(sun_si, TME_SUN_SI_CALLOUT_INT);
1060: }
1061:
1062: /* cancel the remainder of the TLB fill: */
1063: cycles = TME_BUS_CYCLE_UNDEF;
1064: }
1065:
1066: /* get the bus connection for memory: */
1067: conn_bus = sun_si->tme_sun_si_conn_memory;
1068:
1069: /* if we need to fill a TLB entry on the bus: */
1070: if (cycles != TME_BUS_CYCLE_UNDEF) {
1071:
1072: /* the NCR 5380 now has this outstanding TLB entry: */
1073: sun_si->tme_sun_si_ncr5380_tlb
1074: = TME_ATOMIC_READ(struct tme_bus_tlb *, tlb->tme_bus_tlb_backing_reservation);
1075: }
1076:
1077: /* unlock our mutex: */
1078: tme_mutex_unlock(&sun_si->tme_sun_si_mutex);
1079:
1080: /* if we need to fill a TLB entry on the bus: */
1081: if (cycles != TME_BUS_CYCLE_UNDEF) {
1082:
1083: /* DMA must be OK so far: */
1084: assert (rc == TME_OK);
1085: assert (dma_count > ncr5380_address);
1086:
1087: /* call out to fill this TLB entry on the bus: */
1088: rc = (conn_bus != NULL
1089: ? (*conn_bus->tme_bus_tlb_fill)(conn_bus,
1090: tlb,
1091: dma_address,
1092: cycles)
1093: : ENXIO);
1094:
1095: /* if this callout succeeded: */
1096: if (rc == TME_OK) {
1097:
1098: #if defined(TME_SUN_SI_STRICT_VME) || defined(TME_SUN_SI_STRICT_ONBOARD) || defined(TME_SUN_SI_STRICT_COBRA)
1099:
1100: /* when the NCR 5380 wants to do DMA writes, in order to
1101: correctly emulate the byte pack registers on these
1102: controllers without having to emulate their full DMA behavior
1103: (copying 16- or 32-bit words into a controller register for
1104: the NCR 5380), we just insist that all DMA be done to memory
1105: that supports fast access: */
1106: if ((cycles & TME_BUS_CYCLE_WRITE)
1107: && tlb->tme_bus_tlb_emulator_off_write == TME_EMULATOR_OFF_UNDEF) {
1108: abort();
1109: }
1110:
1111: #endif /* defined(TME_SUN_SI_STRICT_VME) || defined(TME_SUN_SI_STRICT_ONBOARD) || defined(TME_SUN_SI_STRICT_COBRA) */
1112:
1113: /* create the mapping TLB entry: */
1114: TME_ATOMIC_WRITE(tme_bus_addr_t,
1115: tlb_mapping.tme_bus_tlb_addr_first,
1116: ncr5380_address);
1117: TME_ATOMIC_WRITE(tme_bus_addr_t,
1118: tlb_mapping.tme_bus_tlb_addr_last,
1119: (dma_count
1120: - 1));
1121: tlb_mapping.tme_bus_tlb_cycles_ok = cycles;
1122:
1123: /* map the filled TLB entry: */
1124: tme_bus_tlb_map(tlb, dma_address, &tlb_mapping, ncr5380_address);
1125:
1126: /* add our bus fault handler: */
1127: TME_BUS_TLB_FAULT_HANDLER(tlb, _tme_sun_si_bus_fault_handler, sun_si);
1128: }
1129: }
1130:
1131: return (rc);
1132: }
1133:
1134: /* the sun_si TLB allocator for the NCR 5380: */
1135: static int
1136: _tme_sun_si_tlb_set_allocate(struct tme_bus_connection *conn_bus,
1137: unsigned int count, unsigned int sizeof_one,
1138: TME_ATOMIC_POINTER_TYPE(struct tme_bus_tlb *) _tlbs)
1139: {
1140: struct tme_sun_si *sun_si;
1141:
1142: /* recover our data structures: */
1143: sun_si = conn_bus->tme_bus_connection.tme_connection_element->tme_element_private;
1144:
1145: /* pass the sun_si's request through to the memory bus: */
1146: conn_bus = sun_si->tme_sun_si_conn_memory;
1147: return (conn_bus != NULL
1148: ? (*conn_bus->tme_bus_tlb_set_allocate)(conn_bus,
1149: count, sizeof_one,
1150: _tlbs)
1151: : ENXIO);
1152: }
1153:
1154: /* this scores a new connection: */
1155: static int
1156: _tme_sun_si_connection_score(struct tme_connection *conn, unsigned int *_score)
1157: {
1158: struct tme_sun_si *sun_si;
1159: struct tme_sun_si_connection *conn_sun_si;
1160:
1161: /* both sides must be generic bus connections: */
1162: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
1163: assert(conn->tme_connection_other->tme_connection_type
1164: == conn->tme_connection_type);
1165:
1166: /* recover our data structures: */
1167: sun_si = conn->tme_connection_element->tme_element_private;
1168: conn_sun_si = (struct tme_sun_si_connection *)conn;
1169:
1170: /* this is a generic bus connection, so just score it nonzero and
1171: return. note that there's no good way to differentiate a
1172: connection to a bus from a connection to just another chip, so we
1173: always return a nonzero score here: */
1174: *_score = 1;
1175: return (TME_OK);
1176: }
1177:
1178: /* this makes a new connection: */
1179: static int
1180: _tme_sun_si_connection_make(struct tme_connection *conn, unsigned int state)
1181: {
1182: struct tme_sun_si *sun_si;
1183: struct tme_sun_si_connection *conn_sun_si;
1184: struct tme_bus_connection *conn_bus;
1185:
1186: /* both sides must be generic bus connections: */
1187: assert(conn->tme_connection_type == TME_CONNECTION_BUS_GENERIC);
1188: assert(conn->tme_connection_other->tme_connection_type
1189: == conn->tme_connection_type);
1190:
1191: /* recover our data structures: */
1192: sun_si = conn->tme_connection_element->tme_element_private;
1193: conn_sun_si = (struct tme_sun_si_connection *) conn;
1194: conn_bus = &conn_sun_si->tme_sun_si_connection;
1195:
1196: /* we're always set up to answer calls across the connection, so we
1197: only have to do work when the connection has gone full, namely
1198: taking the other side of the connection: */
1199: if (state == TME_CONNECTION_FULL) {
1200:
1201: /* lock our mutex: */
1202: tme_mutex_lock(&sun_si->tme_sun_si_mutex);
1203:
1204: /* save our connection: */
1205: if (conn_bus->tme_bus_tlb_fill == _tme_sun_si_tlb_fill) {
1206: sun_si->tme_sun_si_conn_ncr5380 = (struct tme_bus_connection *) conn->tme_connection_other;
1207: }
1208: else {
1209: if (conn_sun_si->tme_sun_si_connection_regs) {
1210: sun_si->tme_sun_si_conn_regs = (struct tme_bus_connection *) conn->tme_connection_other;
1211: }
1212: if (!(sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_ONBOARD
1213: || sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_COBRA)
1214: || !conn_sun_si->tme_sun_si_connection_regs) {
1215: sun_si->tme_sun_si_conn_memory = (struct tme_bus_connection *) conn->tme_connection_other;
1216: }
1217: }
1218:
1219: /* unlock our mutex: */
1220: tme_mutex_unlock(&sun_si->tme_sun_si_mutex);
1221: }
1222:
1223: return (TME_OK);
1224: }
1225:
1226: /* this breaks a connection: */
1227: static int
1228: _tme_sun_si_connection_break(struct tme_connection *conn, unsigned int state)
1229: {
1230: abort();
1231: }
1232:
1233: /* this makes a new connection side for a sun_si: */
1234: static int
1235: _tme_sun_si_connections_new(struct tme_element *element,
1236: const char * const *args,
1237: struct tme_connection **_conns,
1238: char **_output)
1239: {
1240: struct tme_sun_si *sun_si;
1241: struct tme_sun_si_connection *conn_sun_si;
1242: struct tme_bus_connection *conn_bus;
1243: struct tme_connection *conn;
1244: unsigned int ncr5380;
1245: unsigned int regs;
1246: int usage;
1247: int rc;
1248:
1249: /* recover our data structure: */
1250: sun_si = (struct tme_sun_si *) element->tme_element_private;
1251:
1252: /* we don't bother locking the mutex simply to check if connections
1253: already exist: */
1254:
1255: /* check our arguments: */
1256: usage = FALSE;
1257: rc = 0;
1258: regs = FALSE;
1259: ncr5380 = FALSE;
1260:
1261: /* if this connection is for the registers: */
1262: if (TME_ARG_IS(args[1], "csr")) {
1263:
1264: /* if we already have a register connection, complain: */
1265: if (sun_si->tme_sun_si_conn_regs != NULL) {
1266: rc = EEXIST;
1267: }
1268:
1269: /* otherwise, make the new connection: */
1270: else {
1271: regs = TRUE;
1272: }
1273: }
1274:
1275: /* else, if this connection is for the memory: */
1276: else if ((sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_ONBOARD
1277: || sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_COBRA)
1278: && TME_ARG_IS(args[1], "memory")) {
1279:
1280: /* if we already have a memory connection, complain: */
1281: if (sun_si->tme_sun_si_conn_memory != NULL) {
1282: rc = EEXIST;
1283: }
1284: }
1285:
1286: /* else, the connection must be for the ncr5380: */
1287: else if (args[1] == NULL) {
1288:
1289: /* if we already have an ncr5380 connection, complain: */
1290: if (sun_si->tme_sun_si_conn_ncr5380 != NULL) {
1291: rc = EEXIST;
1292: }
1293:
1294: /* otherwise, make the new connection: */
1295: else {
1296: ncr5380 = TRUE;
1297: }
1298: }
1299:
1300: /* otherwise, this is a bad argument: */
1301: else {
1302: tme_output_append_error(_output,
1303: "%s %s, ",
1304: args[1],
1305: _("unexpected"));
1306: usage = TRUE;
1307: }
1308:
1309: if (usage) {
1310: tme_output_append_error(_output,
1311: ((sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_ONBOARD
1312: || sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_COBRA)
1313: ? "%s %s [ csr | memory ]"
1314: : "%s %s [ csr ]"),
1315: _("usage:"),
1316: args[0]);
1317: rc = EINVAL;
1318: }
1319:
1320: if (rc) {
1321: return (rc);
1322: }
1323:
1324: /* make a new connection: */
1325: conn_sun_si = tme_new0(struct tme_sun_si_connection, 1);
1326: conn_bus = &conn_sun_si->tme_sun_si_connection;
1327: conn = &conn_bus->tme_bus_connection;
1328:
1329: /* fill in the generic connection: */
1330: conn->tme_connection_next = *_conns;
1331: conn->tme_connection_type = TME_CONNECTION_BUS_GENERIC;
1332: conn->tme_connection_score = _tme_sun_si_connection_score;
1333: conn->tme_connection_make = _tme_sun_si_connection_make;
1334: conn->tme_connection_break = _tme_sun_si_connection_break;
1335:
1336: /* fill in the generic bus connection: */
1337: conn_bus->tme_bus_subregions.tme_bus_subregion_address_first = 0;
1338: conn_bus->tme_bus_subregions.tme_bus_subregion_next = NULL;
1339: if (ncr5380) {
1340: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = ((tme_bus_addr_t) 0) - 1;
1341: conn_bus->tme_bus_signals_add = NULL;
1342: conn_bus->tme_bus_signal = _tme_sun_si_bus_signal;
1343: conn_bus->tme_bus_tlb_set_allocate = _tme_sun_si_tlb_set_allocate;
1344: conn_bus->tme_bus_tlb_fill = _tme_sun_si_tlb_fill;
1345: }
1346: else if (regs) {
1347: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = TME_SUN_SI_SIZ_REGS - 1;
1348: conn_bus->tme_bus_tlb_fill = _tme_sun_si_tlb_fill_regs;
1349: if (sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_VME
1350: || sun_si->tme_sun_si_type == TME_SUN_SI_TYPE_3E) {
1351: conn_bus->tme_bus_intack = _tme_sun_si_intack;
1352: }
1353: }
1354: else {
1355: conn_bus->tme_bus_subregions.tme_bus_subregion_address_last = 0;
1356: }
1357:
1358: /* fill in the internal information: */
1359: conn_sun_si->tme_sun_si_connection_regs = regs;
1360:
1361: /* return the connection side possibility: */
1362: *_conns = conn;
1363: return (TME_OK);
1364: }
1365:
1366: /* the new sun_si function: */
1367: int
1368: tme_sun_si(struct tme_element *element, const char * const *args, char **_output)
1369: {
1370: struct tme_sun_si *sun_si;
1371: int arg_i;
1372: int usage;
1373: tme_uint32_t si_type;
1374:
1375: /* check our arguments: */
1376: usage = 0;
1377: si_type = TME_SUN_SI_TYPE_NULL;
1378: arg_i = 1;
1379: for (;;) {
1380:
1381: /* the si type: */
1382: if (TME_ARG_IS(args[arg_i + 0], "type")) {
1383: if (TME_ARG_IS(args[arg_i + 1], "vme")) {
1384: si_type = TME_SUN_SI_TYPE_VME;
1385: }
1386: else if (TME_ARG_IS(args[arg_i + 1], "onboard")) {
1387: si_type = TME_SUN_SI_TYPE_ONBOARD;
1388: }
1389: else if (TME_ARG_IS(args[arg_i + 1], "3/E")) {
1390: si_type = TME_SUN_SI_TYPE_3E;
1391: }
1392: else if (TME_ARG_IS(args[arg_i + 1], "cobra")) {
1393: si_type = TME_SUN_SI_TYPE_COBRA;
1394: }
1395: else {
1396: usage = TRUE;
1397: break;
1398: }
1399: arg_i += 2;
1400: }
1401:
1402: /* if we ran out of arguments: */
1403: else if (args[arg_i] == NULL) {
1404:
1405: break;
1406: }
1407:
1408: /* otherwise this is a bad argument: */
1409: else {
1410: tme_output_append_error(_output,
1411: "%s %s, ",
1412: args[arg_i],
1413: _("unexpected"));
1414: usage = TRUE;
1415: break;
1416: }
1417: }
1418:
1419: if (usage) {
1420: tme_output_append_error(_output,
1421: "%s %s type { vme | onboard | 3/E | cobra } [ size { 1600x1280 | 1152x900 | 1024x1024 | 1280x1024 | 1440x1440 | 640x480 } ]",
1422: _("usage:"),
1423: args[0]);
1424: return (EINVAL);
1425: }
1426:
1427: /* start the sun_si structure: */
1428: sun_si = tme_new0(struct tme_sun_si, 1);
1429: sun_si->tme_sun_si_type = si_type;
1430: sun_si->tme_sun_si_3e_dma = (si_type == TME_SUN_SI_TYPE_3E
1431: ? tme_new(char, TME_SUN_SI_3E_SIZ_DMA)
1432: : NULL);
1433: sun_si->tme_sun_si_element = element;
1434: TME_SUN_SI_CSR_PUT(sun_si,
1435: ((si_type == TME_SUN_SI_TYPE_VME
1436: ? TME_SUN_SI_CSR_VME_MODIFIED
1437: : 0)
1438: | (si_type == TME_SUN_SI_TYPE_3E
1439: ? TME_SUN_SI_CSR_3E_VCC
1440: : TME_SUN_SI_CSR_RESET_FIFO)
1441: | TME_SUN_SI_CSR_RESET_CONTROLLER));
1442: sun_si->tme_sun_si_csr_ncr5380 = TME_SUN_SI_CSR_GET(sun_si);
1443: tme_mutex_init(&sun_si->tme_sun_si_mutex);
1444: tme_rwlock_init(&sun_si->tme_sun_si_rwlock);
1445:
1446: /* fill the element: */
1447: element->tme_element_private = sun_si;
1448: element->tme_element_connections_new = _tme_sun_si_connections_new;
1449:
1450: return (TME_OK);
1451: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.