25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_dec21143.c,v 1.28 2007/01/05 15:20:06 debug Exp $ |
* $Id: dev_dec21143.c,v 1.31 2007/06/15 18:44:19 debug Exp $ |
29 |
* |
* |
30 |
* DEC 21143 ("Tulip") ethernet controller. Implemented from Intel document |
* COMMENT: DEC 21143 "Tulip" ethernet controller |
31 |
* 278074-001 ("21143 PC/CardBus 10/100Mb/s Ethernet LAN Controller") and by |
* |
32 |
* reverse-engineering OpenBSD and NetBSD sources. |
* Implemented from Intel document 278074-001 ("21143 PC/CardBus 10/100Mb/s |
33 |
|
* Ethernet LAN Controller") and by reverse-engineering OpenBSD and NetBSD |
34 |
|
* sources. |
35 |
* |
* |
36 |
* This device emulates several sub-components: |
* This device emulates several sub-components: |
37 |
* |
* |
157 |
|
|
158 |
/* Append a 4 byte CRC: */ |
/* Append a 4 byte CRC: */ |
159 |
d->cur_rx_buf_len += 4; |
d->cur_rx_buf_len += 4; |
160 |
d->cur_rx_buf = realloc(d->cur_rx_buf, d->cur_rx_buf_len); |
CHECK_ALLOCATION(d->cur_rx_buf = realloc(d->cur_rx_buf, |
161 |
if (d->cur_rx_buf == NULL) { |
d->cur_rx_buf_len)); |
162 |
fatal("dec21143_rx(): out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
163 |
/* Well... the CRC is just zeros, for now. */ |
/* Well... the CRC is just zeros, for now. */ |
164 |
memset(d->cur_rx_buf + d->cur_rx_buf_len - 4, 0, 4); |
memset(d->cur_rx_buf + d->cur_rx_buf_len - 4, 0, 4); |
165 |
|
|
287 |
uint64_t addr = d->cur_tx_addr, bufaddr; |
uint64_t addr = d->cur_tx_addr, bufaddr; |
288 |
unsigned char descr[16]; |
unsigned char descr[16]; |
289 |
uint32_t tdes0, tdes1, tdes2, tdes3; |
uint32_t tdes0, tdes1, tdes2, tdes3; |
290 |
int bufsize, buf1_size, buf2_size, i, writeback_len = 4; |
int bufsize, buf1_size, buf2_size, i; |
291 |
|
|
292 |
addr &= 0x7fffffff; |
addr &= 0x7fffffff; |
293 |
|
|
341 |
|
|
342 |
/* |
/* |
343 |
fatal("{ TX (%llx): 0x%08x 0x%08x 0x%x 0x%x: buf %i bytes at 0x%x }\n", |
fatal("{ TX (%llx): 0x%08x 0x%08x 0x%x 0x%x: buf %i bytes at 0x%x }\n", |
344 |
(long long)addr, tdes0, tdes1, tdes2, tdes3, bufsize, (int)bufaddr); |
(long long)addr, tdes0, tdes1, tdes2, tdes3, bufsize, (int)bufaddr); |
345 |
*/ |
*/ |
346 |
bufaddr &= 0x7fffffff; |
bufaddr &= 0x7fffffff; |
347 |
|
|
372 |
if (tdes1 & TDCTL_Tx_FS) { |
if (tdes1 & TDCTL_Tx_FS) { |
373 |
/* First segment. Let's allocate a new buffer: */ |
/* First segment. Let's allocate a new buffer: */ |
374 |
/* fatal("new frame }\n"); */ |
/* fatal("new frame }\n"); */ |
375 |
d->cur_tx_buf = malloc(bufsize); |
|
376 |
|
CHECK_ALLOCATION(d->cur_tx_buf = malloc(bufsize)); |
377 |
d->cur_tx_buf_len = 0; |
d->cur_tx_buf_len = 0; |
378 |
} else { |
} else { |
379 |
/* Not first segment. Increase the length of |
/* Not first segment. Increase the length of |
380 |
the current buffer: */ |
the current buffer: */ |
381 |
/* fatal("continuing last frame }\n"); */ |
/* fatal("continuing last frame }\n"); */ |
|
d->cur_tx_buf = realloc(d->cur_tx_buf, |
|
|
d->cur_tx_buf_len + bufsize); |
|
|
} |
|
382 |
|
|
383 |
if (d->cur_tx_buf == NULL) { |
if (d->cur_tx_buf == NULL) |
384 |
fatal("dec21143_tx(): out of memory\n"); |
fatal("[ dec21143: WARNING! tx: middle " |
385 |
exit(1); |
"segment, but no first segment?! ]\n"); |
386 |
|
|
387 |
|
CHECK_ALLOCATION(d->cur_tx_buf = realloc(d->cur_tx_buf, |
388 |
|
d->cur_tx_buf_len + bufsize)); |
389 |
} |
} |
390 |
|
|
391 |
/* "DMA" data from emulated physical memory into the buf: */ |
/* "DMA" data from emulated physical memory into the buf: */ |
417 |
d->cur_tx_buf = NULL; |
d->cur_tx_buf = NULL; |
418 |
d->cur_tx_buf_len = 0; |
d->cur_tx_buf_len = 0; |
419 |
|
|
|
/* TODO: Shouldn't the OWN bit be cleared on all |
|
|
kinds of segments, not just the Last? */ |
|
|
|
|
|
/* We are done. */ |
|
|
tdes0 &= ~TDSTAT_OWN; |
|
|
writeback_len = 1; |
|
|
|
|
420 |
/* Interrupt, if Tx_IC is set: */ |
/* Interrupt, if Tx_IC is set: */ |
421 |
if (tdes1 & TDCTL_Tx_IC) |
if (tdes1 & TDCTL_Tx_IC) |
422 |
d->reg[CSR_STATUS/8] |= STATUS_TI; |
d->reg[CSR_STATUS/8] |= STATUS_TI; |
423 |
} |
} |
424 |
|
|
425 |
|
/* We are done with this segment. */ |
426 |
|
tdes0 &= ~TDSTAT_OWN; |
427 |
} |
} |
428 |
|
|
429 |
/* Error summary: */ |
/* Error summary: */ |
434 |
/* Descriptor writeback: */ |
/* Descriptor writeback: */ |
435 |
descr[ 0] = tdes0; descr[ 1] = tdes0 >> 8; |
descr[ 0] = tdes0; descr[ 1] = tdes0 >> 8; |
436 |
descr[ 2] = tdes0 >> 16; descr[ 3] = tdes0 >> 24; |
descr[ 2] = tdes0 >> 16; descr[ 3] = tdes0 >> 24; |
437 |
if (writeback_len > 1) { |
descr[ 4] = tdes1; descr[ 5] = tdes1 >> 8; |
438 |
descr[ 4] = tdes1; descr[ 5] = tdes1 >> 8; |
descr[ 6] = tdes1 >> 16; descr[ 7] = tdes1 >> 24; |
439 |
descr[ 6] = tdes1 >> 16; descr[ 7] = tdes1 >> 24; |
descr[ 8] = tdes2; descr[ 9] = tdes2 >> 8; |
440 |
descr[ 8] = tdes2; descr[ 9] = tdes2 >> 8; |
descr[10] = tdes2 >> 16; descr[11] = tdes2 >> 24; |
441 |
descr[10] = tdes2 >> 16; descr[11] = tdes2 >> 24; |
descr[12] = tdes3; descr[13] = tdes3 >> 8; |
442 |
descr[12] = tdes3; descr[13] = tdes3 >> 8; |
descr[14] = tdes3 >> 16; descr[15] = tdes3 >> 24; |
|
descr[14] = tdes3 >> 16; descr[15] = tdes3 >> 24; |
|
|
} |
|
443 |
|
|
444 |
if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t) |
if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t) |
445 |
* writeback_len, MEM_WRITE, PHYSICAL | NO_EXCEPTIONS)) { |
* 4, MEM_WRITE, PHYSICAL | NO_EXCEPTIONS)) { |
446 |
fatal("[ dec21143_tx: memory_rw failed! ]\n"); |
fatal("[ dec21143_tx: memory_rw failed! ]\n"); |
447 |
return 0; |
return 0; |
448 |
} |
} |
451 |
} |
} |
452 |
|
|
453 |
|
|
454 |
/* |
DEVICE_TICK(dec21143) |
|
* dev_dec21143_tick(): |
|
|
*/ |
|
|
void dev_dec21143_tick(struct cpu *cpu, void *extra) |
|
455 |
{ |
{ |
456 |
struct dec21143_data *d = extra; |
struct dec21143_data *d = extra; |
457 |
int asserted; |
int asserted; |
979 |
struct dec21143_data *d; |
struct dec21143_data *d; |
980 |
char name2[100]; |
char name2[100]; |
981 |
|
|
982 |
d = malloc(sizeof(struct dec21143_data)); |
CHECK_ALLOCATION(d = malloc(sizeof(struct dec21143_data))); |
|
if (d == NULL) { |
|
|
fprintf(stderr, "out of memory\n"); |
|
|
exit(1); |
|
|
} |
|
983 |
memset(d, 0, sizeof(struct dec21143_data)); |
memset(d, 0, sizeof(struct dec21143_data)); |
984 |
|
|
985 |
INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); |
INTERRUPT_CONNECT(devinit->interrupt_path, d->irq); |
999 |
devinit->addr, 0x100, dev_dec21143_access, d, DM_DEFAULT, NULL); |
devinit->addr, 0x100, dev_dec21143_access, d, DM_DEFAULT, NULL); |
1000 |
|
|
1001 |
machine_add_tickfunction(devinit->machine, |
machine_add_tickfunction(devinit->machine, |
1002 |
dev_dec21143_tick, d, DEC21143_TICK_SHIFT, 0.0); |
dev_dec21143_tick, d, DEC21143_TICK_SHIFT); |
1003 |
|
|
1004 |
/* |
/* |
1005 |
* NetBSD/cats uses memory accesses, OpenBSD/cats uses I/O registers. |
* NetBSD/cats uses memory accesses, OpenBSD/cats uses I/O registers. |