|
|
1.1 root 1: /* $Id: 3c400.c,v 1.6 2003/05/18 00:05:12 fredette Exp $ */
2:
3: /* bus/multibus/3c400.c - implementation of the Multibus 3c400 emulation: */
4:
5: /*
6: * Copyright (c) 2003 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: 3c400.c,v 1.6 2003/05/18 00:05:12 fredette Exp $");
38:
39: /* includes: */
40: #include <tme/generic/bus-device.h>
41: #include <tme/generic/ethernet.h>
42:
43: /* macros: */
44:
45: /* register offsets and sizes: */
46: #define TME_3C400_REG_CSR (0)
47: #define TME_3C400_SIZ_CSR (sizeof(tme_uint16_t))
48: #define TME_3C400_REG_BACKOFF (2)
49: #define TME_3C400_SIZ_BACKOFF (sizeof(tme_uint16_t))
50: #define TME_3C400_REG_AROM (1024)
51: #define TME_3C400_SIZ_AROM (TME_ETHERNET_ADDR_SIZE)
52: #define TME_3C400_REG_ARAM (1536)
53: #define TME_3C400_SIZ_ARAM (TME_ETHERNET_ADDR_SIZE)
54: #define TME_3C400_REG_TBUF (2048)
55: #define TME_3C400_SIZ_BUF (2048)
56: #define TME_3C400_REG_ABUF (TME_3C400_REG_TBUF + TME_3C400_SIZ_BUF)
57: #define TME_3C400_REG_BBUF (TME_3C400_REG_ABUF + TME_3C400_SIZ_BUF)
58: #define TME_3C400_SIZ_CARD (TME_3C400_REG_BBUF + TME_3C400_SIZ_BUF)
59:
60: /* the bits in the Control/Status Register. software can set and
61: clear bits covered by TME_3C400_CSR_INTPA. software can set, but
62: not clear, bits not covered by TME_3C400_CSR_INTPA: */
63: #define TME_3C400_CSR_BBSW (0x8000) /* B buffer empty (belongs to card) */
64: #define TME_3C400_CSR_ABSW (0x4000) /* A buffer empty (belongs to card) */
65: #define TME_3C400_CSR_TBSW (0x2000) /* T buffer full (belongs to card) */
66: #define TME_3C400_CSR_JAM (0x1000) /* Ethernet jammed (collision) */
67: #define TME_3C400_CSR_AMSW (0x0800) /* address RAM belongs to ether */
68: #define TME_3C400_CSR_RBBA (0x0400) /* B buffer received before A */
69: #define TME_3C400_CSR_RESET (0x0100) /* reset the card */
70: #define TME_3C400_CSR_INTPA (0x00ff) /* mask for interrupt and PA fields */
71: #define TME_3C400_CSR_BINT (0x0080) /* B buffer interrupt enable */
72: #define TME_3C400_CSR_AINT (0x0040) /* A buffer interrupt enable */
73: #define TME_3C400_CSR_TINT (0x0020) /* T buffer interrupt enable */
74: #define TME_3C400_CSR_JINT (0x0010) /* jam interrupt enable */
75: #define TME_3C400_CSR_PAMASK (0x000f) /* PA field */
76: #define TME_3C400_CSR_PA (0x0007) /* receive mine+broadcast-errors */
77: #define TME_3C400_CSR_PROMISC (0x0001) /* receive all-errors */
78:
79: /* the first 16 bits of all buffers are a status word: */
80: #define TME_3C400_SIZ_BUF_STATUS (sizeof(tme_uint16_t))
81:
82: /* the bits of a receive buffer status word: */
83: /* Frame Check Sequence (CRC) error */
84: #define TME_3C400_RBUF_FCSERR (0x8000)
85: /* this packet was broadcast: */
86: #define TME_3C400_RBUF_BROADCAST (0x4000)
87: /* this packet had a "range error": */
88: #define TME_3C400_RBUF_RGERR (0x2000)
89: /* this packet matched our address: */
90: #define TME_3C400_RBUF_ADDRMATCH (0x1000)
91: /* this packet had a framing error: */
92: #define TME_3C400_RBUF_FRERR (0x0800)
93: /* the first byte after the frame in the buffer: */
94: #define TME_3C400_RBUF_DOFF_MASK (0x07ff)
95:
96: /* these get and put the CSR: */
97: #define TME_3C400_CSR_GET(_3c400) \
98: tme_betoh_u16(*((tme_uint16_t *) &(_3c400)->tme_3c400_card[TME_3C400_REG_CSR]))
99: #define TME_3C400_CSR_PUT(_3c400, csr) \
100: (*((tme_uint16_t *) &(_3c400)->tme_3c400_card[TME_3C400_REG_CSR]) = tme_betoh_u16(csr))
101:
102: /* the callout flags: */
103: #define TME_3C400_CALLOUT_CHECK (0)
104: #define TME_3C400_CALLOUT_RUNNING TME_BIT(0)
105: #define TME_3C400_CALLOUTS_MASK (-2)
106: #define TME_3C400_CALLOUT_CTRL TME_BIT(1)
107: #define TME_3C400_CALLOUT_CONFIG TME_BIT(2)
108: #define TME_3C400_CALLOUT_READ TME_BIT(3)
109: #define TME_3C400_CALLOUT_INT TME_BIT(4)
110:
111: /* structures: */
112:
113: /* the card: */
114: struct tme_3c400 {
115:
116: /* our simple bus device header: */
117: struct tme_bus_device tme_3c400_device;
118: #define tme_3c400_element tme_3c400_device.tme_bus_device_element
119:
120: /* the mutex protecting the card: */
121: tme_mutex_t tme_3c400_mutex;
122:
123: /* the rwlock protecting the card: */
124: tme_rwlock_t tme_3c400_rwlock;
125:
126: /* the Ethernet connection: */
127: struct tme_ethernet_connection *tme_3c400_eth_connection;
128:
129: /* the callout flags: */
130: int tme_3c400_callout_flags;
131:
132: /* if our interrupt line is currently asserted: */
133: int tme_3c400_int_asserted;
134:
135: /* it's easiest to just model the card as a chunk of memory: */
136: tme_uint8_t tme_3c400_card[TME_3C400_SIZ_CARD];
137:
138: #ifndef TME_NO_LOG
139: tme_uint16_t tme_3c400_last_log_csr;
140: #endif /* !TME_NO_LOG */
141: };
142:
143: /* this resets the card: */
144: static void
145: _tme_3c400_reset(struct tme_3c400 *_3c400)
146: {
147: tme_uint16_t csr;
148:
149: /* the reset CSR value: */
150: csr = 0;
151:
152: /* set the CSR: */
153: TME_3C400_CSR_PUT(_3c400, csr);
154:
155: /* clear all pending callouts: */
156: _3c400->tme_3c400_callout_flags &= TME_3C400_CALLOUTS_MASK;
157:
158: /* if the interrupt line is currently asserted, negate it: */
159: if (_3c400->tme_3c400_int_asserted) {
160: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_INT;
161: }
162: }
163:
164: /* the _3c400 callout function. it must be called with the mutex locked: */
165: static void
166: _tme_3c400_callout(struct tme_3c400 *_3c400, int new_callouts)
167: {
168: struct tme_ethernet_connection *conn_eth;
169: struct tme_bus_connection *conn_bus;
170: tme_uint16_t csr, csr_rbba, recv_buffer;
171: int callouts, later_callouts;
172: unsigned int ctrl;
173: struct tme_ethernet_config config;
174: int rc;
175: const tme_uint8_t *addrs[2];
176: tme_ethernet_fid_t frame_id;
177: tme_uint8_t *rbuf;
178: tme_uint16_t status;
179: struct tme_ethernet_frame_chunk *frame_chunk, frame_chunk_buffer;
180: int int_asserted;
181:
182: /* add in any new callouts: */
183: _3c400->tme_3c400_callout_flags |= new_callouts;
184:
185: /* if this function is already running in another thread, simply
186: return now. the other thread will do our work: */
187: if (_3c400->tme_3c400_callout_flags & TME_3C400_CALLOUT_RUNNING) {
188: return;
189: }
190:
191: /* callouts are now running: */
192: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_RUNNING;
193:
194: /* assume that we won't need any later callouts: */
195: later_callouts = 0;
196:
197: /* loop while callouts are needed: */
198: for (; (callouts = _3c400->tme_3c400_callout_flags) & TME_3C400_CALLOUTS_MASK; ) {
199:
200: /* clear the needed callouts: */
201: _3c400->tme_3c400_callout_flags = callouts & ~TME_3C400_CALLOUTS_MASK;
202: callouts &= TME_3C400_CALLOUTS_MASK;
203:
204: /* get this card's connection: */
205: conn_eth = _3c400->tme_3c400_eth_connection;
206:
207: /* if we need to call out new control information: */
208: if (callouts & TME_3C400_CALLOUT_CTRL) {
209:
210: /* get the current CSR value: */
211: csr = TME_3C400_CSR_GET(_3c400);
212:
213: /* form the new ctrl: */
214: ctrl = 0;
215: if (csr & TME_3C400_CSR_TBSW) {
216: ctrl |= TME_ETHERNET_CTRL_OK_READ;
217: }
218:
219: /* unlock the mutex: */
220: tme_mutex_unlock(&_3c400->tme_3c400_mutex);
221:
222: /* do the callout: */
223: rc = (conn_eth != NULL
224: ? ((*conn_eth->tme_ethernet_connection_ctrl)
225: (conn_eth,
226: ctrl))
227: : TME_OK);
228:
229: /* lock the mutex: */
230: tme_mutex_lock(&_3c400->tme_3c400_mutex);
231:
232: /* if the callout was unsuccessful, remember that at some later
233: time this callout should be attempted again: */
234: if (rc != TME_OK) {
235: later_callouts |= TME_3C400_CALLOUT_CTRL;
236: }
237: }
238:
239: /* if we need to call out new config information: */
240: if (callouts & TME_3C400_CALLOUT_CONFIG) {
241:
242: /* get the current CSR value: */
243: csr = TME_3C400_CSR_GET(_3c400);
244:
245: /* form the new config: */
246: memset(&config, 0, sizeof(config));
247:
248: /* our Ethernet address: */
249: config.tme_ethernet_config_addr_count = 0;
250: addrs[config.tme_ethernet_config_addr_count++]
251: = tme_ethernet_addr_broadcast;
252: if (csr & TME_3C400_CSR_AMSW) {
253: addrs[config.tme_ethernet_config_addr_count++]
254: = &_3c400->tme_3c400_card[TME_3C400_REG_ARAM];
255: }
256: config.tme_ethernet_config_addrs = addrs;
257:
258: /* our config flags: */
259: config.tme_ethernet_config_flags = TME_ETHERNET_CONFIG_NORMAL;
260: switch (csr & TME_3C400_CSR_PAMASK) {
261: case 0:
262: config.tme_ethernet_config_addr_count = 0;
263: break;
264: case TME_3C400_CSR_PA:
265: break;
266: case TME_3C400_CSR_PROMISC:
267: config.tme_ethernet_config_flags |= TME_ETHERNET_CONFIG_PROMISC;
268: break;
269: default: abort();
270: }
271:
272: /* unlock the mutex: */
273: tme_mutex_unlock(&_3c400->tme_3c400_mutex);
274:
275: /* do the callout: */
276: rc = (conn_eth == NULL
277: ? TME_OK
278: : ((*conn_eth->tme_ethernet_connection_config)
279: (conn_eth,
280: &config)));
281:
282: /* lock the mutex: */
283: tme_mutex_lock(&_3c400->tme_3c400_mutex);
284:
285: /* if the callout was unsuccessful, remember that at some later
286: time this callout should be attempted again: */
287: if (rc != TME_OK) {
288: later_callouts |= TME_3C400_CALLOUT_CONFIG;
289: }
290: }
291:
292: /* if the Ethernet is readable: */
293: if (callouts & TME_3C400_CALLOUT_READ) {
294:
295: /* get the current CSR value: */
296: csr = TME_3C400_CSR_GET(_3c400);
297:
298: /* try to find an empty buffer: */
299: switch (csr & (TME_3C400_CSR_BBSW | TME_3C400_CSR_ABSW)) {
300: default:
301: /* both buffers are full: */
302: recv_buffer = 0;
303: csr_rbba = (csr & TME_3C400_CSR_RBBA);
304: break;
305: case TME_3C400_CSR_BBSW:
306: /* the A buffer is full but the B buffer is empty: */
307: recv_buffer = TME_3C400_CSR_BBSW;
308: csr_rbba = 0;
309: break;
310: case TME_3C400_CSR_ABSW:
311: /* the B buffer is full but the A buffer is empty: */
312: recv_buffer = TME_3C400_CSR_ABSW;
313: csr_rbba = TME_3C400_CSR_RBBA;
314: break;
315: case TME_3C400_CSR_ABSW | TME_3C400_CSR_BBSW:
316: /* both buffers are empty: */
317: recv_buffer = TME_3C400_CSR_ABSW;
318: csr_rbba = 0;
319: break;
320: }
321:
322: /* unlock the mutex: */
323: tme_mutex_unlock(&_3c400->tme_3c400_mutex);
324:
325: /* make a frame chunk to receive this frame. remember that the
326: first two bytes of our card's buffers are a status word: */
327: if (recv_buffer == 0) {
328: rbuf = NULL;
329: frame_chunk = NULL;
330: }
331: else {
332: rbuf =
333: &_3c400->tme_3c400_card[(recv_buffer == TME_3C400_CSR_ABSW
334: ? TME_3C400_REG_ABUF
335: : TME_3C400_REG_BBUF)];
336: frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL;
337: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes
338: = rbuf + TME_3C400_SIZ_BUF_STATUS;
339: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count
340: = TME_3C400_SIZ_BUF;
341: frame_chunk = &frame_chunk_buffer;
342: }
343:
344: /* do the callout: */
345: rc = (conn_eth == NULL
346: ? TME_OK
347: : ((*conn_eth->tme_ethernet_connection_read)
348: (conn_eth,
349: &frame_id,
350: frame_chunk,
351: TME_ETHERNET_READ_NEXT)));
352:
353: /* lock the mutex: */
354: tme_mutex_lock(&_3c400->tme_3c400_mutex);
355:
356: /* get the current CSR value: */
357: csr = TME_3C400_CSR_GET(_3c400);
358:
359: /* if the read was successful: */
360: if (rc > 0) {
361:
362: /* if this frame was received into a buffer: */
363: if (recv_buffer != 0) {
364:
365: /* form the status word for this buffer: */
366: status = 0;
367:
368: /* the first thing in the frame is the destination address,
369: which we check against our address and the broadcast
370: address: */
371: if (memcmp(rbuf + TME_3C400_SIZ_BUF_STATUS,
372: &_3c400->tme_3c400_card[TME_3C400_REG_ARAM],
373: TME_ETHERNET_ADDR_SIZE) == 0) {
374: status |= TME_3C400_RBUF_ADDRMATCH;
375: }
376: else if (memcmp(rbuf + TME_3C400_SIZ_BUF_STATUS,
377: tme_ethernet_addr_broadcast,
378: TME_ETHERNET_ADDR_SIZE) == 0) {
379: status |= TME_3C400_RBUF_BROADCAST;
380: }
381:
382: /* put in the offset of the first free byte in the status.
383: make sure we present a packet that is at least as big
384: as the smallest Ethernet frame: */
385: rc = TME_MAX(rc, TME_ETHERNET_FRAME_MIN - TME_ETHERNET_CRC_SIZE);
386: status |= TME_3C400_SIZ_BUF_STATUS + rc;
387:
388: /* put in the status: */
389: *((tme_uint16_t *) rbuf) = tme_htobe_u16(status);
390:
391: /* update the CSR to reflect the new packet: */
392: csr = (csr & ~(recv_buffer | TME_3C400_CSR_RBBA)) | csr_rbba;
393: TME_3C400_CSR_PUT(_3c400, csr);
394:
395: /* if interrupts are enabled on this buffer, mark that we need
396: to callout an interrupt: */
397: if (csr & (recv_buffer >> 8)) {
398: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_INT;
399: }
400: }
401:
402: /* mark that we need to loop to callout to read more frames: */
403: _3c400->tme_3c400_callout_flags |= TME_3C400_CALLOUT_READ;
404: }
405:
406: /* otherwise, the read failed. convention dictates that we
407: forget that the connection was readable, which we already
408: have done by clearing the CALLOUT_READ flag: */
409: }
410:
411: /* if we need to call out a possible change to our interrupt
412: signal: */
413: if (callouts & TME_3C400_CALLOUT_INT) {
414:
415: /* get the current CSR value: */
416: csr = TME_3C400_CSR_GET(_3c400);
417:
418: /* see if the interrupt signal should be asserted or negated: */
419: int_asserted = ((~(csr & (TME_3C400_CSR_BBSW
420: | TME_3C400_CSR_ABSW
421: | TME_3C400_CSR_TBSW)))
422: & ((csr & (TME_3C400_CSR_BINT
423: | TME_3C400_CSR_AINT
424: | TME_3C400_CSR_TINT)) << 8));
425:
426: /* if the interrupt signal doesn't already have the right state: */
427: if (!int_asserted != !_3c400->tme_3c400_int_asserted) {
428:
429: /* unlock our mutex: */
430: tme_mutex_unlock(&_3c400->tme_3c400_mutex);
431:
432: /* get our bus connection: */
433: conn_bus = TME_ATOMIC_READ(struct tme_bus_connection *,
434: _3c400->tme_3c400_device.tme_bus_device_connection);
435:
436: /* call out the bus interrupt signal edge: */
437: rc = (*conn_bus->tme_bus_signal)
438: (conn_bus,
439: TME_BUS_SIGNAL_INT_UNSPEC
440: | (int_asserted
441: ? TME_BUS_SIGNAL_LEVEL_ASSERTED
442: : TME_BUS_SIGNAL_LEVEL_NEGATED)
443: | TME_BUS_SIGNAL_EDGE);
444:
445: /* lock our mutex: */
446: tme_mutex_lock(&_3c400->tme_3c400_mutex);
447:
448: /* if this callout was successful, note the new state of the
449: interrupt signal: */
450: if (rc == TME_OK) {
451: _3c400->tme_3c400_int_asserted = int_asserted;
452: }
453:
454: /* otherwise, remember that at some later time this callout
455: should be attempted again: */
456: else {
457: later_callouts |= TME_3C400_CALLOUT_INT;
458: }
459: }
460: }
461: }
462:
463: /* put in any later callouts, and clear that callouts are running: */
464: _3c400->tme_3c400_callout_flags = later_callouts;
465: }
466:
467: /* the _3c400 bus cycle handler: */
468: static int
469: _tme_3c400_bus_cycle(void *__3c400, struct tme_bus_cycle *cycle_init)
470: {
471: struct tme_3c400 *_3c400;
472: tme_uint16_t csr_old, csr_new, csr_diff;
473: int new_callouts;
474:
475: /* recover our data structure: */
476: _3c400 = (struct tme_3c400 *) __3c400;
477:
478: /* assume we won't need any new callouts: */
479: new_callouts = 0;
480:
481: /* lock the mutex: */
482: tme_mutex_lock(&_3c400->tme_3c400_mutex);
483:
484: /* get the changed CSR value - there are bits that software can only
485: set, and not clear: */
486: csr_old = TME_3C400_CSR_GET(_3c400);
487:
488: /* unless this address falls within the address ROM, run the cycle: */
489: if ((cycle_init->tme_bus_cycle_address
490: < TME_3C400_REG_AROM)
491: || (cycle_init->tme_bus_cycle_address
492: >= TME_3C400_REG_ARAM)) {
493: tme_bus_cycle_xfer_memory(cycle_init,
494: _3c400->tme_3c400_card,
495: _3c400->tme_3c400_device.tme_bus_device_address_last);
496: }
497:
498: /* get the new CSR value, and put back any bits that software
499: cannot clear: */
500: csr_new = TME_3C400_CSR_GET(_3c400);
501: csr_new |= (csr_old & ~TME_3C400_CSR_INTPA);
502:
503: /* get the set of bits that has changed: */
504: csr_diff = (csr_old ^ csr_new);
505:
506: /* if this is a reset: */
507: if (csr_diff & TME_3C400_CSR_RESET) {
508: _tme_3c400_reset(_3c400);
509: }
510:
511: /* otherwise: */
512: else {
513:
514: /* if the transmit buffer now belongs to the card, call out
515: that we are now readable: */
516: if (csr_diff & TME_3C400_CSR_TBSW) {
517: new_callouts |= TME_3C400_CALLOUT_CTRL;
518: }
519:
520: /* if the address RAM now belongs to the card, or if the address
521: filter configuration has changed, call out the config change: */
522: if ((csr_diff & TME_3C400_CSR_AMSW)
523: || (csr_diff & TME_3C400_CSR_PAMASK) != 0) {
524: new_callouts |= TME_3C400_CALLOUT_CONFIG;
525: }
526:
527: /* if any interrupt enable status bits have changed,
528: call out the interrupt signal change: */
529: if (csr_diff & (TME_3C400_CSR_BINT
530: | TME_3C400_CSR_AINT
531: | TME_3C400_CSR_TINT)) {
532: new_callouts |= TME_3C400_CALLOUT_INT;
533: }
534:
535: /* set the current CSR value: */
536: TME_3C400_CSR_PUT(_3c400, csr_new);
537:
538: #ifndef TME_NO_LOG
539: if (csr_new != _3c400->tme_3c400_last_log_csr) {
540: _3c400->tme_3c400_last_log_csr = csr_new;
541: tme_log(&_3c400->tme_3c400_element->tme_element_log_handle,
542: 1000, TME_OK,
543: (&_3c400->tme_3c400_element->tme_element_log_handle,
544: "csr now 0x%04x",
545: csr_new));
546: }
547: #endif /* !TME_NO_LOG */
548: }
549:
550: /* make any new callouts: */
551: _tme_3c400_callout(_3c400, new_callouts);
552:
553: /* unlock the mutex: */
554: tme_mutex_unlock(&_3c400->tme_3c400_mutex);
555:
556: /* no faults: */
557: return (TME_OK);
558: }
559:
560: /* this is called when a device changes its configuration: */
561: static int
562: _tme_3c400_config(struct tme_ethernet_connection *conn_eth,
563: struct tme_ethernet_config *config)
564: {
565: /* we don't care when other devices on the Ethernet
566: reconfigure themselves: */
567: return (TME_OK);
568: }
569:
570: /* this is called when control lines change: */
571: static int
572: _tme_3c400_ctrl(struct tme_ethernet_connection *conn_eth,
573: unsigned int ctrl)
574: {
575: struct tme_3c400 *_3c400;
576: int new_callouts;
577:
578: /* recover our data structures: */
579: _3c400 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private;
580:
581: /* assume that we won't need any new callouts: */
582: new_callouts = 0;
583:
584: /* lock the mutex: */
585: tme_mutex_lock(&_3c400->tme_3c400_mutex);
586:
587: /* if this connection is readable, call out a read: */
588: if (ctrl & TME_ETHERNET_CTRL_OK_READ) {
589: new_callouts |= TME_3C400_CALLOUT_READ;
590: }
591:
592: /* make any new callouts: */
593: _tme_3c400_callout(_3c400, new_callouts);
594:
595: /* unlock the mutex: */
596: tme_mutex_unlock(&_3c400->tme_3c400_mutex);
597:
598: return (TME_OK);
599: }
600:
601: /* this is called to read frames (from the 3c400 perspective, to transmit them): */
602: static int
603: _tme_3c400_read(struct tme_ethernet_connection *conn_eth,
604: tme_ethernet_fid_t *_frame_id,
605: struct tme_ethernet_frame_chunk *frame_chunks,
606: unsigned int flags)
607: {
608: struct tme_3c400 *_3c400;
609: struct tme_ethernet_frame_chunk frame_chunk_buffer;
610: tme_uint16_t csr, count;
611: int new_callouts;
612: int rc;
613:
614: /* recover our data structures: */
615: _3c400 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private;
616:
617: /* assume that we won't need any new callouts: */
618: new_callouts = 0;
619:
620: /* lock our mutex: */
621: tme_mutex_lock(&_3c400->tme_3c400_mutex);
622:
623: /* get the current CSR value: */
624: csr = TME_3C400_CSR_GET(_3c400);
625:
626: /* if the transmit buffer is full: */
627: if (csr & TME_3C400_CSR_TBSW) {
628:
629: /* get the count of bytes in the frame: */
630: count = (TME_3C400_SIZ_BUF
631: - (tme_betoh_u16(*((tme_uint16_t *)
632: &_3c400->tme_3c400_card[TME_3C400_REG_TBUF]))
633: & TME_3C400_RBUF_DOFF_MASK));
634:
635: /* form the single frame chunk: */
636: frame_chunk_buffer.tme_ethernet_frame_chunk_next = NULL;
637: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes
638: = (&_3c400->tme_3c400_card[TME_3C400_REG_TBUF]
639: + TME_3C400_SIZ_BUF
640: - count);
641: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count
642: = count;
643:
644: /* copy out the frame: */
645: count = tme_ethernet_chunks_copy(frame_chunks, &frame_chunk_buffer);
646:
647: /* if this isn't a peek: */
648: if (!(flags & TME_ETHERNET_READ_PEEK)) {
649:
650: /* mark the transmit buffer as empty: */
651: csr &= ~TME_3C400_CSR_TBSW;
652: TME_3C400_CSR_PUT(_3c400, csr);
653:
654: /* if transmit buffer interrupts are enabled, call out
655: an interrupt: */
656: if (csr & TME_3C400_CSR_TINT) {
657: new_callouts |= TME_3C400_CALLOUT_INT;
658: }
659: }
660:
661: /* success: */
662: rc = count;
663: }
664:
665: /* if the transmit buffer is empty, return an error: */
666: else {
667: rc = -ENOENT;
668: }
669:
670: /* make any new callouts: */
671: _tme_3c400_callout(_3c400, new_callouts);
672:
673: /* unlock our mutex: */
674: tme_mutex_unlock(&_3c400->tme_3c400_mutex);
675:
676: /* done: */
677: return (rc);
678: }
679:
680: /* the _3c400 TLB filler: */
681: static int
682: _tme_3c400_tlb_fill(void *__3c400, struct tme_bus_tlb *tlb,
683: tme_bus_addr_t address, unsigned int cycles)
684: {
685: struct tme_3c400 *_3c400;
686:
687: /* recover our data structure: */
688: _3c400 = (struct tme_3c400 *) __3c400;
689:
690: /* the address must be within range: */
691: assert(address < TME_3C400_SIZ_CARD);
692:
693: /* initialize the TLB entry: */
694: tme_bus_tlb_initialize(tlb);
695:
696: /* if the address falls from the CSR to the address ROM: */
697: if (TME_3C400_REG_CSR <= address
698: && address < TME_3C400_REG_AROM) {
699:
700: /* this TLB entry covers this range: */
701: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, TME_3C400_REG_CSR);
702: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_3C400_REG_AROM - 1);
703: }
704:
705: /* if this address falls from the address ROM to the address RAM: */
706: else if (TME_3C400_REG_AROM <= address
707: && address < TME_3C400_REG_ARAM) {
708:
709: /* this TLB entry covers this range: */
710: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, TME_3C400_REG_AROM);
711: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_3C400_REG_ARAM - 1);
712: }
713:
714: /* anything else covers the remainder of the device: */
715: else {
716:
717: /* this TLB entry can cover from the address RAM to the end of the card: */
718: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first, TME_3C400_REG_ARAM);
719: TME_ATOMIC_WRITE(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last, TME_3C400_SIZ_CARD - 1);
720:
721: /* this TLB entry allows fast writing: */
722: tlb->tme_bus_tlb_emulator_off_write = &_3c400->tme_3c400_card[0];
723: }
724:
725: /* all address ranges allow fast reading: */
726: tlb->tme_bus_tlb_emulator_off_read = &_3c400->tme_3c400_card[0];
727: tlb->tme_bus_tlb_rwlock = &_3c400->tme_3c400_rwlock;
728:
729: /* allow reading and writing: */
730: tlb->tme_bus_tlb_cycles_ok = TME_BUS_CYCLE_READ | TME_BUS_CYCLE_WRITE;
731:
732: /* our bus cycle handler: */
733: tlb->tme_bus_tlb_cycle_private = _3c400;
734: tlb->tme_bus_tlb_cycle = _tme_3c400_bus_cycle;
735:
736: return (TME_OK);
737: }
738:
739: /* this makes a new Ethernet connection: */
740: static int
741: _tme_3c400_connection_make(struct tme_connection *conn, unsigned int state)
742: {
743: struct tme_3c400 *_3c400;
744: struct tme_ethernet_connection *conn_eth;
745: struct tme_ethernet_connection *conn_eth_other;
746:
747: /* recover our data structures: */
748: _3c400 = conn->tme_connection_element->tme_element_private;
749: conn_eth = (struct tme_ethernet_connection *) conn;
750: conn_eth_other = (struct tme_ethernet_connection *) conn->tme_connection_other;
751:
752: /* both sides must be Ethernet connections: */
753: assert(conn->tme_connection_type == TME_CONNECTION_ETHERNET);
754: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_ETHERNET);
755:
756: /* we're always set up to answer calls across the connection, so we
757: only have to do work when the connection has gone full, namely
758: taking the other side of the connection: */
759: if (state == TME_CONNECTION_FULL) {
760:
761: /* lock our mutex: */
762: tme_mutex_lock(&_3c400->tme_3c400_mutex);
763:
764: /* save our connection: */
765: _3c400->tme_3c400_eth_connection = conn_eth_other;
766:
767: /* unlock our mutex: */
768: tme_mutex_unlock(&_3c400->tme_3c400_mutex);
769: }
770:
771: return (TME_OK);
772: }
773:
774: /* this breaks a connection: */
775: static int
776: _tme_3c400_connection_break(struct tme_connection *conn, unsigned int state)
777: {
778: abort();
779: }
780:
781: /* this makes a new connection side for a 3c400: */
782: static int
783: _tme_3c400_connections_new(struct tme_element *element,
784: const char * const *args,
785: struct tme_connection **_conns,
786: char **_output)
787: {
788: struct tme_3c400 *_3c400;
789: struct tme_ethernet_connection *conn_eth;
790: struct tme_connection *conn;
791: int rc;
792:
793: /* recover our data structure: */
794: _3c400 = (struct tme_3c400 *) element->tme_element_private;
795:
796: /* make the generic bus device connection side: */
797: rc = tme_bus_device_connections_new(element, args, _conns, _output);
798: if (rc != TME_OK) {
799: return (rc);
800: }
801:
802: /* if we don't have an Ethernet connection, make one: */
803: if (_3c400->tme_3c400_eth_connection == NULL) {
804:
805: /* allocate the new Ethernet connection: */
806: conn_eth = tme_new0(struct tme_ethernet_connection, 1);
807: conn = &conn_eth->tme_ethernet_connection;
808:
809: /* fill in the generic connection: */
810: conn->tme_connection_next = *_conns;
811: conn->tme_connection_type = TME_CONNECTION_ETHERNET;
812: conn->tme_connection_score = tme_ethernet_connection_score;
813: conn->tme_connection_make = _tme_3c400_connection_make;
814: conn->tme_connection_break = _tme_3c400_connection_break;
815:
816: /* fill in the Ethernet connection: */
817: conn_eth->tme_ethernet_connection_config = _tme_3c400_config;
818: conn_eth->tme_ethernet_connection_ctrl = _tme_3c400_ctrl;
819: conn_eth->tme_ethernet_connection_read = _tme_3c400_read;
820:
821: /* return the connection side possibility: */
822: *_conns = conn;
823: }
824:
825: /* done: */
826: return (TME_OK);
827: }
828:
829: /* the new _3c400 function: */
830: TME_ELEMENT_SUB_NEW_DECL(tme_bus_multibus,3c400) {
831: struct tme_3c400 *_3c400;
832: tme_uint8_t arom[TME_ETHERNET_ADDR_SIZE];
833: int arom_ok;
834: int arg_i;
835: int usage;
836:
837: /* check our arguments: */
838: usage = 0;
839: arom_ok = FALSE;
840: arg_i = 1;
841: for (;;) {
842:
843: /* our Ethernet address ROM: */
844: if (TME_ARG_IS(args[arg_i], "ether")
845: && tme_ethernet_addr_parse(args[arg_i + 1], arom) == TME_OK) {
846: arom_ok = TRUE;
847: arg_i += 2;
848: }
849:
850: /* if we ran out of arguments: */
851: else if (args[arg_i] == NULL) {
852:
853: /* we must have been given our Ethernet address ROM: */
854: if (!arom_ok) {
855: usage = TRUE;
856: }
857: break;
858: }
859:
860: /* otherwise this is a bad argument: */
861: else {
862: tme_output_append_error(_output,
863: "%s %s, ",
864: args[arg_i],
865: _("unexpected"));
866: usage = TRUE;
867: break;
868: }
869: }
870:
871: if (usage) {
872: tme_output_append_error(_output,
873: "%s %s ether %s",
874: _("usage:"),
875: args[0],
876: _("ETHERNET-ADDRESS"));
877: return (EINVAL);
878: }
879:
880: /* start the _3c400 structure: */
881: _3c400 = tme_new0(struct tme_3c400, 1);
882: _3c400->tme_3c400_element = element;
883: tme_mutex_init(&_3c400->tme_3c400_mutex);
884: tme_rwlock_init(&_3c400->tme_3c400_rwlock);
885: memcpy(_3c400->tme_3c400_card + TME_3C400_REG_AROM,
886: arom,
887: sizeof(arom));
888:
889: /* initialize our simple bus device descriptor: */
890: assert((TME_3C400_SIZ_CARD & (TME_3C400_SIZ_CARD - 1)) == 0);
891: _3c400->tme_3c400_device.tme_bus_device_element = element;
892: _3c400->tme_3c400_device.tme_bus_device_tlb_fill = _tme_3c400_tlb_fill;
893: _3c400->tme_3c400_device.tme_bus_device_address_last = TME_3C400_SIZ_CARD - 1;
894:
895: /* fill the element: */
896: element->tme_element_private = _3c400;
897: element->tme_element_connections_new = _tme_3c400_connections_new;
898:
899: return (TME_OK);
900: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.