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