|
|
1.1 root 1: /* $Id: i825x6.c,v 1.5 2005/05/11 00:12:24 fredette Exp $ */
2:
3: /* ic/i825x6.c - implementation of the Intel 825x6 emulation: */
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: i825x6.c,v 1.5 2005/05/11 00:12:24 fredette Exp $");
38:
39: /* includes: */
40: #include <tme/generic/bus-device.h>
41: #include <tme/generic/ethernet.h>
42: #undef TME_I825X6_VERSION
43: #define TME_I825X6_VERSION TME_X_VERSION(0, 0)
44: #include <tme/ic/i825x6.h>
45: #include "i825x6reg.h"
46:
47: /* macros: */
48:
49: /* these get and put values of different sizes. the values *must* be aligned: */
50: #define TME_I825X6_GET16(bytes) tme_letoh_u16(*((const tme_uint16_t *) (bytes)))
51: #define TME_I825X6_PUT16(bytes, val) (*((tme_uint16_t *) (bytes)) = tme_htole_u16(val))
52: #define TME_I82586_GET24(bytes) (tme_letoh_u32(*((const tme_uint32_t *) (bytes))) & 0xffffff)
53:
54: /* these read and write regions using DMA: */
55: #define TME_I825X6_READ(address, v) \
56: do { \
57: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device, \
58: (address), \
59: sizeof(v), \
60: (tme_uint8_t *) &(v), \
61: TME_I825X6_LOCKS_DEFAULT); \
62: assert (rc == TME_OK); \
63: } while (/* CONSTCOND */ 0)
64: #define TME_I825X6_WRITE(address, v) \
65: do { \
66: rc = tme_bus_device_dma_write_16(&i825x6->tme_i825x6_device, \
67: (address), \
68: sizeof(v), \
69: (const tme_uint8_t *) &(v), \
70: TME_I825X6_LOCKS_DEFAULT); \
71: assert (rc == TME_OK); \
72: } while (/* CONSTCOND */ 0)
73:
74: /* these read and write values of different sizes using DMA: */
75: #define TME_I825X6_READ16(address, v) \
76: do { \
77: TME_I825X6_READ(address, value16); \
78: v = TME_I825X6_GET16(&value16); \
79: } while (/* CONSTCOND */ 0)
80: #define TME_I82586_READ24(address, v) \
81: do { \
82: TME_I825X6_READ(address, value32); \
83: v = TME_I82586_GET24(&value32); \
84: } while (/* CONSTCOND */ 0)
85: #define TME_I825X6_WRITE16(address, v) \
86: do { \
87: TME_I825X6_PUT16(&value16, v); \
88: TME_I825X6_WRITE(address, value16); \
89: } while (/* CONSTCOND */ 0)
90:
91: /* the "reset" stat_cus_rus_t value: */
92: #define TME_I825X6_CA_RESET (0xffff)
93:
94: /* the address of the idle "Command Block": */
95: #define TME_I825X6_CB_ADDRESS_IDLE (0xffffffff)
96:
97: /* an undefined Receive Unit address: */
98: #define TME_I825X6_RU_ADDRESS_UNDEF (0xffffffff)
99:
100: /* an undefined Receive Unit offset: */
101: #define TME_I825X6_RU_OFFSET_UNDEF (0xffff)
102:
103: /* the default locks: */
104: #define TME_I825X6_LOCKS_DEFAULT (0)
105:
106: /* the size of the TLB entry hash: */
107: #define TME_I825X6_TLB_HASH_SIZE (512)
108:
109: /* the callout flags: */
110: #define TME_I825X6_CALLOUTS_CHECK (0)
111: #define TME_I825X6_CALLOUTS_RUNNING TME_BIT(0)
112: #define TME_I825X6_CALLOUTS_MASK (-2)
113: #define TME_I825X6_CALLOUT_CTRL TME_BIT(1)
114: #define TME_I825X6_CALLOUT_CONFIG TME_BIT(2)
115: #define TME_I825X6_CALLOUT_READ TME_BIT(3)
116: #define TME_I825X6_CALLOUT_INT TME_BIT(4)
117: #define TME_I825X6_CALLOUT_CA TME_BIT(5)
118: #define TME_I825X6_CALLOUT_CU TME_BIT(6)
119:
120: /* structures: */
121:
122: /* an rx buffer: */
123: struct tme_i825x6_rx_buffer {
124:
125: /* the generic ethernet frame chunk. this must be first, since we
126: abuse its tme_ethernet_frame_chunk_next for our own next pointer: */
127: struct tme_ethernet_frame_chunk tme_i825x6_rx_buffer_frame_chunk;
128: #define TME_I825X6_RX_BUFFER_NEXT(rx_buffer) \
129: (*((struct tme_i825x6_rx_buffer **) &(rx_buffer)->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_next))
130:
131: /* when this is TME_I825X6_RU_ADDRESS_UNDEF, this rx buffer was made
132: from a fast-write TLB entry, and the generic ethernet frame chunk
133: points directly into the fast-write memory. otherwise, the
134: generic ethernet frame chunk points to a private intermediate
135: buffer, and this is the bus address to DMA the buffer back to: */
136: tme_uint32_t tme_i825x6_rx_buffer_rb_address;
137:
138: /* when this is not TME_I825X6_RU_ADDRESS_UNDEF, this rx buffer
139: finishes filling the buffer attached to the Receive Buffer
140: Descriptor at this address, and signals the receiver to update
141: that descriptor's Size field: */
142: tme_uint32_t tme_i825x6_rx_buffer_rbd_address;
143: };
144:
145: /* the chip: */
146: struct tme_i825x6 {
147:
148: /* our simple bus device header: */
149: struct tme_bus_device tme_i825x6_device;
150: #define tme_i825x6_element tme_i825x6_device.tme_bus_device_element
151:
152: /* the Ethernet connection: */
153: struct tme_ethernet_connection *tme_i825x6_eth_connection;
154:
155: /* the mutex protecting the chip: */
156: tme_mutex_t tme_i825x6_mutex;
157:
158: /* the callout flags: */
159: int tme_i825x6_callout_flags;
160:
161: /* our DMA TLB hash: */
162: TME_ATOMIC(struct tme_bus_tlb *, tme_i825x6_tlb_hash);
163:
164: /* the i825x6 bus signals: */
165: struct tme_bus_signals tme_i825x6_bus_signals;
166:
167: /* the rx buffer free list: */
168: struct tme_i825x6_rx_buffer *tme_i825x6_rx_buffer_free_list;
169:
170: /* this is nonzero if the next CA follows RESET: */
171: int tme_i825x6_ca_follows_reset;
172:
173: /* the Ethernet addresses. there are always at least two addresses
174: in this array - the broadcast address and the Individual Address,
175: in that order: */
176: unsigned int tme_i825x6_address_count;
177: tme_uint8_t *tme_i825x6_addresses;
178:
179: /* the i82586 AL-LOC value: */
180: int tme_i825x6_al_loc;
181:
182: /* the i82586 PRM value: */
183: int tme_i825x6_prm;
184:
185: /* the i82586 and 32-bit segmented i82596 SCB base: */
186: tme_uint32_t tme_i825x6_scb_base;
187:
188: /* the SCB address: */
189: tme_uint32_t tme_i825x6_scb_address;
190:
191: /* the SCB status word: */
192: tme_uint16_t tme_i825x6_stat_cus_rus_t;
193:
194: /* the SCB Command Unit Command: */
195: tme_uint16_t tme_i825x6_cuc;
196:
197: /* the CB address: */
198: tme_uint32_t tme_i825x6_cb_address;
199:
200: /* the CB status word: */
201: tme_uint16_t tme_i825x6_c_b_ok_a;
202:
203: /* the CB command word: */
204: tme_uint16_t tme_i825x6_el_s_i_cmd;
205:
206: /* the next CB address: */
207: tme_uint32_t tme_i825x6_cb_address_next;
208:
209: /* the RFD address: */
210: tme_uint32_t tme_i825x6_rfd_address;
211:
212: /* the Free Buffer List: */
213: struct tme_i825x6_rx_buffer *tme_i825x6_fbl;
214:
215: /* the size of all buffers on the Free Buffer List: */
216: tme_uint32_t tme_i825x6_fbl_size;
217:
218: /* the address of the offset of the next free RBD: */
219: tme_uint32_t tme_i825x6_rbd_offset_address;
220: };
221:
222: /* prototypes: */
223: static void _tme_i825x6_abort_ru _TME_P((struct tme_i825x6 *));
224:
225: /* globals: */
226: static const struct tme_bus_signals _tme_i825x6_bus_signals = TME_BUS_SIGNALS_I825X6;
227:
228: /* this resets the i825x6: */
229: static void
230: _tme_i825x6_reset(struct tme_i825x6 *i825x6)
231: {
232:
233: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle,
234: 100, TME_OK,
235: (&i825x6->tme_i825x6_element->tme_element_log_handle,
236: "reset"));
237:
238: /* clear all pending callouts: */
239: i825x6->tme_i825x6_callout_flags &= TME_I825X6_CALLOUTS_MASK;
240:
241: /* abort the Receive Unit: */
242: _tme_i825x6_abort_ru(i825x6);
243:
244: /* the Receive Unit is now Idle: */
245: i825x6->tme_i825x6_stat_cus_rus_t
246: = ((i825x6->tme_i825x6_stat_cus_rus_t
247: & ~TME_I82586_SCB_RUS_MASK)
248: | TME_I825X6_SCB_RUS_IDLE);
249:
250: /* we have no packet to transmit: */
251: i825x6->tme_i825x6_el_s_i_cmd = TME_I825X6_CB_CMD_NOP;
252:
253: /* if the interrupt line is currently asserted, negate it: */
254: if (i825x6->tme_i825x6_stat_cus_rus_t
255: & TME_I825X6_SCB_STAT_MASK) {
256: i825x6->tme_i825x6_stat_cus_rus_t &= ~TME_I825X6_SCB_STAT_MASK;
257: i825x6->tme_i825x6_callout_flags |= TME_I825X6_CALLOUT_INT;
258: }
259:
260: /* initialize the address list to match two addresses - the
261: broadcast address, and the Individual Address (which is
262: initially the same as the broadcast address): */
263: i825x6->tme_i825x6_address_count = 2;
264: memcpy (i825x6->tme_i825x6_addresses,
265: &tme_ethernet_addr_broadcast[0],
266: TME_ETHERNET_ADDR_SIZE);
267: memcpy (i825x6->tme_i825x6_addresses + TME_ETHERNET_ADDR_SIZE,
268: &tme_ethernet_addr_broadcast[0],
269: TME_ETHERNET_ADDR_SIZE);
270:
271: /* the next CA follows RESET: */
272: i825x6->tme_i825x6_ca_follows_reset = TRUE;
273: }
274:
275: /* this hashes an address into a TLB entry: */
276: static struct tme_bus_tlb *
277: _tme_i825x6_tlb_hash(void *_i825x6,
278: tme_bus_addr_t linear_address,
279: unsigned int cycles)
280: {
281: struct tme_i825x6 *i825x6;
282:
283: /* recover our data structure: */
284: i825x6 = (struct tme_i825x6 *) _i825x6;
285:
286: /* return the TLB entry: */
287: return (TME_ATOMIC_READ(struct tme_bus_tlb *, i825x6->tme_i825x6_tlb_hash)
288: + ((linear_address >> 10) & (TME_I825X6_TLB_HASH_SIZE - 1)));
289: }
290:
291: /* this locks the mutex: */
292: static void
293: _tme_i825x6_lock(void *_i825x6,
294: unsigned int locks)
295: {
296: struct tme_i825x6 *i825x6;
297:
298: /* recover our data structure: */
299: i825x6 = (struct tme_i825x6 *) _i825x6;
300:
301: /* lock the mutex: */
302: tme_mutex_lock(&i825x6->tme_i825x6_mutex);
303: }
304:
305: /* this unlocks the mutex: */
306: static void
307: _tme_i825x6_unlock(void *_i825x6,
308: unsigned int locks)
309: {
310: struct tme_i825x6 *i825x6;
311:
312: /* recover our data structure: */
313: i825x6 = (struct tme_i825x6 *) _i825x6;
314:
315: /* unlock the mutex: */
316: tme_mutex_unlock(&i825x6->tme_i825x6_mutex);
317: }
318:
319: /* this frees an rx buffer: */
320: static struct tme_i825x6_rx_buffer *
321: _tme_i825x6_rx_buffer_free(struct tme_i825x6 *i825x6,
322: struct tme_i825x6_rx_buffer *rx_buffer)
323: {
324: struct tme_i825x6_rx_buffer *rx_buffer_next;
325:
326: /* get the next rx buffer: */
327: rx_buffer_next = TME_I825X6_RX_BUFFER_NEXT(rx_buffer);
328:
329: /* put this rx buffer on the free list: */
330: TME_I825X6_RX_BUFFER_NEXT(rx_buffer) = i825x6->tme_i825x6_rx_buffer_free_list;
331: i825x6->tme_i825x6_rx_buffer_free_list = rx_buffer;
332:
333: /* return the next rx buffer: */
334: return (rx_buffer_next);
335: }
336:
337: /* this allocates a rx buffer: */
338: static struct tme_i825x6_rx_buffer *
339: _tme_i825x6_rx_buffer_new(struct tme_i825x6 *i825x6,
340: struct tme_i825x6_rx_buffer ***__prev)
341: {
342: struct tme_i825x6_rx_buffer *rx_buffer, **_prev;
343:
344: /* if the free list is not empty: */
345: rx_buffer = i825x6->tme_i825x6_rx_buffer_free_list;
346: if (rx_buffer != NULL) {
347:
348: /* remove this rx buffer from the free list: */
349: i825x6->tme_i825x6_rx_buffer_free_list = TME_I825X6_RX_BUFFER_NEXT(rx_buffer);
350: }
351:
352: /* otherwise, the free list is empty: */
353: else {
354:
355: /* allocate a new rx buffer: */
356: rx_buffer = tme_new(struct tme_i825x6_rx_buffer, 1);
357:
358: /* treat this as an old fast-write TLB entry: */
359: rx_buffer->tme_i825x6_rx_buffer_rb_address = TME_I825X6_RU_ADDRESS_UNDEF;
360: }
361:
362: /* add this new rx buffer to the list: */
363: _prev = *__prev;
364: *_prev = rx_buffer;
365: _prev = &TME_I825X6_RX_BUFFER_NEXT(rx_buffer);
366: *__prev = _prev;
367:
368: /* return the new buffer: */
369: return (rx_buffer);
370: }
371:
372: /* given a bus address and a size, this adds rx buffers to a list: */
373: static struct tme_i825x6_rx_buffer *
374: _tme_i825x6_rx_buffers_add(struct tme_i825x6 *i825x6,
375: tme_uint32_t address_init,
376: tme_uint32_t size,
377: struct tme_i825x6_rx_buffer ***__prev)
378: {
379: struct tme_i825x6_rx_buffer *rx_buffer, **_prev;
380: struct tme_bus_tlb *tlb, tlb_local;
381: struct tme_bus_connection *conn_bus;
382: tme_bus_addr_t count_minus_one, count;
383: tme_bus_addr_t tlb_addr_last;
384: int err;
385:
386: /* recover the rx buffers list: */
387: _prev = *__prev;
388:
389: /* there isn't a last rx buffer yet: */
390: rx_buffer = NULL;
391:
392: /* loop while we have more addresses to cover: */
393: for (; size > 0; ) {
394:
395: /* hash this address into a TLB entry: */
396: tlb = _tme_i825x6_tlb_hash(i825x6,
397: address_init,
398: TME_BUS_CYCLE_WRITE);
399:
400: /* if this TLB entry doesn't cover this address, or if it doesn't
401: allow writing, reload it: */
402: tlb_addr_last = TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last);
403: if (address_init < TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first)
404: || address_init > tlb_addr_last
405: || (tlb->tme_bus_tlb_emulator_off_write == TME_EMULATOR_OFF_UNDEF
406: && !(tlb->tme_bus_tlb_cycles_ok & TME_BUS_CYCLE_WRITE))) {
407:
408: /* reserve this TLB entry: */
409: tme_bus_tlb_reserve(tlb, &tlb_local);
410: tlb = &tlb_local;
411:
412: /* get our bus connection: */
413: conn_bus = TME_ATOMIC_READ(struct tme_bus_connection *,
414: i825x6->tme_i825x6_device.tme_bus_device_connection);
415:
416: /* unlock the mutex: */
417: tme_mutex_unlock(&i825x6->tme_i825x6_mutex);
418:
419: /* reload the TLB entry: */
420: err = (*conn_bus->tme_bus_tlb_fill)
421: (conn_bus,
422: tlb,
423: address_init,
424: TME_BUS_CYCLE_WRITE);
425:
426: /* lock the mutex: */
427: tme_mutex_lock(&i825x6->tme_i825x6_mutex);
428:
429: /* XXX we could create a poison frame chunk instead of
430: aborting: */
431: if (err != TME_OK) {
432: abort();
433: }
434:
435: /* the TLB entry must cover this address and allow writing: */
436: tlb_addr_last = TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_bus_tlb_addr_last);
437: assert (address_init >= TME_ATOMIC_READ(tme_bus_addr_t, tlb->tme_bus_tlb_addr_first)
438: && address_init <= tlb_addr_last
439: && (tlb->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF
440: || (tlb->tme_bus_tlb_cycles_ok & TME_BUS_CYCLE_WRITE)));
441:
442: /* store the TLB entry: */
443: tme_bus_tlb_back(tlb);
444: }
445:
446: /* see how many addresses we can cover with this TLB entry,
447: starting at this address: */
448: count_minus_one = (tlb_addr_last - address_init);
449: count_minus_one = TME_MIN(count_minus_one,
450: (size - 1));
451: count = count_minus_one + 1;
452: assert (count != 0);
453:
454: /* allocate another rx buffer: */
455: rx_buffer = _tme_i825x6_rx_buffer_new(i825x6, &_prev);
456:
457: /* if this TLB entry allows fast writing: */
458: if (tlb->tme_bus_tlb_emulator_off_write != TME_EMULATOR_OFF_UNDEF) {
459:
460: /* if this rx buffer was previously a slow rx buffer, free its
461: chunk buffer: */
462: if (rx_buffer->tme_i825x6_rx_buffer_rb_address != TME_I825X6_RU_ADDRESS_UNDEF) {
463: tme_free(rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes);
464: }
465:
466: /* this is a fast rx buffer: */
467: rx_buffer->tme_i825x6_rx_buffer_rb_address = TME_I825X6_RU_ADDRESS_UNDEF;
468: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes
469: = tlb->tme_bus_tlb_emulator_off_write + address_init;
470: }
471:
472: /* otherwise, this TLB entry does not allow fast writing: */
473: else {
474:
475: /* if this rx buffer was previously a fast rx buffer,
476: allocate a new chunk buffer: */
477: if (rx_buffer->tme_i825x6_rx_buffer_rb_address == TME_I825X6_RU_ADDRESS_UNDEF) {
478: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes
479: = tme_new(tme_uint8_t,
480: count);
481: }
482:
483: /* otherwise, if this rx buffer was previously a slow receive
484: buffer, with a chunk buffer smaller than what we need,
485: reallocate the chunk buffer: */
486: else if (rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes_count
487: < count) {
488: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes
489: = tme_renew(tme_uint8_t,
490: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes,
491: count);
492: }
493:
494: /* this is a slow frame chunk: */
495: rx_buffer->tme_i825x6_rx_buffer_rb_address = address_init;
496: }
497:
498: /* finish this rx buffer: */
499: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes_count = count;
500: rx_buffer->tme_i825x6_rx_buffer_rbd_address = TME_I825X6_RU_ADDRESS_UNDEF;
501:
502: /* update the address and size: */
503: address_init += count;
504: size -= count;
505: }
506:
507: /* update the rx buffers list end: */
508: *__prev = _prev;
509:
510: /* return the last rx buffer: */
511: return (rx_buffer);
512: }
513:
514: /* this refills the Free Buffer List: */
515: static tme_uint16_t
516: _tme_i825x6_fbl_refill(struct tme_i825x6 *i825x6, int from_rfd)
517: {
518: struct tme_i825x6_rx_buffer *rx_buffer, **_prev;
519: tme_uint32_t fbl_size;
520: tme_uint32_t rbd_offset_address, rbd_address, rb_address;
521: tme_uint16_t rbd_offset, rbd_offset_first;
522: tme_uint16_t el_p_size;
523: tme_uint16_t size;
524: tme_uint32_t value32;
525: tme_uint16_t value16;
526: int rc;
527:
528: /* assume that there are no free Receive Buffer Descriptors: */
529: rbd_offset_first = TME_I825X6_RU_OFFSET_UNDEF;
530:
531: /* find the end of the Free Buffer List: */
532: for (_prev = &i825x6->tme_i825x6_fbl;
533: (rx_buffer = *_prev) != NULL;
534: _prev = &TME_I825X6_RX_BUFFER_NEXT(rx_buffer)) {
535:
536: /* if we don't have the first free Receive Buffer Descriptor yet,
537: and this is the last rx buffer for a Receive Buffer, its
538: Receive Buffer Descriptor is the first free one: */
539: rbd_address = rx_buffer->tme_i825x6_rx_buffer_rbd_address;
540: if (rbd_offset_first == TME_I825X6_RU_OFFSET_UNDEF
541: && rbd_address != TME_I825X6_RU_ADDRESS_UNDEF) {
542: rbd_offset_first = rbd_address - i825x6->tme_i825x6_scb_base;
543: }
544: }
545:
546: /* get the address of the next RBD offset: */
547: rbd_offset_address = i825x6->tme_i825x6_rbd_offset_address;
548:
549: /* stop now if the address of the next RBD offset is undefined: */
550: if (rbd_offset_address == TME_I825X6_RU_ADDRESS_UNDEF) {
551: return (rbd_offset_first);
552: }
553:
554: /* get the current size of the Free Buffer List: */
555: fbl_size = i825x6->tme_i825x6_fbl_size;
556:
557: /* turn Receive Buffers into rx buffers on the Free Buffer List,
558: until the Free Buffer List has a maximum-sized Ethernet frame's
559: worth of buffers: */
560: for (; fbl_size < TME_ETHERNET_FRAME_MAX; ) {
561:
562: /* read in the Receive Buffer Descriptor offset: */
563: TME_I825X6_READ16(rbd_offset_address,
564: rbd_offset);
565:
566: /* if this Receive Buffer Descriptor offset is in an RFD, stop if
567: the offset is all-bits-one, indicating no RBDs: */
568: if (from_rfd
569: && rbd_offset == TME_I825X6_RU_OFFSET_UNDEF) {
570: break;
571: }
572: from_rfd = FALSE;
573:
574: /* if we don't have the first free Receive Buffer Descriptor yet,
575: this is it: */
576: if (rbd_offset_first == TME_I825X6_RU_OFFSET_UNDEF) {
577: rbd_offset_first = rbd_offset;
578: }
579:
580: /* make the Receive Buffer Descriptor address: */
581: rbd_address = i825x6->tme_i825x6_scb_base + rbd_offset;
582:
583: /* read in the Receive Buffer address: */
584: TME_I82586_READ24((rbd_address
585: + TME_I82586_RBD_RB_ADDRESS),
586: rb_address);
587:
588: /* read in the EL_P_SIZE field: */
589: TME_I825X6_READ16((rbd_address
590: + TME_I82586_RBD_EL_P_SIZE),
591: el_p_size);
592:
593: /* get the size of this Receive Buffer: */
594: size = el_p_size & TME_I825X6_RBD_SIZE_MASK;
595:
596: /* if this Receive Buffer has zero size, stop now. this can
597: happen with NetBSD 1.6.x, which zeroes and reinitializes the
598: memory for the i825x6 without stopping the Receive Unit: */
599: if (size == 0) {
600:
601: /* log a complaint: */
602: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle,
603: 0, EBADF,
604: (&i825x6->tme_i825x6_element->tme_element_log_handle,
605: _("caught an empty Receive Buffer")));
606:
607: break;
608: }
609:
610: /* add this Receive Buffer to the rx buffers: */
611: rx_buffer = _tme_i825x6_rx_buffers_add(i825x6,
612: rb_address,
613: size,
614: &_prev);
615:
616: /* on the last rx buffer for a Receive Buffer, set the address of
617: the Receive Buffer Descriptor, so we can update its size field: */
618: rx_buffer->tme_i825x6_rx_buffer_rbd_address = rbd_address;
619:
620: /* update the amount of space on the Free Buffer list: */
621: fbl_size += size;
622:
623: /* if this is the last Receive Buffer Descriptor: */
624: if (el_p_size & TME_I825X6_RBD_EL) {
625:
626: /* the address of the next RBD offset is undefined: */
627: rbd_offset_address = TME_I825X6_RU_ADDRESS_UNDEF;
628:
629: /* stop now: */
630: break;
631: }
632:
633: /* get the address of the next RBD offset: */
634: rbd_offset_address
635: = (rbd_address
636: + TME_I82586_RBD_RBD_OFFSET);
637: }
638:
639: /* terminate the Free Buffer List: */
640: *_prev = NULL;
641:
642: /* save the current size of the Free Buffer List: */
643: i825x6->tme_i825x6_fbl_size = fbl_size;
644:
645: /* save the address of the next RBD offset: */
646: i825x6->tme_i825x6_rbd_offset_address = rbd_offset_address;
647:
648: /* return the address of the first free Receive Buffer Descriptor: */
649: return (rbd_offset_first);
650: }
651:
652: /* this aborts the Receive Unit: */
653: static void
654: _tme_i825x6_abort_ru(struct tme_i825x6 *i825x6)
655: {
656: struct tme_i825x6_rx_buffer *rx_buffer;
657:
658: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle,
659: 100, TME_OK,
660: (&i825x6->tme_i825x6_element->tme_element_log_handle,
661: "RU abort"));
662:
663: /* free the Free Buffer List: */
664: for (rx_buffer = i825x6->tme_i825x6_fbl;
665: rx_buffer != NULL;
666: rx_buffer = _tme_i825x6_rx_buffer_free(i825x6, rx_buffer));
667:
668: /* the Receive Unit now has no resources: */
669: i825x6->tme_i825x6_rfd_address = TME_I825X6_RU_ADDRESS_UNDEF;
670: i825x6->tme_i825x6_rbd_offset_address = TME_I825X6_RU_ADDRESS_UNDEF;
671: i825x6->tme_i825x6_fbl = NULL;
672: i825x6->tme_i825x6_fbl_size = 0;
673: }
674:
675: /* this does a DMA directly into transmit frame chunks: */
676: static int
677: _tme_i825x6_chunks_dma_tx(struct tme_i825x6 *i825x6,
678: struct tme_ethernet_frame_chunk *frame_chunks,
679: tme_uint32_t address,
680: tme_uint32_t size)
681: {
682: tme_uint32_t count;
683: int rc;
684:
685: /* while we have bytes left to DMA: */
686: for (; size > 0; ) {
687:
688: /* get the count of bytes to copy in this iteration: */
689: count = frame_chunks->tme_ethernet_frame_chunk_bytes_count;
690: if (count == 0) {
691: break;
692: }
693: count = TME_MIN(count, size);
694:
695: /* do the copy: */
696: /* XXX FIXME this assumes an i82586: */
697: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device,
698: address,
699: count,
700: frame_chunks->tme_ethernet_frame_chunk_bytes,
701: TME_I825X6_LOCKS_DEFAULT);
702: if (rc != TME_OK) {
703: return (rc);
704: }
705:
706: /* update: */
707: size -= count;
708: frame_chunks->tme_ethernet_frame_chunk_bytes += count;
709: if ((frame_chunks->tme_ethernet_frame_chunk_bytes_count -= count) == 0
710: && frame_chunks->tme_ethernet_frame_chunk_next != NULL) {
711: *frame_chunks = *frame_chunks->tme_ethernet_frame_chunk_next;
712: }
713: }
714:
715: /* success: */
716: return (TME_OK);
717: }
718:
719: /* this does a memcpy directly into transmit frame chunks: */
720: static void
721: _tme_i825x6_chunks_mem_tx(struct tme_ethernet_frame_chunk *frame_chunks,
722: const tme_uint8_t *data,
723: unsigned int size)
724: {
725: unsigned int count;
726:
727: /* while we have bytes left to copy: */
728: for (; size > 0; ) {
729:
730: /* get the count of bytes to copy in this iteration: */
731: count = frame_chunks->tme_ethernet_frame_chunk_bytes_count;
732: if (count == 0) {
733: break;
734: }
735: count = TME_MIN(count, size);
736:
737: /* do the copy: */
738: memcpy(frame_chunks->tme_ethernet_frame_chunk_bytes,
739: data,
740: count);
741:
742: /* update: */
743: size -= count;
744: frame_chunks->tme_ethernet_frame_chunk_bytes += count;
745: if ((frame_chunks->tme_ethernet_frame_chunk_bytes_count -= count) == 0
746: && frame_chunks->tme_ethernet_frame_chunk_next != NULL) {
747: *frame_chunks = *frame_chunks->tme_ethernet_frame_chunk_next;
748: }
749: }
750: }
751:
752: /* this is called to handle a Channel Attention (CA) callout: */
753: static tme_uint16_t
754: _tme_i825x6_callout_ca(struct tme_i825x6 *i825x6, tme_uint16_t stat_cus_rus_t)
755: {
756: tme_uint8_t scp[TME_I825X6_SCP_SIZE];
757: tme_uint32_t iscp_address, rfd_offset;
758: tme_uint8_t iscp[TME_I825X6_ISCP_SIZE];
759: tme_uint16_t ack_cuc_r_ruc;
760: tme_uint16_t cuc;
761: tme_uint16_t value16;
762: tme_uint16_t rbd_offset_first;
763: int rc;
764:
765: /* if this CA follows RESET: */
766: if (i825x6->tme_i825x6_ca_follows_reset) {
767:
768: /* the next CA will not follow RESET: */
769: i825x6->tme_i825x6_ca_follows_reset = FALSE;
770:
771: /* read in the SCP: */
772: TME_I825X6_READ(TME_I825X6_SCP_ADDRESS, scp);
773:
774: /* check the SYSBUS byte: */
775: assert ((scp[TME_I825X6_SCP_SYSBUS]
776: & TME_I825X6_SCP_SYSBUS_MODE_MASK)
777: == TME_I825X6_SCP_SYSBUS_MODE_82586);
778:
779: /* get the ISCP address: */
780: iscp_address = TME_I82586_GET24(&scp[TME_I825X6_SCP_ISCP_ADDRESS]);
781:
782: /* read in the ISCP: */
783: TME_I825X6_READ(iscp_address, iscp);
784:
785: /* get the SCB base and SCB address: */
786: i825x6->tme_i825x6_scb_base = TME_I82586_GET24(&iscp[TME_I82586_ISCP_SCB_BASE]);
787: i825x6->tme_i825x6_scb_address
788: = (i825x6->tme_i825x6_scb_base
789: + TME_I825X6_GET16(&iscp[TME_I82586_ISCP_SCB_OFFSET]));
790:
791: /* "The 82596 clears BUSY": */
792: iscp[TME_I825X6_ISCP_BUSY] = 0;
793: TME_I825X6_WRITE((iscp_address
794: + TME_I825X6_ISCP_BUSY),
795: iscp[TME_I825X6_ISCP_BUSY]);
796:
797: /* "The 82596 ... sets CX and CNR to equal 1 in the SCB": */
798: stat_cus_rus_t
799: = (TME_I825X6_SCB_STAT_CX
800: | TME_I825X6_SCB_STAT_CNA
801: | TME_I825X6_SCB_CUS_IDLE
802: | TME_I825X6_SCB_RUS_IDLE);
803:
804: /* "The 82596 ... sends an interrupt to the CPU": */
805: i825x6->tme_i825x6_callout_flags = TME_I825X6_CALLOUTS_RUNNING | TME_I825X6_CALLOUT_INT;
806: }
807:
808: /* otherwise, this CA does not follow RESET: */
809: else {
810:
811: /* read in the SCB command word: */
812: TME_I825X6_READ16((i825x6->tme_i825x6_scb_address
813: + TME_I825X6_SCB_ACK_CUC_R_RUC),
814: ack_cuc_r_ruc);
815:
816: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle,
817: 100, TME_OK,
818: (&i825x6->tme_i825x6_element->tme_element_log_handle,
819: "SCB command 0x%04x",
820: ack_cuc_r_ruc));
821:
822: /* handle a Reset: */
823: if (ack_cuc_r_ruc & TME_I825X6_SCB_RESET) {
824: _tme_i825x6_reset(i825x6);
825: return (TME_I825X6_CA_RESET);
826: }
827:
828: /* clear any acknowledged Status bits: */
829: stat_cus_rus_t
830: &= ~(ack_cuc_r_ruc
831: & TME_I825X6_SCB_STAT_MASK);
832:
833: /* if the Command Unit Command isn't a NOP: */
834: cuc = (ack_cuc_r_ruc
835: & TME_I825X6_SCB_CUC_MASK);
836: if (cuc != TME_I825X6_SCB_CUC_NOP) {
837:
838: /* set this Command Unit Command: */
839: i825x6->tme_i825x6_cuc = cuc;
840:
841: /* if the Command Unit Command is an Abort, or if the Command
842: Unit isn't already Active, run the Command Unit: */
843: if ((cuc == TME_I825X6_SCB_CUC_ABORT)
844: || ((stat_cus_rus_t
845: & TME_I825X6_SCB_CUS_MASK)
846: != TME_I825X6_SCB_CUS_ACTIVE)) {
847: i825x6->tme_i825x6_callout_flags |= TME_I825X6_CALLOUT_CU;
848: }
849: }
850:
851: /* dispatch on the Receive Unit command: */
852: switch (ack_cuc_r_ruc & TME_I825X6_SCB_RUC_MASK) {
853:
854: case TME_I825X6_SCB_RUC_NOP:
855: break;
856:
857: case TME_I825X6_SCB_RUC_START:
858:
859: /* if the Receive Unit is still Ready or Suspended: */
860: switch (stat_cus_rus_t & TME_I82586_SCB_RUS_MASK) {
861: case TME_I825X6_SCB_RUS_READY:
862: case TME_I825X6_SCB_RUS_SUSPENDED:
863:
864: /* abort the Receive Unit: */
865: _tme_i825x6_abort_ru(i825x6);
866: break;
867:
868: case TME_I825X6_SCB_RUS_ERESOURCE:
869: case TME_I825X6_SCB_RUS_IDLE:
870: break;
871:
872: default:
873: abort();
874: }
875:
876: /* the Receive Unit must have no resources: */
877: assert (i825x6->tme_i825x6_rfd_address == TME_I825X6_RU_ADDRESS_UNDEF);
878: assert (i825x6->tme_i825x6_rbd_offset_address == TME_I825X6_RU_ADDRESS_UNDEF);
879: assert (i825x6->tme_i825x6_fbl == NULL && i825x6->tme_i825x6_fbl_size == 0);
880:
881: /* get the RFD offset from the SCB: */
882: TME_I825X6_READ16((i825x6->tme_i825x6_scb_address
883: + TME_I82586_SCB_RFA_OFFSET),
884: rfd_offset);
885:
886: /* if the RFD offset is defined: */
887: if (rfd_offset != TME_I825X6_RU_OFFSET_UNDEF) {
888:
889: /* set the RFD address: */
890: i825x6->tme_i825x6_rfd_address
891: = (i825x6->tme_i825x6_scb_base
892: + rfd_offset);
893:
894: /* set the RBD offset address: */
895: i825x6->tme_i825x6_rbd_offset_address
896: = (i825x6->tme_i825x6_rfd_address
897: + TME_I82586_RFD_RBD_OFFSET);
898:
899: /* refill the Free Buffer List: */
900: rbd_offset_first = _tme_i825x6_fbl_refill(i825x6, TRUE);
901:
902: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle,
903: 100, TME_OK,
904: (&i825x6->tme_i825x6_element->tme_element_log_handle,
905: "RU start RFD 0x%06x RBD 0x%04x",
906: i825x6->tme_i825x6_rfd_address,
907: rbd_offset_first));
908: }
909:
910: /* FALLTHROUGH: */
911: case TME_I825X6_SCB_RUC_RESUME:
912:
913: /* the Receive Unit is now Ready: */
914: stat_cus_rus_t
915: = ((stat_cus_rus_t
916: & ~TME_I82586_SCB_RUS_MASK)
917: | TME_I825X6_SCB_RUS_READY);
918: break;
919:
920: case TME_I825X6_SCB_RUC_SUSPEND:
921:
922: /* the Receive Unit is now Suspended: */
923: stat_cus_rus_t
924: = ((stat_cus_rus_t
925: & ~TME_I82586_SCB_RUS_MASK)
926: | TME_I825X6_SCB_RUS_SUSPENDED);
927: break;
928:
929: case TME_I825X6_SCB_RUC_ABORT:
930:
931: /* abort the Receive Unit: */
932: _tme_i825x6_abort_ru(i825x6);
933:
934: /* the Receive Unit is now Idle: */
935: stat_cus_rus_t
936: = ((stat_cus_rus_t
937: & ~TME_I82586_SCB_RUS_MASK)
938: | TME_I825X6_SCB_RUS_IDLE);
939: break;
940:
941: default:
942: abort();
943: }
944: }
945:
946: /* always clear the SCB command word after a CA: */
947: TME_I825X6_WRITE16((i825x6->tme_i825x6_scb_address
948: + TME_I825X6_SCB_ACK_CUC_R_RUC),
949: 0);
950:
951: /* return the current status word: */
952: return (stat_cus_rus_t);
953: }
954:
955: /* this is called to handle a Command Unit (CU) callout: */
956: static tme_uint16_t
957: _tme_i825x6_callout_cu(struct tme_i825x6 *i825x6, tme_uint16_t stat_cus_rus_t)
958: {
959: tme_uint16_t cuc;
960: tme_uint16_t el_s_i_cmd;
961: tme_uint16_t mc_count;
962: tme_uint8_t config_bytes[12];
963: unsigned int config_byte_count;
964: unsigned int callouts;
965: tme_uint16_t value16;
966: int rc;
967:
968: /* get the SCB Command Unit Command: */
969: cuc = i825x6->tme_i825x6_cuc;
970:
971: /* if the Command Unit was active, complete the command that it
972: was working on: */
973: if ((stat_cus_rus_t
974: & TME_I825X6_SCB_CUS_MASK)
975: == TME_I825X6_SCB_CUS_ACTIVE) {
976:
977: /* finish the CB status word. clear B, and set C. if the
978: command was aborted, clear OK and set A, else set OK and
979: clear A: */
980: i825x6->tme_i825x6_c_b_ok_a
981: = ((i825x6->tme_i825x6_c_b_ok_a
982: & ~TME_I825X6_FLAG_B)
983: | TME_I825X6_FLAG_C
984: | TME_I825X6_FLAG_OK
985: | TME_I825X6_CB_A);
986: i825x6->tme_i825x6_c_b_ok_a
987: ^= ((cuc
988: == TME_I825X6_SCB_CUC_ABORT)
989: ? TME_I825X6_FLAG_OK
990: : TME_I825X6_CB_A);
991:
992: /* write the CB status word: */
993: TME_I825X6_WRITE16((i825x6->tme_i825x6_cb_address
994: + TME_I825X6_CB_C_B_OK_A),
995: i825x6->tme_i825x6_c_b_ok_a);
996:
997: /* if this command had the I bit set, set CX: */
998: if (i825x6->tme_i825x6_el_s_i_cmd & TME_I825X6_CB_I) {
999: stat_cus_rus_t |= TME_I825X6_SCB_STAT_CX;
1000: }
1001:
1002: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle,
1003: 100, TME_OK,
1004: (&i825x6->tme_i825x6_element->tme_element_log_handle,
1005: "CU finish 0x%06x status 0x%04x",
1006: i825x6->tme_i825x6_cb_address,
1007: i825x6->tme_i825x6_c_b_ok_a));
1008: }
1009:
1010: /* dispatch on the Command Unit command: */
1011: switch (cuc) {
1012:
1013: case TME_I825X6_SCB_CUC_NOP:
1014: break;
1015:
1016: case TME_I825X6_SCB_CUC_START:
1017:
1018: /* get the CBL address: */
1019: TME_I825X6_READ16((i825x6->tme_i825x6_scb_address
1020: + TME_I82586_SCB_CBL_OFFSET),
1021: i825x6->tme_i825x6_cb_address_next);
1022: i825x6->tme_i825x6_cb_address_next += i825x6->tme_i825x6_scb_base;
1023:
1024: /* FALLTHROUGH */
1025: case TME_I825X6_SCB_CUC_RESUME:
1026:
1027: /* the Command Unit is now active: */
1028: stat_cus_rus_t
1029: = ((stat_cus_rus_t
1030: & ~TME_I825X6_SCB_CUS_MASK)
1031: | TME_I825X6_SCB_CUS_ACTIVE);
1032: break;
1033:
1034: case TME_I825X6_SCB_CUC_ABORT:
1035:
1036: /* the Command Unit is now Idle: */
1037: stat_cus_rus_t
1038: = ((stat_cus_rus_t
1039: & ~TME_I825X6_SCB_CUS_MASK)
1040: | TME_I825X6_SCB_CUS_IDLE);
1041: break;
1042:
1043: case TME_I825X6_SCB_CUC_SUSPEND:
1044:
1045: /* the Command Unit is now Suspended: */
1046: stat_cus_rus_t
1047: = ((stat_cus_rus_t
1048: & ~TME_I825X6_SCB_CUS_MASK)
1049: | TME_I825X6_SCB_CUS_SUSPENDED);
1050: break;
1051:
1052: default:
1053: abort();
1054: }
1055:
1056: /* if the Command Unit is not active, return now: */
1057: if ((stat_cus_rus_t
1058: & TME_I825X6_SCB_CUS_MASK)
1059: != TME_I825X6_SCB_CUS_ACTIVE) {
1060: return (stat_cus_rus_t);
1061: }
1062:
1063: /* advance to the next command: */
1064: i825x6->tme_i825x6_cb_address = i825x6->tme_i825x6_cb_address_next;
1065:
1066: /* if there is no next command, the Command Unit is now Idle: */
1067: if (i825x6->tme_i825x6_cb_address == TME_I825X6_CB_ADDRESS_IDLE) {
1068: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle,
1069: 100, TME_OK,
1070: (&i825x6->tme_i825x6_element->tme_element_log_handle,
1071: "CU idle"));
1072: stat_cus_rus_t
1073: = ((stat_cus_rus_t
1074: & ~TME_I825X6_SCB_CUS_MASK)
1075: | TME_I825X6_SCB_CUS_IDLE);
1076: return (stat_cus_rus_t);
1077: }
1078:
1079: /* start the CB status word: */
1080: i825x6->tme_i825x6_c_b_ok_a = TME_I825X6_FLAG_B;
1081: TME_I825X6_WRITE16((i825x6->tme_i825x6_cb_address
1082: + TME_I825X6_CB_C_B_OK_A),
1083: i825x6->tme_i825x6_c_b_ok_a);
1084:
1085: /* get the CB command word: */
1086: TME_I825X6_READ16((i825x6->tme_i825x6_cb_address
1087: + TME_I825X6_CB_EL_S_I_CMD),
1088: i825x6->tme_i825x6_el_s_i_cmd);
1089: el_s_i_cmd = i825x6->tme_i825x6_el_s_i_cmd;
1090:
1091: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle,
1092: 100, TME_OK,
1093: (&i825x6->tme_i825x6_element->tme_element_log_handle,
1094: "CU start 0x%06x el_s_i_cmd 0x%04x",
1095: i825x6->tme_i825x6_cb_address,
1096: el_s_i_cmd));
1097:
1098: /* if EL is set, there is no next Command Block, and when
1099: the Command Unit tries to execute the next command it
1100: will go Idle: */
1101: if (el_s_i_cmd & TME_I825X6_FLAG_EL) {
1102: i825x6->tme_i825x6_cb_address_next = TME_I825X6_CB_ADDRESS_IDLE;
1103: }
1104:
1105: /* otherwise, get the address of the next Command Block: */
1106: else {
1107: TME_I825X6_READ16((i825x6->tme_i825x6_cb_address
1108: + TME_I82586_CB_LINK_OFFSET),
1109: i825x6->tme_i825x6_cb_address_next);
1110: i825x6->tme_i825x6_cb_address_next += i825x6->tme_i825x6_scb_base;
1111: }
1112:
1113: /* if S is set, after the Command Unit executes this command
1114: it will Suspend, else it will stay Active: */
1115: i825x6->tme_i825x6_cuc
1116: = ((el_s_i_cmd & TME_I825X6_FLAG_S)
1117: ? TME_I825X6_SCB_CUC_SUSPEND
1118: : TME_I825X6_SCB_CUC_NOP);
1119:
1120: /* assume that this command will complete now: */
1121: callouts = TME_I825X6_CALLOUT_CU;
1122:
1123: /* dispatch on this command: */
1124: switch (el_s_i_cmd & TME_I825X6_CB_CMD_MASK) {
1125:
1126: case TME_I825X6_CB_CMD_NOP:
1127: break;
1128:
1129: case TME_I825X6_CB_CMD_SETUP_IA:
1130:
1131: /* read in the new Individual Address, into the second element of
1132: the addresses array: */
1133: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device,
1134: (i825x6->tme_i825x6_cb_address
1135: + TME_I82586_CB_X),
1136: TME_ETHERNET_ADDR_SIZE,
1137: (i825x6->tme_i825x6_addresses
1138: + TME_ETHERNET_ADDR_SIZE),
1139: TME_I825X6_LOCKS_DEFAULT);
1140: assert (rc == TME_OK);
1141:
1142: /* call out an Ethernet configuration change: */
1143: callouts |= TME_I825X6_CALLOUT_CONFIG;
1144: break;
1145:
1146: case TME_I825X6_CB_CMD_CONFIGURE:
1147:
1148: /* read in bytes 0 and 1 of the configuration: */
1149: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device,
1150: (i825x6->tme_i825x6_cb_address
1151: + TME_I82586_CB_X),
1152: sizeof(tme_uint16_t),
1153: config_bytes,
1154: TME_I825X6_LOCKS_DEFAULT);
1155: assert (rc == TME_OK);
1156:
1157: /* "In the 82586 mode the maximum number of configuration bytes
1158: is 12. Any number larger than 12 will be reduced to 12 and
1159: any number less than 4 will be increased to 4." */
1160: config_byte_count = (config_bytes[0] & 0x0f);
1161: if (config_byte_count < 4) {
1162: config_byte_count = 4;
1163: }
1164: else if (config_byte_count > 12) {
1165: config_byte_count = 12;
1166: }
1167:
1168: /* read in the remaining bytes of the configuration: */
1169: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device,
1170: (i825x6->tme_i825x6_cb_address
1171: + TME_I82586_CB_X
1172: + sizeof(tme_uint16_t)),
1173: (config_byte_count
1174: - sizeof(tme_uint16_t)),
1175: (config_bytes
1176: + sizeof(tme_uint16_t)),
1177: TME_I825X6_LOCKS_DEFAULT);
1178: assert (rc == TME_OK);
1179:
1180: /* byte 3: */
1181: if (config_byte_count > 3) {
1182:
1183: /* AL-LOC: */
1184: i825x6->tme_i825x6_al_loc = config_bytes[3] & 0x08;
1185:
1186: /* Address Length: */
1187: if ((config_bytes[3] & 0x07) != TME_ETHERNET_ADDR_SIZE) {
1188: abort();
1189: }
1190: }
1191:
1192: /* byte 8: */
1193: if (config_byte_count > 8) {
1194:
1195: /* Promiscuous Mode: */
1196: i825x6->tme_i825x6_prm = config_bytes[8] & 0x01;
1197:
1198: /* call out an Ethernet configuration change: */
1199: callouts |= TME_I825X6_CALLOUT_CONFIG;
1200: }
1201: break;
1202:
1203: case TME_I825X6_CB_CMD_SETUP_MC:
1204:
1205: /* read in the MC COUNT byte count: */
1206: TME_I825X6_READ16((i825x6->tme_i825x6_cb_address
1207: + TME_I82586_CB_X),
1208: mc_count);
1209: mc_count -= (mc_count % TME_ETHERNET_ADDR_SIZE);
1210:
1211: /* reallocate the addresses list, which is always at least two
1212: elements long - the broadcast address and the individual
1213: address: */
1214: i825x6->tme_i825x6_address_count = (2 + (mc_count / TME_ETHERNET_ADDR_SIZE));
1215: i825x6->tme_i825x6_addresses
1216: = tme_renew(tme_uint8_t,
1217: i825x6->tme_i825x6_addresses,
1218: (i825x6->tme_i825x6_address_count
1219: * TME_ETHERNET_ADDR_SIZE));
1220:
1221: /* read in the new Multicast addresses: */
1222: rc = tme_bus_device_dma_read_16(&i825x6->tme_i825x6_device,
1223: (i825x6->tme_i825x6_cb_address
1224: + TME_I82586_CB_X
1225: + sizeof(mc_count)),
1226: mc_count,
1227: (i825x6->tme_i825x6_addresses
1228: + (2
1229: * TME_ETHERNET_ADDR_SIZE)),
1230: TME_I825X6_LOCKS_DEFAULT);
1231: assert (rc == TME_OK);
1232:
1233: /* call out an Ethernet configuration change: */
1234: callouts |= TME_I825X6_CALLOUT_CONFIG;
1235: break;
1236:
1237: case TME_I825X6_CB_CMD_TRANSMIT:
1238:
1239: /* call out only a control change; this command is not
1240: completing now: */
1241: callouts = TME_I825X6_CALLOUT_CTRL;
1242: break;
1243:
1244: case TME_I825X6_CB_CMD_TDR:
1245:
1246: /* write a successful TDR status: */
1247: TME_I825X6_WRITE16((i825x6->tme_i825x6_cb_address
1248: + TME_I82586_CB_X),
1249: TME_I82586_TDR_STATUS_OK);
1250: break;
1251:
1252: case TME_I825X6_CB_CMD_DUMP:
1253: case TME_I825X6_CB_CMD_DIAGNOSE:
1254: abort();
1255: }
1256:
1257: /* add to the callouts and return the current status: */
1258: i825x6->tme_i825x6_callout_flags |= callouts;
1259: return (stat_cus_rus_t);
1260: }
1261:
1262: /* this is called to handle a Receive Unit (RU) callout: */
1263: static tme_uint16_t
1264: _tme_i825x6_callout_ru(struct tme_i825x6 *i825x6, tme_uint16_t stat_cus_rus_t)
1265: {
1266: struct tme_ethernet_connection *conn_eth;
1267: tme_ethernet_fid_t frame_id;
1268: tme_uint16_t el_s_sf;
1269: tme_uint16_t eof_f_act_count;
1270: tme_uint16_t c_b_ok_status;
1271: struct tme_i825x6_rx_buffer *rx_buffers, *rx_buffer, **_prev;
1272: unsigned int rbd_size, rx_buffer_size;
1273: tme_uint32_t rfd_address;
1274: tme_uint16_t rbd_offset_next;
1275: tme_uint16_t discards;
1276: int resid;
1277: int rc;
1278: tme_uint16_t value16;
1279:
1280: /* start a list of rx buffers: */
1281: rx_buffers = NULL;
1282: _prev = &rx_buffers;
1283:
1284: /* start counting the number of bytes in the first Receive Buffer: */
1285: rbd_size = 0;
1286:
1287: /* assume that we have no Receive Frame Descriptor: */
1288: rfd_address = TME_I825X6_RU_ADDRESS_UNDEF;
1289: el_s_sf = 0;
1290:
1291: /* if the Receive Unit is Active and we have a Receive Frame Descriptor: */
1292: if (((stat_cus_rus_t & TME_I82586_SCB_RUS_MASK)
1293: == TME_I825X6_SCB_RUS_READY)
1294: && ((rfd_address = i825x6->tme_i825x6_rfd_address)
1295: != TME_I825X6_RU_ADDRESS_UNDEF)) {
1296:
1297: /* get the flags word: */
1298: TME_I825X6_READ16((rfd_address
1299: + TME_I825X6_RFD_EL_S_SF),
1300: el_s_sf);
1301:
1302: /* if AL-LOC is set to zero, the Ethernet/802.3 MAC header will be
1303: received into the Receive Frame Descriptor: */
1304: if (i825x6->tme_i825x6_al_loc == 0) {
1305:
1306: /* make a set of rx buffers out of the Ethernet header part of
1307: the Receive Frame Descriptor: */
1308: _tme_i825x6_rx_buffers_add(i825x6,
1309: (rfd_address
1310: + TME_I82586_RFD_RBD_ETH_HEADER),
1311: TME_ETHERNET_HEADER_SIZE,
1312: &_prev);
1313:
1314: /* account for the Receive Frame Descriptor header bytes in the
1315: Free Buffer List space and Receive Buffer size calculations: */
1316: i825x6->tme_i825x6_fbl_size += TME_ETHERNET_HEADER_SIZE;
1317: rbd_size = 0 - TME_ETHERNET_HEADER_SIZE;
1318: }
1319:
1320: /* take the Free Buffer List: */
1321: *_prev = i825x6->tme_i825x6_fbl;
1322: }
1323:
1324: /* get the Ethernet connection: */
1325: conn_eth = i825x6->tme_i825x6_eth_connection;
1326:
1327: /* unlock the mutex: */
1328: tme_mutex_unlock(&i825x6->tme_i825x6_mutex);
1329:
1330: /* do the callout: */
1331: resid = (conn_eth == NULL
1332: ? 0
1333: : ((*conn_eth->tme_ethernet_connection_read)
1334: (conn_eth,
1335: &frame_id,
1336: &rx_buffers->tme_i825x6_rx_buffer_frame_chunk,
1337: TME_ETHERNET_READ_NEXT)));
1338:
1339: /* lock the mutex: */
1340: tme_mutex_lock(&i825x6->tme_i825x6_mutex);
1341:
1342: /* if the read failed: */
1343: if (resid <= 0) {
1344:
1345: /* convention dictates that we forget that the connection was
1346: readable, which we already have done by clearing the
1347: CALLOUT_READ flag: */
1348: return (stat_cus_rus_t);
1349: }
1350:
1351: /* mark that we need to loop to callout to read more frames: */
1352: i825x6->tme_i825x6_callout_flags |= TME_I825X6_CALLOUT_READ;
1353:
1354: /* return now if the Receive Unit is Idle: */
1355: if ((stat_cus_rus_t & TME_I82586_SCB_RUS_MASK)
1356: == TME_I825X6_SCB_RUS_IDLE) {
1357: return (stat_cus_rus_t);
1358: }
1359:
1360: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle,
1361: 100, TME_OK,
1362: (&i825x6->tme_i825x6_element->tme_element_log_handle,
1363: "RU RFD 0x%06x el_s_sf 0x%04x",
1364: rfd_address,
1365: el_s_sf));
1366:
1367: /* we must have received more than just headers: */
1368: assert (resid > TME_ETHERNET_HEADER_SIZE);
1369:
1370: /* if we have a Receive Frame Descriptor: */
1371: if (rfd_address != TME_I825X6_RU_ADDRESS_UNDEF) {
1372:
1373: /* walk the rx buffers, stopping early only if we have exhausted
1374: the Ethernet frame *and* we have updated the last Receive
1375: Buffer used to receive it: */
1376: for (rx_buffer = rx_buffers;
1377: (rx_buffer != NULL
1378: && (resid > 0
1379: || rbd_size > 0)); ) {
1380:
1381: /* calculate the number of bytes used in this rx buffer. since
1382: a single Receive Buffer can be split into many rx buffers,
1383: the Ethernet frame may not fill all of them, so this can be
1384: zero: */
1385: rx_buffer_size
1386: = TME_MIN((unsigned int) resid,
1387: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes_count);
1388:
1389: /* this many more bytes have been received into this Receive Buffer: */
1390: rbd_size += rx_buffer_size;
1391:
1392: /* this many more bytes have been accounted for in the Ethernet frame: */
1393: resid -= rx_buffer_size;
1394:
1395: /* if this was a slow frame chunk: */
1396: if (rx_buffer->tme_i825x6_rx_buffer_rb_address
1397: != TME_I825X6_RU_ADDRESS_UNDEF) {
1398:
1399: /* DMA the contents out: */
1400: rc = tme_bus_device_dma_write_16(&i825x6->tme_i825x6_device,
1401: rx_buffer->tme_i825x6_rx_buffer_rb_address,
1402: rx_buffer_size,
1403: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes,
1404: TME_I825X6_LOCKS_DEFAULT);
1405: assert (rc == TME_OK);
1406: }
1407:
1408: /* if this was the last rx buffer for a Receive Buffer: */
1409: if (rx_buffer->tme_i825x6_rx_buffer_rbd_address
1410: != TME_I825X6_RU_ADDRESS_UNDEF) {
1411:
1412: /* make the EOF_F_ACT_COUNT field: */
1413: assert (rbd_size > 0 && rbd_size <= TME_I825X6_RBD_ACT_COUNT_MASK);
1414: eof_f_act_count = ((resid == 0
1415: ? TME_I825X6_RBD_EOF
1416: : 0)
1417: | TME_I825X6_RBD_F
1418: | rbd_size);
1419:
1420: /* write the EOF_F_ACT_COUNT field out to the Receive Buffer
1421: Descriptor: */
1422: TME_I825X6_WRITE16((rx_buffer->tme_i825x6_rx_buffer_rbd_address
1423: + TME_I825X6_RBD_EOF_F_ACT_COUNT),
1424: eof_f_act_count);
1425:
1426: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle,
1427: 100, TME_OK,
1428: (&i825x6->tme_i825x6_element->tme_element_log_handle,
1429: "RU RBD 0x%06x last-size 0x%04x eof_f_act_count 0x%04x",
1430: rx_buffer->tme_i825x6_rx_buffer_rbd_address,
1431: rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes_count,
1432: eof_f_act_count));
1433:
1434: /* we're starting on the next Receive Buffer: */
1435: rbd_size = 0;
1436: }
1437:
1438: /* free this rx buffer and move to the next rx buffer: */
1439: i825x6->tme_i825x6_fbl_size -= rx_buffer->tme_i825x6_rx_buffer_frame_chunk.tme_ethernet_frame_chunk_bytes_count;
1440: rx_buffer = _tme_i825x6_rx_buffer_free(i825x6, rx_buffer);
1441: }
1442:
1443: /* update the Free Buffer List: */
1444: assert ((rx_buffer != NULL) == (i825x6->tme_i825x6_fbl_size != 0));
1445: i825x6->tme_i825x6_fbl = rx_buffer;
1446:
1447: /* make the C_B_OK_STATUS field: */
1448: c_b_ok_status = (TME_I825X6_FLAG_C
1449: | (resid == 0
1450: ? TME_I825X6_FLAG_OK
1451: : TME_I825X6_RFD_STATUS_RNR));
1452:
1453: /* write the C_B_OK_STATUS field in the RFD: */
1454: TME_I825X6_WRITE16((rfd_address
1455: + TME_I825X6_RFD_C_B_OK_STATUS),
1456: c_b_ok_status);
1457:
1458: /* signal an interrupt: */
1459: stat_cus_rus_t |= TME_I825X6_SCB_STAT_FR;
1460:
1461: /* if EL is set, there is no next Receive Frame Descriptor,
1462: and when the Receive Unit tries to receive another frame
1463: it will go No Resources: */
1464: if (el_s_sf & TME_I825X6_FLAG_EL) {
1465: rfd_address = TME_I825X6_RU_ADDRESS_UNDEF;
1466: }
1467:
1468: /* otherwise, get the address of the next Receive Frame Descriptor: */
1469: else {
1470: TME_I825X6_READ16((rfd_address
1471: + TME_I82586_RFD_LINK_OFFSET),
1472: rfd_address);
1473: rfd_address += i825x6->tme_i825x6_scb_base;
1474: }
1475:
1476: /* set the next RFD address: */
1477: i825x6->tme_i825x6_rfd_address = rfd_address;
1478:
1479: /* if there is a next RFD address: */
1480: if (rfd_address != TME_I825X6_RU_ADDRESS_UNDEF) {
1481:
1482: /* refill the Free Buffer List: */
1483: rbd_offset_next = _tme_i825x6_fbl_refill(i825x6, FALSE);
1484:
1485: /* write the offset of the first free Receive Buffer Descriptor
1486: in the RBD Offset field in the RFD: */
1487: TME_I825X6_WRITE16((rfd_address
1488: + TME_I82586_RFD_RBD_OFFSET),
1489: rbd_offset_next);
1490: }
1491:
1492: /* if S is set, the Receive Unit becomes Suspended: */
1493: if (el_s_sf & TME_I825X6_FLAG_S) {
1494:
1495: /* the Receive Unit is now Suspended: */
1496: stat_cus_rus_t
1497: = ((stat_cus_rus_t
1498: & ~TME_I82586_SCB_RUS_MASK)
1499: | TME_I825X6_SCB_RUS_SUSPENDED);
1500: }
1501: }
1502:
1503: /* otherwise, we had no Receive Frame Descriptor, so we had
1504: to discard this packet entirely: */
1505: else {
1506:
1507: /* account for the discarded packet: */
1508: TME_I825X6_READ16((i825x6->tme_i825x6_scb_address
1509: + TME_I82586_SCB_ERRORS_RESOURCE),
1510: discards);
1511: discards++;
1512: TME_I825X6_WRITE16((i825x6->tme_i825x6_scb_address
1513: + TME_I82586_SCB_ERRORS_RESOURCE),
1514: discards);
1515: }
1516:
1517: /* if we ran out of resources: */
1518: if (resid > 0) {
1519:
1520: /* the receiver is now out of resources: */
1521: stat_cus_rus_t = ((stat_cus_rus_t
1522: & ~TME_I82586_SCB_RUS_MASK)
1523: | TME_I825X6_SCB_RUS_ERESOURCE);
1524: }
1525:
1526: /* done: */
1527: return (stat_cus_rus_t);
1528: }
1529:
1530: /* the i825x6 callout function. it must be called with the mutex locked: */
1531: static void
1532: _tme_i825x6_callout(struct tme_i825x6 *i825x6, int new_callouts)
1533: {
1534: struct tme_ethernet_connection *conn_eth;
1535: struct tme_bus_connection *conn_bus;
1536: int callouts, later_callouts;
1537: unsigned int ctrl;
1538: struct tme_ethernet_config config;
1539: int rc;
1540: tme_uint16_t stat_cus_rus_t;
1541: tme_uint16_t value16;
1542: int int_asserted;
1543: unsigned int address_i;
1544:
1545: /* add in any new callouts: */
1546: i825x6->tme_i825x6_callout_flags |= new_callouts;
1547:
1548: /* if this function is already running in another thread, simply
1549: return now. the other thread will do our work: */
1550: if (i825x6->tme_i825x6_callout_flags & TME_I825X6_CALLOUTS_RUNNING) {
1551: return;
1552: }
1553:
1554: /* callouts are now running: */
1555: i825x6->tme_i825x6_callout_flags |= TME_I825X6_CALLOUTS_RUNNING;
1556:
1557: /* assume that we won't need any later callouts: */
1558: later_callouts = 0;
1559:
1560: /* loop while callouts are needed: */
1561: for (; (callouts = i825x6->tme_i825x6_callout_flags) & TME_I825X6_CALLOUTS_MASK; ) {
1562:
1563: /* clear the needed callouts: */
1564: i825x6->tme_i825x6_callout_flags = callouts & ~TME_I825X6_CALLOUTS_MASK;
1565: callouts &= TME_I825X6_CALLOUTS_MASK;
1566:
1567: /* get this card's connection: */
1568: conn_eth = i825x6->tme_i825x6_eth_connection;
1569:
1570: /* get the current SCB status word. this word is referenced and
1571: updated throughout the body of this for loop; any changes made
1572: are written out at the bottom of the loop: */
1573: stat_cus_rus_t = i825x6->tme_i825x6_stat_cus_rus_t;
1574:
1575: /* if we need to handle a Channel Attention: */
1576: if (callouts & TME_I825X6_CALLOUT_CA) {
1577: stat_cus_rus_t = _tme_i825x6_callout_ca(i825x6, stat_cus_rus_t);
1578: if (stat_cus_rus_t == TME_I825X6_CA_RESET) {
1579: continue;
1580: }
1581: }
1582:
1583: /* if we need to run the Command Unit: */
1584: if (callouts & TME_I825X6_CALLOUT_CU) {
1585: stat_cus_rus_t = _tme_i825x6_callout_cu(i825x6, stat_cus_rus_t);
1586: }
1587:
1588: /* if we need to call out new control information: */
1589: if (callouts & TME_I825X6_CALLOUT_CTRL) {
1590:
1591: /* form the new ctrl: */
1592: ctrl = 0;
1593: if (((stat_cus_rus_t
1594: & TME_I825X6_SCB_CUS_MASK)
1595: == TME_I825X6_SCB_CUS_ACTIVE)
1596: && ((i825x6->tme_i825x6_el_s_i_cmd
1597: & TME_I825X6_CB_CMD_MASK)
1598: == TME_I825X6_CB_CMD_TRANSMIT)) {
1599: ctrl |= TME_ETHERNET_CTRL_OK_READ;
1600: }
1601:
1602: /* unlock the mutex: */
1603: tme_mutex_unlock(&i825x6->tme_i825x6_mutex);
1604:
1605: /* do the callout: */
1606: rc = (conn_eth != NULL
1607: ? ((*conn_eth->tme_ethernet_connection_ctrl)
1608: (conn_eth,
1609: ctrl))
1610: : TME_OK);
1611:
1612: /* lock the mutex: */
1613: tme_mutex_lock(&i825x6->tme_i825x6_mutex);
1614:
1615: /* if the callout was unsuccessful, remember that at some later
1616: time this callout should be attempted again: */
1617: if (rc != TME_OK) {
1618: later_callouts |= TME_I825X6_CALLOUT_CTRL;
1619: }
1620: }
1621:
1622: /* if we need to call out new config information: */
1623: if (callouts & TME_I825X6_CALLOUT_CONFIG) {
1624:
1625: /* form the new config: */
1626: memset(&config, 0, sizeof(config));
1627:
1628: /* our Ethernet addresses: */
1629: config.tme_ethernet_config_addr_count = i825x6->tme_i825x6_address_count;
1630: config.tme_ethernet_config_addrs
1631: = tme_new(const tme_uint8_t *,
1632: i825x6->tme_i825x6_address_count);
1633: for (address_i = 0;
1634: address_i < i825x6->tme_i825x6_address_count;
1635: address_i++) {
1636: config.tme_ethernet_config_addrs[address_i]
1637: = &i825x6->tme_i825x6_addresses[(address_i
1638: * TME_ETHERNET_ADDR_SIZE)];
1639: }
1640:
1641: /* our config flags: */
1642: config.tme_ethernet_config_flags
1643: = (TME_ETHERNET_CONFIG_NORMAL
1644: | (i825x6->tme_i825x6_prm
1645: ? TME_ETHERNET_CONFIG_PROMISC
1646: : 0));
1647:
1648: /* unlock the mutex: */
1649: tme_mutex_unlock(&i825x6->tme_i825x6_mutex);
1650:
1651: /* do the callout: */
1652: rc = (conn_eth == NULL
1653: ? TME_OK
1654: : ((*conn_eth->tme_ethernet_connection_config)
1655: (conn_eth,
1656: &config)));
1657:
1658: /* lock the mutex: */
1659: tme_mutex_lock(&i825x6->tme_i825x6_mutex);
1660:
1661: /* free the Ethernet address pointer array: */
1662: tme_free(config.tme_ethernet_config_addrs);
1663:
1664: /* if the callout was unsuccessful, remember that at some later
1665: time this callout should be attempted again: */
1666: if (rc != TME_OK) {
1667: later_callouts |= TME_I825X6_CALLOUT_CONFIG;
1668: }
1669: }
1670:
1671: /* if the Ethernet is readable: */
1672: if (callouts & TME_I825X6_CALLOUT_READ) {
1673:
1674: /* if the Receive Unit is Suspended, make this callout later: */
1675: if ((stat_cus_rus_t
1676: & TME_I82586_SCB_RUS_MASK)
1677: == TME_I825X6_SCB_RUS_SUSPENDED) {
1678: later_callouts |= TME_I825X6_CALLOUT_READ;
1679: }
1680:
1681: /* otherwise, the Receive Unit is not Suspended, so read this
1682: frame. the frame will not be stored if the Receive Unit is
1683: in the Idle or No Resources state: */
1684: else {
1685: stat_cus_rus_t = _tme_i825x6_callout_ru(i825x6, stat_cus_rus_t);
1686: }
1687: }
1688:
1689: /* note if the Command Unit left the Active state: */
1690: if (((i825x6->tme_i825x6_stat_cus_rus_t
1691: & TME_I825X6_SCB_CUS_MASK)
1692: == TME_I825X6_SCB_CUS_ACTIVE)
1693: && ((stat_cus_rus_t
1694: & TME_I825X6_SCB_CUS_MASK)
1695: != TME_I825X6_SCB_CUS_ACTIVE)) {
1696: stat_cus_rus_t |= TME_I825X6_SCB_STAT_CNA;
1697: }
1698:
1699: /* note if the Receive Unit left the Ready state: */
1700: if (((i825x6->tme_i825x6_stat_cus_rus_t
1701: & TME_I82586_SCB_RUS_MASK)
1702: == TME_I825X6_SCB_RUS_READY)
1703: && ((stat_cus_rus_t
1704: & TME_I82586_SCB_RUS_MASK)
1705: != TME_I825X6_SCB_RUS_READY)) {
1706: stat_cus_rus_t |= TME_I825X6_SCB_STAT_RNR;
1707: }
1708:
1709: /* if our Status bits have changed such that our interrupt signal
1710: changes, we need to call out an interrupt: */
1711: if (!(i825x6->tme_i825x6_stat_cus_rus_t
1712: & TME_I825X6_SCB_STAT_MASK)
1713: != !(stat_cus_rus_t
1714: & TME_I825X6_SCB_STAT_MASK)) {
1715: i825x6->tme_i825x6_callout_flags |= TME_I825X6_CALLOUT_INT;
1716: }
1717:
1718: /* if our SCB status word has changed, write it out: */
1719: if (stat_cus_rus_t != i825x6->tme_i825x6_stat_cus_rus_t) {
1720:
1721: /* log: */
1722: tme_log(&i825x6->tme_i825x6_element->tme_element_log_handle,
1723: 100, TME_OK,
1724: (&i825x6->tme_i825x6_element->tme_element_log_handle,
1725: "SCB status 0x%04x -> 0x%04x",
1726: i825x6->tme_i825x6_stat_cus_rus_t,
1727: stat_cus_rus_t));
1728:
1729: TME_I825X6_WRITE16((i825x6->tme_i825x6_scb_address
1730: + TME_I825X6_SCB_STAT_CUS_RUS_T),
1731: stat_cus_rus_t);
1732: i825x6->tme_i825x6_stat_cus_rus_t = stat_cus_rus_t;
1733: }
1734:
1735: /* if we need to call out a change to our interrupt signal: */
1736: if (callouts & TME_I825X6_CALLOUT_INT) {
1737:
1738: /* see if the interrupt signal should be asserted or negated: */
1739: int_asserted = (stat_cus_rus_t & TME_I825X6_SCB_STAT_MASK);
1740:
1741: /* unlock our mutex: */
1742: tme_mutex_unlock(&i825x6->tme_i825x6_mutex);
1743:
1744: /* get our bus connection: */
1745: conn_bus = TME_ATOMIC_READ(struct tme_bus_connection *,
1746: i825x6->tme_i825x6_device.tme_bus_device_connection);
1747:
1748: /* call out the bus interrupt signal edge: */
1749: rc = (*conn_bus->tme_bus_signal)
1750: (conn_bus,
1751: TME_BUS_SIGNAL_INT_UNSPEC
1752: | (int_asserted
1753: ? TME_BUS_SIGNAL_LEVEL_ASSERTED
1754: : TME_BUS_SIGNAL_LEVEL_NEGATED));
1755:
1756: /* lock our mutex: */
1757: tme_mutex_lock(&i825x6->tme_i825x6_mutex);
1758:
1759: /* if this callout failed, remember that at some later time this
1760: callout should be attempted again: */
1761: if (rc != TME_OK) {
1762: later_callouts |= TME_I825X6_CALLOUT_INT;
1763: }
1764: }
1765: }
1766:
1767: /* put in any later callouts, and clear that callouts are running: */
1768: i825x6->tme_i825x6_callout_flags = later_callouts;
1769: }
1770:
1771: /* the i825x6 bus signal handler: */
1772: static int
1773: _tme_i825x6_signal(void *_i825x6,
1774: unsigned int signal)
1775: {
1776: struct tme_i825x6 *i825x6;
1777: int new_callouts;
1778: unsigned int level;
1779:
1780: /* recover our data structure: */
1781: i825x6 = (struct tme_i825x6 *) _i825x6;
1782:
1783: /* assume we won't need any new callouts: */
1784: new_callouts = 0;
1785:
1786: /* lock the mutex: */
1787: tme_mutex_lock(&i825x6->tme_i825x6_mutex);
1788:
1789: /* take out the signal level: */
1790: level = signal & TME_BUS_SIGNAL_LEVEL_MASK;
1791: signal ^= level;
1792:
1793: /* dispatch on the generic bus signals: */
1794: switch (signal) {
1795: case TME_BUS_SIGNAL_RESET:
1796: if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) {
1797: _tme_i825x6_reset(i825x6);
1798: }
1799: break;
1800: default:
1801: break;
1802: }
1803:
1804: /* dispatch on the i825x6 bus signals: */
1805: if (signal >= i825x6->tme_i825x6_bus_signals.tme_bus_signals_first) {
1806: switch (signal - i825x6->tme_i825x6_bus_signals.tme_bus_signals_first) {
1807:
1808: case TME_I825X6_SIGNAL_CA:
1809: if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) {
1810: new_callouts |= TME_I825X6_CALLOUT_CA;
1811: }
1812: break;
1813:
1814: case TME_I825X6_SIGNAL_LOOP:
1815: #if 0
1816: if (level == TME_BUS_SIGNAL_LEVEL_ASSERTED) {
1817: abort();
1818: }
1819: #endif
1820: break;
1821:
1822: default:
1823: break;
1824: }
1825: }
1826:
1827: /* make any new callouts: */
1828: _tme_i825x6_callout(i825x6, new_callouts);
1829:
1830: /* unlock the mutex: */
1831: tme_mutex_unlock(&i825x6->tme_i825x6_mutex);
1832:
1833: /* no faults: */
1834: return (TME_OK);
1835: }
1836:
1837: /* this is called when a device changes its configuration: */
1838: static int
1839: _tme_i825x6_config(struct tme_ethernet_connection *conn_eth,
1840: struct tme_ethernet_config *config)
1841: {
1842: /* we don't care when other devices on the Ethernet
1843: reconfigure themselves: */
1844: return (TME_OK);
1845: }
1846:
1847: /* this is called when control lines change: */
1848: static int
1849: _tme_i825x6_ctrl(struct tme_ethernet_connection *conn_eth,
1850: unsigned int ctrl)
1851: {
1852: struct tme_i825x6 *i825x6;
1853: int new_callouts;
1854:
1855: /* recover our data structures: */
1856: i825x6 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private;
1857:
1858: /* assume that we won't need any new callouts: */
1859: new_callouts = 0;
1860:
1861: /* lock the mutex: */
1862: tme_mutex_lock(&i825x6->tme_i825x6_mutex);
1863:
1864: /* if this connection is readable, call out a read: */
1865: if (ctrl & TME_ETHERNET_CTRL_OK_READ) {
1866: new_callouts |= TME_I825X6_CALLOUT_READ;
1867: }
1868:
1869: /* make any new callouts: */
1870: _tme_i825x6_callout(i825x6, new_callouts);
1871:
1872: /* unlock the mutex: */
1873: tme_mutex_unlock(&i825x6->tme_i825x6_mutex);
1874:
1875: return (TME_OK);
1876: }
1877:
1878: /* this is called to read frames (from the i825x6 perspective, to transmit them): */
1879: static int
1880: _tme_i825x6_read(struct tme_ethernet_connection *conn_eth,
1881: tme_ethernet_fid_t *_frame_id,
1882: struct tme_ethernet_frame_chunk *frame_chunks,
1883: unsigned int flags)
1884: {
1885: struct tme_i825x6 *i825x6;
1886: int new_callouts;
1887: struct tme_ethernet_frame_chunk frame_chunk_buffer;
1888: tme_uint32_t tbd_address, tb_address;
1889: tme_uint16_t eof_size;
1890: tme_uint16_t c_b_ok_a;
1891: tme_uint16_t value16;
1892: tme_uint32_t value32;
1893: int rc, err;
1894:
1895: /* recover our data structures: */
1896: i825x6 = conn_eth->tme_ethernet_connection.tme_connection_element->tme_element_private;
1897:
1898: /* assume that we won't need any new callouts: */
1899: new_callouts = 0;
1900:
1901: /* start our local copy of the caller's frame chunks: */
1902: if (frame_chunks != NULL) {
1903: frame_chunk_buffer = *frame_chunks;
1904: }
1905: else {
1906: frame_chunk_buffer.tme_ethernet_frame_chunk_bytes_count = 0;
1907: }
1908: frame_chunks = &frame_chunk_buffer;
1909:
1910: /* lock our mutex: */
1911: tme_mutex_lock(&i825x6->tme_i825x6_mutex);
1912:
1913: /* assume that we will have no packet to transmit: */
1914: rc = 0;
1915:
1916: /* if we have a packet to transmit: */
1917: if ((i825x6->tme_i825x6_el_s_i_cmd
1918: & TME_I825X6_CB_CMD_MASK)
1919: == TME_I825X6_CB_CMD_TRANSMIT) {
1920:
1921: /* assume that we will succeed: */
1922: err = TME_OK;
1923: do {
1924:
1925: /* a helper macro for DMAing and copying data into chunks: */
1926: #define CHUNKS_DMA_TX(addr, size) \
1927: err = _tme_i825x6_chunks_dma_tx(i825x6, frame_chunks, (addr), (size)); \
1928: if (err != TME_OK) break; \
1929: rc += size
1930: #define CHUNKS_MEM_TX(data, size) \
1931: _tme_i825x6_chunks_mem_tx(frame_chunks, (data), (size)); \
1932: rc += size
1933:
1934: /* if AL-LOC is set to zero, add the Ethernet/802.3 MAC header: */
1935: if (i825x6->tme_i825x6_al_loc == 0) {
1936:
1937: /* the destination address: */
1938: CHUNKS_DMA_TX(i825x6->tme_i825x6_cb_address + TME_I82586_TCB_ADDR_DEST,
1939: TME_ETHERNET_ADDR_SIZE);
1940:
1941: /* our source address (our Individual Address): */
1942: CHUNKS_MEM_TX(&i825x6->tme_i825x6_addresses[TME_ETHERNET_ADDR_SIZE],
1943: TME_ETHERNET_ADDR_SIZE);
1944:
1945: /* the length field: */
1946: CHUNKS_DMA_TX(i825x6->tme_i825x6_cb_address + TME_I82586_TCB_LENGTH,
1947: TME_ETHERNET_LENGTH_SIZE);
1948: }
1949:
1950: /* the transmit buffers: */
1951: TME_I825X6_READ16((i825x6->tme_i825x6_cb_address
1952: + TME_I82586_TCB_TBD_OFFSET),
1953: tbd_address);
1954: for (; tbd_address != 0xffff; ) {
1955: tbd_address += i825x6->tme_i825x6_scb_base;
1956:
1957: TME_I825X6_READ16((tbd_address
1958: + TME_I82586_TBD_EOF_SIZE),
1959: eof_size);
1960: TME_I82586_READ24((tbd_address
1961: + TME_I82586_TBD_TB_ADDRESS),
1962: tb_address);
1963:
1964: /* the transmit buffer contents: */
1965: CHUNKS_DMA_TX(tb_address,
1966: (eof_size & TME_I82586_TBD_SIZE_MASK));
1967:
1968: /* the next transmit buffer: */
1969: if (eof_size & TME_I82586_TBD_EOF) {
1970: break;
1971: }
1972: TME_I825X6_READ16((tbd_address
1973: + TME_I82586_TBD_TBD_OFFSET),
1974: tbd_address);
1975: }
1976:
1977: #undef CHUNKS_DMA_TX
1978: #undef CHUNKS_MEM_TX
1979:
1980: } while (/* CONSTCOND */ 0);
1981:
1982: /* get the CB status word and clear all of the transmit status bits: */
1983: c_b_ok_a
1984: = (i825x6->tme_i825x6_c_b_ok_a
1985: & ~TME_I825X6_TCB_STATUS_MASK);
1986:
1987: /* if we got a bus error: */
1988: if (err != TME_OK) {
1989:
1990: /* set the DMA underrun transmit status bit: */
1991: c_b_ok_a |= TME_I825X6_TCB_STATUS_UNDERRUN;
1992:
1993: /* return an error to our caller: */
1994: rc = -ENOENT;
1995: }
1996:
1997: /* update the CB status word: */
1998: i825x6->tme_i825x6_c_b_ok_a = c_b_ok_a;
1999:
2000: /* run the Command Unit: */
2001: new_callouts |= TME_I825X6_CALLOUT_CU;
2002:
2003: /* we no longer have a packet to transmit: */
2004: i825x6->tme_i825x6_el_s_i_cmd
2005: = ((i825x6->tme_i825x6_el_s_i_cmd
2006: & ~TME_I825X6_CB_CMD_MASK)
2007: | TME_I825X6_CB_CMD_NOP);
2008: }
2009:
2010: /* make any new callouts: */
2011: _tme_i825x6_callout(i825x6, new_callouts);
2012:
2013: /* unlock our mutex: */
2014: tme_mutex_unlock(&i825x6->tme_i825x6_mutex);
2015:
2016: /* done: */
2017: return (rc);
2018: }
2019:
2020: /* this makes a new Ethernet connection: */
2021: static int
2022: _tme_i825x6_connection_make_eth(struct tme_connection *conn, unsigned int state)
2023: {
2024: struct tme_i825x6 *i825x6;
2025: struct tme_ethernet_connection *conn_eth;
2026: struct tme_ethernet_connection *conn_eth_other;
2027:
2028: /* recover our data structures: */
2029: i825x6 = conn->tme_connection_element->tme_element_private;
2030: conn_eth = (struct tme_ethernet_connection *) conn;
2031: conn_eth_other = (struct tme_ethernet_connection *) conn->tme_connection_other;
2032:
2033: /* both sides must be Ethernet connections: */
2034: assert(conn->tme_connection_type == TME_CONNECTION_ETHERNET);
2035: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_ETHERNET);
2036:
2037: /* we're always set up to answer calls across the connection, so we
2038: only have to do work when the connection has gone full, namely
2039: taking the other side of the connection: */
2040: if (state == TME_CONNECTION_FULL) {
2041:
2042: /* lock our mutex: */
2043: tme_mutex_lock(&i825x6->tme_i825x6_mutex);
2044:
2045: /* save our connection: */
2046: i825x6->tme_i825x6_eth_connection = conn_eth_other;
2047:
2048: /* unlock our mutex: */
2049: tme_mutex_unlock(&i825x6->tme_i825x6_mutex);
2050: }
2051:
2052: return (TME_OK);
2053: }
2054:
2055: /* this makes a new bus connection: */
2056: static int
2057: _tme_i825x6_connection_make_bus(struct tme_connection *conn,
2058: unsigned int state)
2059: {
2060: struct tme_i825x6 *i825x6;
2061: struct tme_bus_connection *conn_bus;
2062: int rc;
2063:
2064: /* recover our data structure: */
2065: i825x6 = conn->tme_connection_element->tme_element_private;
2066:
2067: /* call the bus device connection maker: */
2068: rc = tme_bus_device_connection_make(conn, state);
2069:
2070: /* if the full connection was successful, and we don't have a TLB
2071: hash yet, allocate it and add our bus signals: */
2072: if (rc == TME_OK
2073: && state == TME_CONNECTION_FULL
2074: && TME_ATOMIC_READ(struct tme_bus_tlb *,
2075: i825x6->tme_i825x6_tlb_hash) == NULL) {
2076:
2077: /* get our bus connection: */
2078: conn_bus
2079: = TME_ATOMIC_READ(struct tme_bus_connection *,
2080: i825x6->tme_i825x6_device.tme_bus_device_connection);
2081:
2082: /* allocate the TLB set: */
2083: rc = ((*conn_bus->tme_bus_tlb_set_allocate)
2084: (conn_bus,
2085: TME_I825X6_TLB_HASH_SIZE,
2086: sizeof(struct tme_bus_tlb),
2087: TME_ATOMIC_POINTER(&i825x6->tme_i825x6_tlb_hash)));
2088: assert (rc == TME_OK);
2089:
2090: /* add our bus signals: */
2091: i825x6->tme_i825x6_bus_signals = _tme_i825x6_bus_signals;
2092: rc = ((*conn_bus->tme_bus_signals_add)
2093: (conn_bus,
2094: &i825x6->tme_i825x6_bus_signals));
2095: assert (rc == TME_OK);
2096: }
2097:
2098: return (rc);
2099: }
2100:
2101: /* this breaks a connection: */
2102: static int
2103: _tme_i825x6_connection_break(struct tme_connection *conn, unsigned int state)
2104: {
2105: abort();
2106: }
2107:
2108: /* this makes a new connection side for a i825x6: */
2109: static int
2110: _tme_i825x6_connections_new(struct tme_element *element,
2111: const char * const *args,
2112: struct tme_connection **_conns,
2113: char **_output)
2114: {
2115: struct tme_i825x6 *i825x6;
2116: struct tme_ethernet_connection *conn_eth;
2117: struct tme_connection *conn;
2118: int rc;
2119:
2120: /* recover our data structure: */
2121: i825x6 = (struct tme_i825x6 *) element->tme_element_private;
2122:
2123: /* make the generic bus device connection side: */
2124: rc = tme_bus_device_connections_new(element, args, _conns, _output);
2125: if (rc != TME_OK) {
2126: return (rc);
2127: }
2128:
2129: /* since we need to allocate our TLB hash and add our signals sets
2130: when we make our bus connection, make sure any generic bus device
2131: connection sides use our connection maker: */
2132: for (conn = *_conns;
2133: conn != NULL;
2134: conn = conn->tme_connection_next) {
2135: if ((conn->tme_connection_type
2136: == TME_CONNECTION_BUS_GENERIC)
2137: && (conn->tme_connection_make
2138: == tme_bus_device_connection_make)) {
2139: conn->tme_connection_make
2140: = _tme_i825x6_connection_make_bus;
2141: }
2142: }
2143:
2144: /* if we don't have an Ethernet connection, make one: */
2145: if (i825x6->tme_i825x6_eth_connection == NULL) {
2146:
2147: /* allocate the new Ethernet connection: */
2148: conn_eth = tme_new0(struct tme_ethernet_connection, 1);
2149: conn = &conn_eth->tme_ethernet_connection;
2150:
2151: /* fill in the generic connection: */
2152: conn->tme_connection_next = *_conns;
2153: conn->tme_connection_type = TME_CONNECTION_ETHERNET;
2154: conn->tme_connection_score = tme_ethernet_connection_score;
2155: conn->tme_connection_make = _tme_i825x6_connection_make_eth;
2156: conn->tme_connection_break = _tme_i825x6_connection_break;
2157:
2158: /* fill in the Ethernet connection: */
2159: conn_eth->tme_ethernet_connection_config = _tme_i825x6_config;
2160: conn_eth->tme_ethernet_connection_ctrl = _tme_i825x6_ctrl;
2161: conn_eth->tme_ethernet_connection_read = _tme_i825x6_read;
2162:
2163: /* return the connection side possibility: */
2164: *_conns = conn;
2165: }
2166:
2167: /* done: */
2168: return (TME_OK);
2169: }
2170:
2171: /* the new i82586 function: */
2172: TME_ELEMENT_X_NEW_DECL(tme_ic_,i825x6,i82586) {
2173: struct tme_i825x6 *i825x6;
2174: int arg_i;
2175: int usage;
2176:
2177: /* check our arguments: */
2178: usage = 0;
2179: arg_i = 1;
2180: for (;;) {
2181:
2182: if (0) {
2183: }
2184:
2185: /* if we ran out of arguments: */
2186: else if (args[arg_i] == NULL) {
2187:
2188: break;
2189: }
2190:
2191: /* otherwise this is a bad argument: */
2192: else {
2193: tme_output_append_error(_output,
2194: "%s %s, ",
2195: args[arg_i],
2196: _("unexpected"));
2197: usage = TRUE;
2198: break;
2199: }
2200: }
2201:
2202: if (usage) {
2203: tme_output_append_error(_output,
2204: "%s %s",
2205: _("usage:"),
2206: args[0]);
2207: return (EINVAL);
2208: }
2209:
2210: /* start the i825x6 structure: */
2211: i825x6 = tme_new0(struct tme_i825x6, 1);
2212: i825x6->tme_i825x6_element = element;
2213: tme_mutex_init(&i825x6->tme_i825x6_mutex);
2214: i825x6->tme_i825x6_address_count = 2;
2215: i825x6->tme_i825x6_addresses
2216: = tme_new(tme_uint8_t,
2217: i825x6->tme_i825x6_address_count
2218: * TME_ETHERNET_ADDR_SIZE);
2219:
2220: /* initialize our simple bus device descriptor: */
2221: i825x6->tme_i825x6_device.tme_bus_device_element = element;
2222: i825x6->tme_i825x6_device.tme_bus_device_signal = _tme_i825x6_signal;
2223: i825x6->tme_i825x6_device.tme_bus_device_lock = _tme_i825x6_lock;
2224: i825x6->tme_i825x6_device.tme_bus_device_unlock = _tme_i825x6_unlock;
2225: i825x6->tme_i825x6_device.tme_bus_device_tlb_hash = _tme_i825x6_tlb_hash;
2226: i825x6->tme_i825x6_device.tme_bus_device_router = tme_bus_device_router_16el;
2227:
2228: /* fill the element: */
2229: element->tme_element_private = i825x6;
2230: element->tme_element_connections_new = _tme_i825x6_connections_new;
2231:
2232: /* reset the i825x6: */
2233: _tme_i825x6_reset(i825x6);
2234:
2235: return (TME_OK);
2236: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.