2 |
* Cisco router simulation platform. |
* Cisco router simulation platform. |
3 |
* Copyright (C) 2007 Christophe Fillot. All rights reserved. |
* Copyright (C) 2007 Christophe Fillot. All rights reserved. |
4 |
* |
* |
5 |
* Intel i8254x (Livengood) FastEthernet chip emulation. |
* Intel i8254x (Wiseman/Livengood) Ethernet chip emulation. |
6 |
*/ |
*/ |
7 |
|
|
8 |
#include <stdio.h> |
#include <stdio.h> |
27 |
|
|
28 |
/* Debugging flags */ |
/* Debugging flags */ |
29 |
#define DEBUG_MII_REGS 0 |
#define DEBUG_MII_REGS 0 |
30 |
#define DEBUG_ACCESS 1 |
#define DEBUG_ACCESS 0 |
31 |
#define DEBUG_TRANSMIT 0 |
#define DEBUG_TRANSMIT 0 |
32 |
#define DEBUG_RECEIVE 0 |
#define DEBUG_RECEIVE 0 |
33 |
#define DEBUG_UNKNOWN 1 |
#define DEBUG_UNKNOWN 0 |
34 |
|
|
35 |
/* Intel i8254x PCI vendor/product codes */ |
/* Intel i8254x PCI vendor/product codes */ |
36 |
#define I8254X_PCI_VENDOR_ID 0x8086 |
#define I8254X_PCI_VENDOR_ID 0x8086 |
68 |
#define I8254X_REG_RDLEN 0x2808 /* RX Descriptor Length */ |
#define I8254X_REG_RDLEN 0x2808 /* RX Descriptor Length */ |
69 |
#define I8254X_REG_RDH 0x2810 /* RX Descriptor Head */ |
#define I8254X_REG_RDH 0x2810 /* RX Descriptor Head */ |
70 |
#define I8254X_REG_RDT 0x2818 /* RX Descriptor Tail */ |
#define I8254X_REG_RDT 0x2818 /* RX Descriptor Tail */ |
|
#define I82542_REG_RDH 0x0120 /* RDH for i82542 */ |
|
|
#define I82542_REG_RDT 0x0128 /* RDT for i82542 */ |
|
71 |
#define I8254X_REG_RDTR 0x2820 /* RX Delay Timer Register */ |
#define I8254X_REG_RDTR 0x2820 /* RX Delay Timer Register */ |
72 |
#define I8254X_REG_RXDCTL 0x3828 /* RX Descriptor Control */ |
#define I8254X_REG_RXDCTL 0x3828 /* RX Descriptor Control */ |
73 |
#define I8254X_REG_RADV 0x282c /* RX Int. Absolute Delay Timer */ |
#define I8254X_REG_RADV 0x282c /* RX Int. Absolute Delay Timer */ |
79 |
#define I8254X_REG_TDLEN 0x3808 /* TX Descriptor Length */ |
#define I8254X_REG_TDLEN 0x3808 /* TX Descriptor Length */ |
80 |
#define I8254X_REG_TDH 0x3810 /* TX Descriptor Head */ |
#define I8254X_REG_TDH 0x3810 /* TX Descriptor Head */ |
81 |
#define I8254X_REG_TDT 0x3818 /* TX Descriptor Tail */ |
#define I8254X_REG_TDT 0x3818 /* TX Descriptor Tail */ |
|
#define I82542_REG_TDH 0x0430 /* TDH for i82542 */ |
|
|
#define I82542_REG_TDT 0x0438 /* TDT for i82542 */ |
|
82 |
#define I8254X_REG_TIDV 0x3820 /* TX Interrupt Delay Value */ |
#define I8254X_REG_TIDV 0x3820 /* TX Interrupt Delay Value */ |
83 |
#define I8254X_REG_TXDCTL 0x3828 /* TX Descriptor Control */ |
#define I8254X_REG_TXDCTL 0x3828 /* TX Descriptor Control */ |
84 |
#define I8254X_REG_TADV 0x382c /* TX Absolute Interrupt Delay Value */ |
#define I8254X_REG_TADV 0x382c /* TX Absolute Interrupt Delay Value */ |
86 |
|
|
87 |
#define I8254X_REG_RXCSUM 0x5000 /* RX Checksum Control */ |
#define I8254X_REG_RXCSUM 0x5000 /* RX Checksum Control */ |
88 |
|
|
89 |
|
/* Register list for i8254x */ |
90 |
|
#define I82542_REG_RDTR 0x0108 /* RX Delay Timer Register */ |
91 |
|
#define I82542_REG_RDBAL 0x0110 /* RX Descriptor Base Address Low */ |
92 |
|
#define I82542_REG_RDBAH 0x0114 /* RX Descriptor Base Address High */ |
93 |
|
#define I82542_REG_RDLEN 0x0118 /* RX Descriptor Length */ |
94 |
|
#define I82542_REG_RDH 0x0120 /* RDH for i82542 */ |
95 |
|
#define I82542_REG_RDT 0x0128 /* RDT for i82542 */ |
96 |
|
#define I82542_REG_TDBAL 0x0420 /* TX Descriptor Base Address Low */ |
97 |
|
#define I82542_REG_TDBAH 0x0424 /* TX Descriptor Base Address Low */ |
98 |
|
#define I82542_REG_TDLEN 0x0428 /* TX Descriptor Length */ |
99 |
|
#define I82542_REG_TDH 0x0430 /* TDH for i82542 */ |
100 |
|
#define I82542_REG_TDT 0x0438 /* TDT for i82542 */ |
101 |
|
|
102 |
/* CTRL - Control Register (0x0000) */ |
/* CTRL - Control Register (0x0000) */ |
103 |
#define I8254X_CTRL_FD 0x00000001 /* Full Duplex */ |
#define I8254X_CTRL_FD 0x00000001 /* Full Duplex */ |
247 |
#define I8254X_RXDESC_EOP 0x00000002 /* End Of Packet */ |
#define I8254X_RXDESC_EOP 0x00000002 /* End Of Packet */ |
248 |
#define I8254X_RXDESC_DD 0x00000001 /* Descriptor Done */ |
#define I8254X_RXDESC_DD 0x00000001 /* Descriptor Done */ |
249 |
|
|
|
|
|
|
|
|
250 |
/* Intel i8254x private data */ |
/* Intel i8254x private data */ |
251 |
struct i8254x_data { |
struct i8254x_data { |
252 |
char *name; |
char *name; |
281 |
/* Extended Control Register */ |
/* Extended Control Register */ |
282 |
m_uint32_t ctrl_ext; |
m_uint32_t ctrl_ext; |
283 |
|
|
284 |
|
/* Flow Control registers */ |
285 |
|
m_uint32_t fcal,fcah,fct; |
286 |
|
|
287 |
|
/* RX Delay Timer */ |
288 |
|
m_uint32_t rdtr; |
289 |
|
|
290 |
/* RX/TX Control Registers */ |
/* RX/TX Control Registers */ |
291 |
m_uint32_t rctl,tctl; |
m_uint32_t rctl,tctl; |
292 |
|
|
354 |
case 0x05: |
case 0x05: |
355 |
return(0x41e1); |
return(0x41e1); |
356 |
case 0x06: |
case 0x06: |
357 |
return(0x1); |
return(0x0001); |
358 |
case 0x11: |
case 0x11: |
359 |
return(0x4700); |
return(0x4700); |
360 |
default: |
default: |
475 |
{ |
{ |
476 |
if (d->icr & d->imr) |
if (d->icr & d->imr) |
477 |
pci_dev_trigger_irq(d->vm,d->pci_dev); |
pci_dev_trigger_irq(d->vm,d->pci_dev); |
478 |
|
else |
479 |
|
pci_dev_clear_irq(d->vm,d->pci_dev); |
480 |
} |
} |
481 |
|
|
482 |
/* Compute RX buffer size */ |
/* Compute RX buffer size */ |
546 |
LVG_LOCK(d); |
LVG_LOCK(d); |
547 |
|
|
548 |
switch(offset) { |
switch(offset) { |
549 |
|
#if 0 /* TODO */ |
550 |
|
case 0x180: |
551 |
|
if (op_type == MTS_READ) |
552 |
|
*data = 0xFFFFFFFF; //0xDC004020; //1 << 31; |
553 |
|
break; |
554 |
|
#endif |
555 |
|
|
556 |
/* Link is Up and Full Duplex */ |
/* Link is Up and Full Duplex */ |
557 |
case I8254X_REG_STATUS: |
case I8254X_REG_STATUS: |
558 |
if (op_type == MTS_READ) |
if (op_type == MTS_READ) |
559 |
*data = I8254X_STATUS_LU | I8254X_STATUS_FD ; |
*data = I8254X_STATUS_LU | I8254X_STATUS_FD; |
560 |
break; |
break; |
561 |
|
|
562 |
/* Device Control Register */ |
/* Device Control Register */ |
664 |
|
|
665 |
/* RX Descriptor Base Address Low */ |
/* RX Descriptor Base Address Low */ |
666 |
case I8254X_REG_RDBAL: |
case I8254X_REG_RDBAL: |
667 |
|
case I82542_REG_RDBAL: |
668 |
if (op_type == MTS_WRITE) { |
if (op_type == MTS_WRITE) { |
669 |
d->rx_addr &= 0xFFFFFFFF00000000ULL; |
d->rx_addr &= 0xFFFFFFFF00000000ULL; |
670 |
d->rx_addr |= (m_uint32_t)(*data); |
d->rx_addr |= (m_uint32_t)(*data); |
675 |
|
|
676 |
/* RX Descriptor Base Address High */ |
/* RX Descriptor Base Address High */ |
677 |
case I8254X_REG_RDBAH: |
case I8254X_REG_RDBAH: |
678 |
|
case I82542_REG_RDBAH: |
679 |
if (op_type == MTS_WRITE) { |
if (op_type == MTS_WRITE) { |
680 |
d->rx_addr &= 0x00000000FFFFFFFFULL; |
d->rx_addr &= 0x00000000FFFFFFFFULL; |
681 |
d->rx_addr |= *data << 32; |
d->rx_addr |= *data << 32; |
686 |
|
|
687 |
/* TX Descriptor Base Address Low */ |
/* TX Descriptor Base Address Low */ |
688 |
case I8254X_REG_TDBAL: |
case I8254X_REG_TDBAL: |
689 |
|
case I82542_REG_TDBAL: |
690 |
if (op_type == MTS_WRITE) { |
if (op_type == MTS_WRITE) { |
691 |
d->tx_addr &= 0xFFFFFFFF00000000ULL; |
d->tx_addr &= 0xFFFFFFFF00000000ULL; |
692 |
d->tx_addr |= (m_uint32_t)(*data); |
d->tx_addr |= (m_uint32_t)(*data); |
697 |
|
|
698 |
/* TX Descriptor Base Address High */ |
/* TX Descriptor Base Address High */ |
699 |
case I8254X_REG_TDBAH: |
case I8254X_REG_TDBAH: |
700 |
|
case I82542_REG_TDBAH: |
701 |
if (op_type == MTS_WRITE) { |
if (op_type == MTS_WRITE) { |
702 |
d->tx_addr &= 0x00000000FFFFFFFFULL; |
d->tx_addr &= 0x00000000FFFFFFFFULL; |
703 |
d->tx_addr |= *data << 32; |
d->tx_addr |= *data << 32; |
708 |
|
|
709 |
/* RX Descriptor Length */ |
/* RX Descriptor Length */ |
710 |
case I8254X_REG_RDLEN: |
case I8254X_REG_RDLEN: |
711 |
|
case I82542_REG_RDLEN: |
712 |
if (op_type == MTS_WRITE) |
if (op_type == MTS_WRITE) |
713 |
d->rdlen = *data & 0xFFF80; |
d->rdlen = *data & 0xFFF80; |
714 |
else |
else |
717 |
|
|
718 |
/* TX Descriptor Length */ |
/* TX Descriptor Length */ |
719 |
case I8254X_REG_TDLEN: |
case I8254X_REG_TDLEN: |
720 |
|
case I82542_REG_TDLEN: |
721 |
if (op_type == MTS_WRITE) |
if (op_type == MTS_WRITE) |
722 |
d->tdlen = *data & 0xFFF80; |
d->tdlen = *data & 0xFFF80; |
723 |
else |
else |
760 |
*data = d->tdt; |
*data = d->tdt; |
761 |
break; |
break; |
762 |
|
|
763 |
|
/* Flow Control Address Low */ |
764 |
|
case I8254X_REG_FCAL: |
765 |
|
if (op_type == MTS_WRITE) |
766 |
|
d->fcal = *data; |
767 |
|
else |
768 |
|
*data = d->fcal; |
769 |
|
break; |
770 |
|
|
771 |
|
/* Flow Control Address High */ |
772 |
|
case I8254X_REG_FCAH: |
773 |
|
if (op_type == MTS_WRITE) |
774 |
|
d->fcah = *data & 0xFFFF; |
775 |
|
else |
776 |
|
*data = d->fcah; |
777 |
|
break; |
778 |
|
|
779 |
|
/* Flow Control Type */ |
780 |
|
case I8254X_REG_FCT: |
781 |
|
if (op_type == MTS_WRITE) |
782 |
|
d->fct = *data & 0xFFFF; |
783 |
|
else |
784 |
|
*data = d->fct; |
785 |
|
break; |
786 |
|
|
787 |
|
/* RX Delay Timer */ |
788 |
|
case I8254X_REG_RDTR: |
789 |
|
case I82542_REG_RDTR: |
790 |
|
if (op_type == MTS_WRITE) |
791 |
|
d->rdtr = *data & 0xFFFF; |
792 |
|
else |
793 |
|
*data = d->rdtr; |
794 |
|
break; |
795 |
|
|
796 |
#if DEBUG_UNKNOWN |
#if DEBUG_UNKNOWN |
797 |
default: |
default: |
798 |
if (op_type == MTS_READ) { |
if (op_type == MTS_READ) { |
845 |
return(FALSE); |
return(FALSE); |
846 |
|
|
847 |
LVG_LOCK(d); |
LVG_LOCK(d); |
848 |
|
|
849 |
/* Empty packet for now */ |
/* Empty packet for now */ |
850 |
pkt_ptr = d->tx_buffer; |
pkt_ptr = d->tx_buffer; |
851 |
tot_len = 0; |
tot_len = 0; |
859 |
buf_addr = ((m_uint64_t)txd.tdes[1] << 32) | txd.tdes[0]; |
buf_addr = ((m_uint64_t)txd.tdes[1] << 32) | txd.tdes[0]; |
860 |
buf_len = txd.tdes[2] & I8254X_TXDESC_LEN_MASK; |
buf_len = txd.tdes[2] & I8254X_TXDESC_LEN_MASK; |
861 |
|
|
862 |
|
//printf("COPYING DATA FROM 0x%8.8llx\n",buf_addr); |
863 |
norm_len = normalize_size(buf_len,4,0); |
norm_len = normalize_size(buf_len,4,0); |
864 |
physmem_copy_from_vm(d->vm,pkt_ptr,buf_addr,norm_len); |
physmem_copy_from_vm(d->vm,pkt_ptr,buf_addr,norm_len); |
865 |
mem_bswap32(pkt_ptr,norm_len); |
mem_bswap32(pkt_ptr,norm_len); |
880 |
|
|
881 |
/* End of packet ? */ |
/* End of packet ? */ |
882 |
if (txd.tdes[2] & I8254X_TXDESC_EOP) { |
if (txd.tdes[2] & I8254X_TXDESC_EOP) { |
883 |
|
#if DEBUG_TRANSMIT |
884 |
|
LVG_LOG(d,"sending packet of %u bytes\n",tot_len); |
885 |
|
mem_dump(log_file,d->tx_buffer,tot_len); |
886 |
|
#endif |
887 |
netio_send(d->nio,d->tx_buffer,tot_len); |
netio_send(d->nio,d->tx_buffer,tot_len); |
888 |
break; |
break; |
889 |
} |
} |
1015 |
* Read a PCI register. |
* Read a PCI register. |
1016 |
*/ |
*/ |
1017 |
static m_uint32_t pci_i8254x_read(cpu_gen_t *cpu,struct pci_device *dev, |
static m_uint32_t pci_i8254x_read(cpu_gen_t *cpu,struct pci_device *dev, |
1018 |
int reg) |
int reg) |
1019 |
{ |
{ |
1020 |
struct i8254x_data *d = dev->priv_data; |
struct i8254x_data *d = dev->priv_data; |
1021 |
|
|
1027 |
case 0x00: |
case 0x00: |
1028 |
return((I8254X_PCI_PRODUCT_ID << 16) | I8254X_PCI_VENDOR_ID); |
return((I8254X_PCI_PRODUCT_ID << 16) | I8254X_PCI_VENDOR_ID); |
1029 |
case 0x08: |
case 0x08: |
1030 |
return(0x02000002); |
return(0x02000003); |
1031 |
case PCI_REG_BAR0: |
case PCI_REG_BAR0: |
1032 |
return(d->dev->phys_addr); |
return(d->dev->phys_addr); |
1033 |
default: |
default: |
1041 |
* Write a PCI register. |
* Write a PCI register. |
1042 |
*/ |
*/ |
1043 |
static void pci_i8254x_write(cpu_gen_t *cpu,struct pci_device *dev, |
static void pci_i8254x_write(cpu_gen_t *cpu,struct pci_device *dev, |
1044 |
int reg,m_uint32_t value) |
int reg,m_uint32_t value) |
1045 |
{ |
{ |
1046 |
struct i8254x_data *d = dev->priv_data; |
struct i8254x_data *d = dev->priv_data; |
1047 |
|
|