Revision e5e23ab8
b/hw/eepro100.c | ||
---|---|---|
20 | 20 |
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 | 21 |
* |
22 | 22 |
* Tested features (i82559): |
23 |
* PXE boot (i386) ok |
|
23 |
* PXE boot (i386 guest, i386 / mips / mipsel / ppc host) ok
|
|
24 | 24 |
* Linux networking (i386) ok |
25 | 25 |
* |
26 | 26 |
* Untested: |
27 |
* non-i386 platforms |
|
28 | 27 |
* Windows networking |
29 | 28 |
* |
30 | 29 |
* References: |
... | ... | |
139 | 138 |
|
140 | 139 |
/* Offsets to the various registers. |
141 | 140 |
All accesses need not be longword aligned. */ |
142 |
enum speedo_offsets {
|
|
141 |
typedef enum {
|
|
143 | 142 |
SCBStatus = 0, /* Status Word. */ |
144 | 143 |
SCBAck = 1, |
145 | 144 |
SCBCmd = 2, /* Rx/Command Unit command and status. */ |
... | ... | |
154 | 153 |
SCBpmdr = 27, /* Power Management Driver. */ |
155 | 154 |
SCBgctrl = 28, /* General Control. */ |
156 | 155 |
SCBgstat = 29, /* General Status. */ |
157 |
}; |
|
156 |
} E100RegisterOffset;
|
|
158 | 157 |
|
159 | 158 |
/* A speedo3 transmit buffer descriptor with two buffers... */ |
160 | 159 |
typedef struct { |
... | ... | |
258 | 257 |
/* Statistical counters. Also used for wake-up packet (i82559). */ |
259 | 258 |
eepro100_stats_t statistics; |
260 | 259 |
|
260 |
/* Data in mem is always in the byte order of the controller (le). |
|
261 |
* It must be dword aligned to allow direct access to 32 bit values. */ |
|
262 |
uint8_t mem[PCI_MEM_SIZE] __attribute__((aligned(8)));; |
|
263 |
|
|
261 | 264 |
/* Configuration bytes. */ |
262 | 265 |
uint8_t configuration[22]; |
263 | 266 |
|
264 |
/* Data in mem is always in the byte order of the controller (le). */ |
|
265 |
uint8_t mem[PCI_MEM_SIZE]; |
|
266 | 267 |
/* vmstate for each particular nic */ |
267 | 268 |
VMStateDescription *vmstate; |
268 | 269 |
|
... | ... | |
316 | 317 |
0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, |
317 | 318 |
}; |
318 | 319 |
|
319 |
/* XXX: optimize */ |
|
320 |
static void stl_le_phys(target_phys_addr_t addr, uint32_t val) |
|
320 |
/* Read a 16 bit little endian value from physical memory. */ |
|
321 |
static uint16_t e100_ldw_le_phys(target_phys_addr_t addr) |
|
322 |
{ |
|
323 |
/* Load 16 bit (little endian) word from emulated hardware. */ |
|
324 |
uint16_t val; |
|
325 |
cpu_physical_memory_read(addr, &val, sizeof(val)); |
|
326 |
return le16_to_cpu(val); |
|
327 |
} |
|
328 |
|
|
329 |
/* Read a 32 bit little endian value from physical memory. */ |
|
330 |
static uint32_t e100_ldl_le_phys(target_phys_addr_t addr) |
|
331 |
{ |
|
332 |
/* Load 32 bit (little endian) word from emulated hardware. */ |
|
333 |
uint32_t val; |
|
334 |
cpu_physical_memory_read(addr, &val, sizeof(val)); |
|
335 |
return le32_to_cpu(val); |
|
336 |
} |
|
337 |
|
|
338 |
/* Write a 16 bit little endian value to physical memory. */ |
|
339 |
static void e100_stw_le_phys(target_phys_addr_t addr, uint16_t val) |
|
340 |
{ |
|
341 |
val = cpu_to_le16(val); |
|
342 |
cpu_physical_memory_write(addr, &val, sizeof(val)); |
|
343 |
} |
|
344 |
|
|
345 |
/* Write a 32 bit little endian value to physical memory. */ |
|
346 |
static void e100_stl_le_phys(target_phys_addr_t addr, uint32_t val) |
|
321 | 347 |
{ |
322 | 348 |
val = cpu_to_le32(val); |
323 | 349 |
cpu_physical_memory_write(addr, &val, sizeof(val)); |
... | ... | |
348 | 374 |
return (crc & BITS(7, 2)) >> 2; |
349 | 375 |
} |
350 | 376 |
|
377 |
/* Read a 16 bit control/status (CSR) register. */ |
|
378 |
static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr) |
|
379 |
{ |
|
380 |
assert(!((uintptr_t)&s->mem[addr] & 1)); |
|
381 |
return le16_to_cpup((uint16_t *)&s->mem[addr]); |
|
382 |
} |
|
383 |
|
|
384 |
/* Read a 32 bit control/status (CSR) register. */ |
|
385 |
static uint32_t e100_read_reg4(EEPRO100State *s, E100RegisterOffset addr) |
|
386 |
{ |
|
387 |
assert(!((uintptr_t)&s->mem[addr] & 3)); |
|
388 |
return le32_to_cpup((uint32_t *)&s->mem[addr]); |
|
389 |
} |
|
390 |
|
|
391 |
/* Write a 16 bit control/status (CSR) register. */ |
|
392 |
static void e100_write_reg2(EEPRO100State *s, E100RegisterOffset addr, |
|
393 |
uint16_t val) |
|
394 |
{ |
|
395 |
assert(!((uintptr_t)&s->mem[addr] & 1)); |
|
396 |
cpu_to_le16w((uint16_t *)&s->mem[addr], val); |
|
397 |
} |
|
398 |
|
|
399 |
/* Read a 32 bit control/status (CSR) register. */ |
|
400 |
static void e100_write_reg4(EEPRO100State *s, E100RegisterOffset addr, |
|
401 |
uint32_t val) |
|
402 |
{ |
|
403 |
assert(!((uintptr_t)&s->mem[addr] & 3)); |
|
404 |
cpu_to_le32w((uint32_t *)&s->mem[addr], val); |
|
405 |
} |
|
406 |
|
|
351 | 407 |
#if defined(DEBUG_EEPRO100) |
352 | 408 |
static const char *nic_dump(const uint8_t * buf, unsigned size) |
353 | 409 |
{ |
... | ... | |
599 | 655 |
TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE - 1])); |
600 | 656 |
|
601 | 657 |
memset(s->mem, 0, sizeof(s->mem)); |
602 |
uint32_t val = BIT(21); |
|
603 |
memcpy(&s->mem[SCBCtrlMDI], &val, sizeof(val)); |
|
658 |
e100_write_reg4(s, SCBCtrlMDI, BIT(21)); |
|
604 | 659 |
|
605 | 660 |
assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default)); |
606 | 661 |
memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem)); |
... | ... | |
704 | 759 |
* Number of data should check configuration!!! |
705 | 760 |
*/ |
706 | 761 |
cpu_physical_memory_write(s->statsaddr, &s->statistics, s->stats_size); |
707 |
stl_le_phys(s->statsaddr + 0, s->statistics.tx_good_frames); |
|
708 |
stl_le_phys(s->statsaddr + 36, s->statistics.rx_good_frames); |
|
709 |
stl_le_phys(s->statsaddr + 48, s->statistics.rx_resource_errors); |
|
710 |
stl_le_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors); |
|
762 |
e100_stl_le_phys(s->statsaddr + 0, s->statistics.tx_good_frames);
|
|
763 |
e100_stl_le_phys(s->statsaddr + 36, s->statistics.rx_good_frames);
|
|
764 |
e100_stl_le_phys(s->statsaddr + 48, s->statistics.rx_resource_errors);
|
|
765 |
e100_stl_le_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors);
|
|
711 | 766 |
#if 0 |
712 |
stw_le_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames); |
|
713 |
stw_le_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames); |
|
767 |
e100_stw_le_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames);
|
|
768 |
e100_stw_le_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames);
|
|
714 | 769 |
missing("CU dump statistical counters"); |
715 | 770 |
#endif |
716 | 771 |
} |
... | ... | |
747 | 802 |
} |
748 | 803 |
assert(tcb_bytes <= sizeof(buf)); |
749 | 804 |
while (size < tcb_bytes) { |
750 |
uint32_t tx_buffer_address = ldl_phys(tbd_address);
|
|
751 |
uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
|
|
805 |
uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
|
|
806 |
uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
|
|
752 | 807 |
#if 0 |
753 |
uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
|
|
808 |
uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6);
|
|
754 | 809 |
#endif |
755 | 810 |
tbd_address += 8; |
756 | 811 |
TRACE(RXTX, logout |
... | ... | |
769 | 824 |
if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) { |
770 | 825 |
/* Extended Flexible TCB. */ |
771 | 826 |
for (; tbd_count < 2; tbd_count++) { |
772 |
uint32_t tx_buffer_address = ldl_phys(tbd_address);
|
|
773 |
uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
|
|
774 |
uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
|
|
827 |
uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
|
|
828 |
uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
|
|
829 |
uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6);
|
|
775 | 830 |
tbd_address += 8; |
776 | 831 |
TRACE(RXTX, logout |
777 | 832 |
("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n", |
... | ... | |
787 | 842 |
} |
788 | 843 |
tbd_address = tbd_array; |
789 | 844 |
for (; tbd_count < s->tx.tbd_count; tbd_count++) { |
790 |
uint32_t tx_buffer_address = ldl_phys(tbd_address);
|
|
791 |
uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
|
|
792 |
uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
|
|
845 |
uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
|
|
846 |
uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
|
|
847 |
uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6);
|
|
793 | 848 |
tbd_address += 8; |
794 | 849 |
TRACE(RXTX, logout |
795 | 850 |
("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n", |
... | ... | |
897 | 952 |
break; |
898 | 953 |
} |
899 | 954 |
/* Write new status. */ |
900 |
stw_phys(s->cb_address, s->tx.status | ok_status | STATUS_C);
|
|
955 |
e100_stw_le_phys(s->cb_address, s->tx.status | ok_status | STATUS_C);
|
|
901 | 956 |
if (bit_i) { |
902 | 957 |
/* CU completed action. */ |
903 | 958 |
eepro100_cx_interrupt(s); |
... | ... | |
964 | 1019 |
/* Dump statistical counters. */ |
965 | 1020 |
TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val)); |
966 | 1021 |
dump_statistics(s); |
967 |
stl_le_phys(s->statsaddr + s->stats_size, 0xa005); |
|
1022 |
e100_stl_le_phys(s->statsaddr + s->stats_size, 0xa005);
|
|
968 | 1023 |
break; |
969 | 1024 |
case CU_CMD_BASE: |
970 | 1025 |
/* Load CU base. */ |
... | ... | |
975 | 1030 |
/* Dump and reset statistical counters. */ |
976 | 1031 |
TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val)); |
977 | 1032 |
dump_statistics(s); |
978 |
stl_le_phys(s->statsaddr + s->stats_size, 0xa007); |
|
1033 |
e100_stl_le_phys(s->statsaddr + s->stats_size, 0xa007);
|
|
979 | 1034 |
memset(&s->statistics, 0, sizeof(s->statistics)); |
980 | 1035 |
break; |
981 | 1036 |
case CU_SRESUME: |
... | ... | |
1058 | 1113 |
|
1059 | 1114 |
static uint16_t eepro100_read_eeprom(EEPRO100State * s) |
1060 | 1115 |
{ |
1061 |
uint16_t val; |
|
1062 |
memcpy(&val, &s->mem[SCBeeprom], sizeof(val)); |
|
1116 |
uint16_t val = e100_read_reg2(s, SCBeeprom); |
|
1063 | 1117 |
if (eeprom93xx_read(s->eeprom)) { |
1064 | 1118 |
val |= EEPROM_DO; |
1065 | 1119 |
} else { |
... | ... | |
1129 | 1183 |
|
1130 | 1184 |
static uint32_t eepro100_read_mdi(EEPRO100State * s) |
1131 | 1185 |
{ |
1132 |
uint32_t val; |
|
1133 |
memcpy(&val, &s->mem[0x10], sizeof(val)); |
|
1186 |
uint32_t val = e100_read_reg4(s, SCBCtrlMDI); |
|
1134 | 1187 |
|
1135 | 1188 |
#ifdef DEBUG_EEPRO100 |
1136 | 1189 |
uint8_t raiseint = (val & BIT(29)) >> 29; |
... | ... | |
1239 | 1292 |
} |
1240 | 1293 |
} |
1241 | 1294 |
val = (val & 0xffff0000) + data; |
1242 |
memcpy(&s->mem[0x10], &val, sizeof(val));
|
|
1295 |
e100_write_reg4(s, SCBCtrlMDI, val);
|
|
1243 | 1296 |
} |
1244 | 1297 |
|
1245 | 1298 |
/***************************************************************************** |
... | ... | |
1266 | 1319 |
|
1267 | 1320 |
static void eepro100_write_port(EEPRO100State * s, uint32_t val) |
1268 | 1321 |
{ |
1269 |
val = le32_to_cpu(val); |
|
1270 | 1322 |
uint32_t address = (val & ~PORT_SELECTION_MASK); |
1271 | 1323 |
uint8_t selection = (val & PORT_SELECTION_MASK); |
1272 | 1324 |
switch (selection) { |
... | ... | |
1301 | 1353 |
{ |
1302 | 1354 |
uint8_t val = 0; |
1303 | 1355 |
if (addr <= sizeof(s->mem) - sizeof(val)) { |
1304 |
memcpy(&val, &s->mem[addr], sizeof(val));
|
|
1356 |
val = s->mem[addr];
|
|
1305 | 1357 |
} |
1306 | 1358 |
|
1307 | 1359 |
switch (addr) { |
... | ... | |
1344 | 1396 |
{ |
1345 | 1397 |
uint16_t val = 0; |
1346 | 1398 |
if (addr <= sizeof(s->mem) - sizeof(val)) { |
1347 |
memcpy(&val, &s->mem[addr], sizeof(val));
|
|
1399 |
val = e100_read_reg2(s, addr);
|
|
1348 | 1400 |
} |
1349 | 1401 |
|
1350 | 1402 |
switch (addr) { |
... | ... | |
1367 | 1419 |
{ |
1368 | 1420 |
uint32_t val = 0; |
1369 | 1421 |
if (addr <= sizeof(s->mem) - sizeof(val)) { |
1370 |
memcpy(&val, &s->mem[addr], sizeof(val));
|
|
1422 |
val = e100_read_reg4(s, addr);
|
|
1371 | 1423 |
} |
1372 | 1424 |
|
1373 | 1425 |
switch (addr) { |
... | ... | |
1398 | 1450 |
{ |
1399 | 1451 |
/* SCBStatus is readonly. */ |
1400 | 1452 |
if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) { |
1401 |
memcpy(&s->mem[addr], &val, sizeof(val));
|
|
1453 |
s->mem[addr] = val;
|
|
1402 | 1454 |
} |
1403 | 1455 |
|
1404 | 1456 |
switch (addr) { |
... | ... | |
1441 | 1493 |
{ |
1442 | 1494 |
/* SCBStatus is readonly. */ |
1443 | 1495 |
if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) { |
1444 |
memcpy(&s->mem[addr], &val, sizeof(val));
|
|
1496 |
e100_write_reg2(s, addr, val);
|
|
1445 | 1497 |
} |
1446 | 1498 |
|
1447 | 1499 |
switch (addr) { |
... | ... | |
1468 | 1520 |
static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val) |
1469 | 1521 |
{ |
1470 | 1522 |
if (addr <= sizeof(s->mem) - sizeof(val)) { |
1471 |
memcpy(&s->mem[addr], &val, sizeof(val));
|
|
1523 |
e100_write_reg4(s, addr, val);
|
|
1472 | 1524 |
} |
1473 | 1525 |
|
1474 | 1526 |
switch (addr) { |
... | ... | |
1760 | 1812 |
#endif |
1761 | 1813 |
TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n", |
1762 | 1814 |
rfd_command, rx.link, rx.rx_buf_addr, rfd_size)); |
1763 |
stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, status), |
|
1764 |
rfd_status); |
|
1765 |
stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, count), size); |
|
1815 |
e100_stw_le_phys(s->ru_base + s->ru_offset + |
|
1816 |
offsetof(eepro100_rx_t, status), rfd_status); |
|
1817 |
e100_stw_le_phys(s->ru_base + s->ru_offset + |
|
1818 |
offsetof(eepro100_rx_t, count), size); |
|
1766 | 1819 |
/* Early receive interrupt not supported. */ |
1767 | 1820 |
#if 0 |
1768 | 1821 |
eepro100_er_interrupt(s); |
... | ... | |
1891 | 1944 |
/* Handler for memory-mapped I/O */ |
1892 | 1945 |
s->mmio_index = |
1893 | 1946 |
cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s, |
1894 |
DEVICE_NATIVE_ENDIAN);
|
|
1947 |
DEVICE_LITTLE_ENDIAN);
|
|
1895 | 1948 |
|
1896 | 1949 |
pci_register_bar_simple(&s->dev, 0, PCI_MEM_SIZE, |
1897 | 1950 |
PCI_BASE_ADDRESS_MEM_PREFETCH, s->mmio_index); |
Also available in: Unified diff