1 |
/* |
/* |
2 |
* Copyright (C) 2005 Anders Gavare. All rights reserved. |
* Copyright (C) 2005-2006 Anders Gavare. All rights reserved. |
3 |
* |
* |
4 |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
5 |
* modification, are permitted provided that the following conditions are met: |
* modification, are permitted provided that the following conditions are met: |
25 |
* SUCH DAMAGE. |
* SUCH DAMAGE. |
26 |
* |
* |
27 |
* |
* |
28 |
* $Id: dev_dec21143.c,v 1.16 2005/11/25 03:52:55 debug Exp $ |
* $Id: dev_dec21143.c,v 1.24 2006/02/09 20:02:59 debug Exp $ |
29 |
* |
* |
30 |
* DEC 21143 ("Tulip") ethernet controller. Implemented from Intel document |
* DEC 21143 ("Tulip") ethernet controller. Implemented from Intel document |
31 |
* 278074-001 ("21143 PC/CardBus 10/100Mb/s Ethernet LAN Controller") and by |
* 278074-001 ("21143 PC/CardBus 10/100Mb/s Ethernet LAN Controller") and by |
32 |
* reverse-engineering OpenBSD and NetBSD sources. |
* reverse-engineering OpenBSD and NetBSD sources. |
33 |
* |
* |
34 |
|
* This device emulates several sub-components: |
35 |
|
* |
36 |
|
* 21143: This is the actual ethernet controller. |
37 |
|
* |
38 |
|
* MII: The "physical" network interface. |
39 |
|
* |
40 |
|
* SROM: A ROM area containing setting such as which MAC address to |
41 |
|
* use, and info about the MII. |
42 |
* |
* |
|
* TODO: |
|
43 |
* |
* |
44 |
* o) Endianness for descriptors... |
* TODO: |
45 |
|
* o) Handle _writes_ to MII registers. |
46 |
|
* o) Make it work with modern Linux kernels (as a guest OS). |
47 |
|
* o) Endianness for descriptors? If necessary. |
48 |
|
* o) Actually handle the "Setup" packet. |
49 |
|
* o) MAC filtering on incoming packets. |
50 |
|
* o) Don't hardcode as many values. |
51 |
*/ |
*/ |
52 |
|
|
53 |
#include <stdio.h> |
#include <stdio.h> |
130 |
|
|
131 |
/* |
/* |
132 |
* dec21143_rx(): |
* dec21143_rx(): |
133 |
|
* |
134 |
|
* Receive a packet. (If there is no current packet, then check for newly |
135 |
|
* arrived ones. If the current packet couldn't be fully transfered the |
136 |
|
* last time, then continue on that packet.) |
137 |
*/ |
*/ |
138 |
int dec21143_rx(struct cpu *cpu, struct dec21143_data *d) |
int dec21143_rx(struct cpu *cpu, struct dec21143_data *d) |
139 |
{ |
{ |
152 |
net_ethernet_rx(d->net, d, &d->cur_rx_buf, |
net_ethernet_rx(d->net, d, &d->cur_rx_buf, |
153 |
&d->cur_rx_buf_len); |
&d->cur_rx_buf_len); |
154 |
|
|
155 |
|
/* Append a 4 byte CRC: */ |
156 |
|
d->cur_rx_buf_len += 4; |
157 |
|
d->cur_rx_buf = realloc(d->cur_rx_buf, d->cur_rx_buf_len); |
158 |
|
if (d->cur_rx_buf == NULL) { |
159 |
|
fatal("dec21143_rx(): out of memory\n"); |
160 |
|
exit(1); |
161 |
|
} |
162 |
|
/* Well... the CRC is just zeros, for now. */ |
163 |
|
memset(d->cur_rx_buf + d->cur_rx_buf_len - 4, 0, 4); |
164 |
|
|
165 |
d->cur_rx_offset = 0; |
d->cur_rx_offset = 0; |
166 |
} |
} |
167 |
|
|
168 |
/* fatal("{ dec21143_rx: base = 0x%08x }\n", (int)addr); */ |
/* fatal("{ dec21143_rx: base = 0x%08x }\n", (int)addr); */ |
169 |
|
addr &= 0x7fffffff; |
170 |
|
|
171 |
if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t), |
if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t), |
172 |
MEM_READ, PHYSICAL | NO_EXCEPTIONS)) { |
MEM_READ, PHYSICAL | NO_EXCEPTIONS)) { |
209 |
d->cur_rx_addr += 4 * sizeof(uint32_t); |
d->cur_rx_addr += 4 * sizeof(uint32_t); |
210 |
} |
} |
211 |
|
|
212 |
/* fatal("{ RX (%llx): %08x %08x %x %x: buf %i bytes at 0x%x }\n", |
debug("{ RX (%llx): 0x%08x 0x%08x 0x%x 0x%x: buf %i bytes at 0x%x }\n", |
213 |
(long long)addr, rdes0, rdes1, rdes2, rdes3, bufsize, |
(long long)addr, rdes0, rdes1, rdes2, rdes3, bufsize, (int)bufaddr); |
214 |
(int)bufaddr); */ |
bufaddr &= 0x7fffffff; |
215 |
|
|
216 |
/* Turn off all status bits, and give up ownership: */ |
/* Turn off all status bits, and give up ownership: */ |
217 |
rdes0 = 0x00000000; |
rdes0 = 0x00000000; |
238 |
if (d->cur_rx_offset >= d->cur_rx_buf_len) { |
if (d->cur_rx_offset >= d->cur_rx_buf_len) { |
239 |
rdes0 |= TDSTAT_Rx_LS; |
rdes0 |= TDSTAT_Rx_LS; |
240 |
|
|
241 |
/* Frame len, which includes the size of a 4-byte CRC: */ |
/* Set the frame length: */ |
242 |
rdes0 |= ((d->cur_rx_buf_len + 4) << 16) & TDSTAT_Rx_FL; |
rdes0 |= (d->cur_rx_buf_len << 16) & TDSTAT_Rx_FL; |
243 |
|
|
244 |
/* Frame too long? (1518 is max ethernet frame length) */ |
/* Frame too long? (1518 is max ethernet frame length) */ |
245 |
if (d->cur_rx_buf_len > 1518) |
if (d->cur_rx_buf_len > 1518) |
277 |
|
|
278 |
/* |
/* |
279 |
* dec21143_tx(): |
* dec21143_tx(): |
280 |
|
* |
281 |
|
* Transmit a packet, if the guest OS has marked a descriptor as containing |
282 |
|
* data to transmit. |
283 |
*/ |
*/ |
284 |
int dec21143_tx(struct cpu *cpu, struct dec21143_data *d) |
int dec21143_tx(struct cpu *cpu, struct dec21143_data *d) |
285 |
{ |
{ |
288 |
uint32_t tdes0, tdes1, tdes2, tdes3; |
uint32_t tdes0, tdes1, tdes2, tdes3; |
289 |
int bufsize, buf1_size, buf2_size, i, writeback_len = 4; |
int bufsize, buf1_size, buf2_size, i, writeback_len = 4; |
290 |
|
|
291 |
/* fatal("{ dec21143_tx: base = 0x%08x }\n", (int)addr); */ |
addr &= 0x7fffffff; |
292 |
|
|
293 |
if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t), |
if (!cpu->memory_rw(cpu, cpu->mem, addr, descr, sizeof(uint32_t), |
294 |
MEM_READ, PHYSICAL | NO_EXCEPTIONS)) { |
MEM_READ, PHYSICAL | NO_EXCEPTIONS)) { |
298 |
|
|
299 |
tdes0 = descr[0] + (descr[1]<<8) + (descr[2]<<16) + (descr[3]<<24); |
tdes0 = descr[0] + (descr[1]<<8) + (descr[2]<<16) + (descr[3]<<24); |
300 |
|
|
301 |
|
/* fatal("{ dec21143_tx: base=0x%08x, tdes0=0x%08x }\n", |
302 |
|
(int)addr, (int)tdes0); */ |
303 |
|
|
304 |
/* Only process packets owned by the 21143: */ |
/* Only process packets owned by the 21143: */ |
305 |
if (!(tdes0 & TDSTAT_OWN)) { |
if (!(tdes0 & TDSTAT_OWN)) { |
306 |
if (d->tx_idling > d->tx_idling_threshold) { |
if (d->tx_idling > d->tx_idling_threshold) { |
338 |
d->cur_tx_addr += 4 * sizeof(uint32_t); |
d->cur_tx_addr += 4 * sizeof(uint32_t); |
339 |
} |
} |
340 |
|
|
341 |
/* fatal("{ TX (%llx): %08x %08x %x %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", |
342 |
(long long)addr, tdes0, tdes1, tdes2, tdes3, bufsize, |
(long long)addr, tdes0, tdes1, tdes2, tdes3, bufsize, (int)bufaddr); |
343 |
(int)bufaddr); */ |
bufaddr &= 0x7fffffff; |
344 |
|
|
345 |
/* Assume no error: */ |
/* Assume no error: */ |
346 |
tdes0 &= ~ (TDSTAT_Tx_UF | TDSTAT_Tx_EC | TDSTAT_Tx_LC |
tdes0 &= ~ (TDSTAT_Tx_UF | TDSTAT_Tx_EC | TDSTAT_Tx_LC |
413 |
d->cur_tx_buf = NULL; |
d->cur_tx_buf = NULL; |
414 |
d->cur_tx_buf_len = 0; |
d->cur_tx_buf_len = 0; |
415 |
|
|
416 |
|
/* TODO: Shouldn't the OWN bit be cleared on all |
417 |
|
kinds of segments, not just the Last? */ |
418 |
|
|
419 |
/* We are done. */ |
/* We are done. */ |
420 |
tdes0 &= ~TDSTAT_OWN; |
tdes0 &= ~TDSTAT_OWN; |
421 |
writeback_len = 1; |
writeback_len = 1; |
658 |
* |
* |
659 |
* This function handles reads from the Ethernet Address ROM. This is not a |
* This function handles reads from the Ethernet Address ROM. This is not a |
660 |
* 100% correct implementation, as it was reverse-engineered from OpenBSD |
* 100% correct implementation, as it was reverse-engineered from OpenBSD |
661 |
* sources; it seems to work with OpenBSD, NetBSD, and Linux. |
* sources; it seems to work with OpenBSD, NetBSD, and Linux, though. |
662 |
* |
* |
663 |
* Each transfer (if I understood this correctly) is of the following format: |
* Each transfer (if I understood this correctly) is of the following format: |
664 |
* |
* |
822 |
/* |
/* |
823 |
* dev_dec21143_access(): |
* dev_dec21143_access(): |
824 |
*/ |
*/ |
825 |
int dev_dec21143_access(struct cpu *cpu, struct memory *mem, |
DEVICE_ACCESS(dec21143) |
|
uint64_t relative_addr, unsigned char *data, size_t len, |
|
|
int writeflag, void *extra) |
|
826 |
{ |
{ |
827 |
struct dec21143_data *d = extra; |
struct dec21143_data *d = extra; |
828 |
uint64_t idata = 0, odata = 0; |
uint64_t idata = 0, odata = 0; |
928 |
d->reg[CSR_STATUS/8] &= ~STATUS_RS; |
d->reg[CSR_STATUS/8] &= ~STATUS_RS; |
929 |
} |
} |
930 |
idata &= ~(OPMODE_HBD | OPMODE_SCR | OPMODE_PCS |
idata &= ~(OPMODE_HBD | OPMODE_SCR | OPMODE_PCS |
931 |
| OPMODE_PS | OPMODE_SF | OPMODE_TTM); |
| OPMODE_PS | OPMODE_SF | OPMODE_TTM | OPMODE_FD); |
932 |
if (idata & OPMODE_PNIC_IT) { |
if (idata & OPMODE_PNIC_IT) { |
933 |
idata &= ~OPMODE_PNIC_IT; |
idata &= ~OPMODE_PNIC_IT; |
934 |
d->tx_idling = d->tx_idling_threshold; |
d->tx_idling = d->tx_idling_threshold; |
983 |
} |
} |
984 |
|
|
985 |
|
|
986 |
/* |
DEVINIT(dec21143) |
|
* devinit_dec21143(): |
|
|
*/ |
|
|
int devinit_dec21143(struct devinit *devinit) |
|
987 |
{ |
{ |
988 |
struct dec21143_data *d; |
struct dec21143_data *d; |
989 |
char name2[100]; |
char name2[100]; |