X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=hw%2Fpcnet.c;h=54eecd01d3a1eb6132fb3658d2f21c3fbdf69f46;hb=a8170e5e97ad17ca169c64ba87ae2f53850dab4c;hp=b5793ff246bae4ab9174f52b122d472a0b05a308;hpb=4f1c942b7fb29864ad86cb3af9076da38f38f74e;p=mirror_qemu.git diff --git a/hw/pcnet.c b/hw/pcnet.c index b5793ff246..54eecd01d3 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -35,11 +35,13 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt */ -#include "sysbus.h" -#include "pci.h" +#include "qdev.h" #include "net.h" #include "qemu-timer.h" #include "qemu_socket.h" +#include "sysemu.h" + +#include "pcnet.h" //#define PCNET_DEBUG //#define PCNET_DEBUG_IO @@ -50,72 +52,12 @@ //#define PCNET_DEBUG_MATCH -#define PCNET_IOPORT_SIZE 0x20 -#define PCNET_PNPMMIO_SIZE 0x20 - -#define PCNET_LOOPTEST_CRC 1 -#define PCNET_LOOPTEST_NOCRC 2 - - -typedef struct PCNetState_st PCNetState; - -struct PCNetState_st { - PCIDevice *pci_dev; - VLANClientState *vc; - uint8_t macaddr[6]; - QEMUTimer *poll_timer; - int rap, isr, lnkst; - uint32_t rdra, tdra; - uint8_t prom[16]; - uint16_t csr[128]; - uint16_t bcr[32]; - uint64_t timer; - int mmio_index, xmit_pos, recv_pos; - uint8_t buffer[4096]; - int tx_busy; - qemu_irq irq; - void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int do_bswap); - void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int do_bswap); - void *dma_opaque; - int looptest; -}; - -typedef struct { - PCIDevice pci_dev; - PCNetState state; -} PCIPCNetState; - -typedef struct { - SysBusDevice busdev; - PCNetState state; -} SysBusPCNetState; - struct qemu_ether_header { uint8_t ether_dhost[6]; uint8_t ether_shost[6]; uint16_t ether_type; }; -/* BUS CONFIGURATION REGISTERS */ -#define BCR_MSRDA 0 -#define BCR_MSWRA 1 -#define BCR_MC 2 -#define BCR_LNKST 4 -#define BCR_LED1 5 -#define BCR_LED2 6 -#define BCR_LED3 7 -#define BCR_FDC 9 -#define BCR_BSBC 18 -#define BCR_EECAS 19 -#define BCR_SWS 20 -#define BCR_PLAT 22 - -#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080) -#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100) -#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF) - #define CSR_INIT(S) !!(((S)->csr[0])&0x0001) #define CSR_STRT(S) !!(((S)->csr[0])&0x0002) #define CSR_STOP(S) !!(((S)->csr[0])&0x0004) @@ -135,6 +77,7 @@ struct qemu_ether_header { #define CSR_DTX(S) !!(((S)->csr[15])&0x0002) #define CSR_LOOP(S) !!(((S)->csr[15])&0x0004) #define CSR_DXMTFCS(S) !!(((S)->csr[15])&0x0008) +#define CSR_INTL(S) !!(((S)->csr[15])&0x0040) #define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000) #define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000) #define CSR_PROM(S) !!(((S)->csr[15])&0x8000) @@ -153,23 +96,23 @@ struct qemu_ether_header { #define CSR_XMTRL(S) ((S)->csr[78]) #define CSR_MISSC(S) ((S)->csr[112]) -#define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16)) -#define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16)) -#define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16)) -#define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16)) -#define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16)) -#define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16)) -#define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16)) -#define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16)) -#define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16)) -#define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16)) -#define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16)) -#define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16)) -#define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16)) -#define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16)) +#define CSR_IADR(S) ((S)->csr[ 1] | ((uint32_t)(S)->csr[ 2] << 16)) +#define CSR_CRBA(S) ((S)->csr[18] | ((uint32_t)(S)->csr[19] << 16)) +#define CSR_CXBA(S) ((S)->csr[20] | ((uint32_t)(S)->csr[21] << 16)) +#define CSR_NRBA(S) ((S)->csr[22] | ((uint32_t)(S)->csr[23] << 16)) +#define CSR_BADR(S) ((S)->csr[24] | ((uint32_t)(S)->csr[25] << 16)) +#define CSR_NRDA(S) ((S)->csr[26] | ((uint32_t)(S)->csr[27] << 16)) +#define CSR_CRDA(S) ((S)->csr[28] | ((uint32_t)(S)->csr[29] << 16)) +#define CSR_BADX(S) ((S)->csr[30] | ((uint32_t)(S)->csr[31] << 16)) +#define CSR_NXDA(S) ((S)->csr[32] | ((uint32_t)(S)->csr[33] << 16)) +#define CSR_CXDA(S) ((S)->csr[34] | ((uint32_t)(S)->csr[35] << 16)) +#define CSR_NNRD(S) ((S)->csr[36] | ((uint32_t)(S)->csr[37] << 16)) +#define CSR_NNXD(S) ((S)->csr[38] | ((uint32_t)(S)->csr[39] << 16)) +#define CSR_PXDA(S) ((S)->csr[60] | ((uint32_t)(S)->csr[61] << 16)) +#define CSR_NXBA(S) ((S)->csr[64] | ((uint32_t)(S)->csr[65] << 16)) #define PHYSADDR(S,A) \ - (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16)) + (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(S)->csr[2])<<16)) struct pcnet_initblk16 { uint16_t mode; @@ -350,7 +293,7 @@ struct pcnet_RMD { GET_FIELD((R)->msg_length, RMDM, ZEROS)) static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, - target_phys_addr_t addr) + hwaddr addr) { if (!BCR_SSIZE32(s)) { struct { @@ -380,7 +323,7 @@ static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, } static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd, - target_phys_addr_t addr) + hwaddr addr) { if (!BCR_SSIZE32(s)) { struct { @@ -416,7 +359,7 @@ static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd, } static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, - target_phys_addr_t addr) + hwaddr addr) { if (!BCR_SSIZE32(s)) { struct { @@ -446,7 +389,7 @@ static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, } static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, - target_phys_addr_t addr) + hwaddr addr) { if (!BCR_SSIZE32(s)) { struct { @@ -717,7 +660,7 @@ static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size) return 0; } -static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx) +static inline hwaddr pcnet_rdra_addr(PCNetState *s, int idx) { while (idx < 1) idx += CSR_RCVRL(s); return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8)); @@ -727,7 +670,7 @@ static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_ti { int64_t next_time = current_time + muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)), - ticks_per_sec, 33000000L); + get_ticks_per_sec(), 33000000L); if (next_time <= current_time) next_time = current_time + 1; return next_time; @@ -739,7 +682,6 @@ static void pcnet_poll_timer(void *opaque); static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap); static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value); static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val); -static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); static void pcnet_s_reset(PCNetState *s) { @@ -747,7 +689,6 @@ static void pcnet_s_reset(PCNetState *s) printf("pcnet_s_reset\n"); #endif - s->lnkst = 0x40; s->rdra = 0; s->tdra = 0; s->rap = 0; @@ -936,6 +877,7 @@ static void pcnet_start(PCNetState *s) s->csr[0] &= ~0x0004; /* clear STOP bit */ s->csr[0] |= 0x0002; + pcnet_poll_timer(s); } static void pcnet_stop(PCNetState *s) @@ -943,7 +885,7 @@ static void pcnet_stop(PCNetState *s) #ifdef PCNET_DEBUG printf("pcnet_stop\n"); #endif - s->csr[0] &= ~0x7feb; + s->csr[0] &= ~0xffeb; s->csr[0] |= 0x0014; s->csr[4] &= ~0x02c2; s->csr[5] &= ~0x0011; @@ -956,19 +898,19 @@ static void pcnet_rdte_poll(PCNetState *s) if (s->rdra) { int bad = 0; #if 1 - target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); - target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); - target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s)); + hwaddr crda = pcnet_rdra_addr(s, CSR_RCVRC(s)); + hwaddr nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s)); + hwaddr nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s)); #else - target_phys_addr_t crda = s->rdra + + hwaddr crda = s->rdra + (CSR_RCVRL(s) - CSR_RCVRC(s)) * (BCR_SWSTYLE(s) ? 16 : 8 ); int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1; - target_phys_addr_t nrda = s->rdra + + hwaddr nrda = s->rdra + (CSR_RCVRL(s) - nrdc) * (BCR_SWSTYLE(s) ? 16 : 8 ); int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1; - target_phys_addr_t nnrd = s->rdra + + hwaddr nnrd = s->rdra + (CSR_RCVRL(s) - nnrc) * (BCR_SWSTYLE(s) ? 16 : 8 ); #endif @@ -1028,7 +970,7 @@ static int pcnet_tdte_poll(PCNetState *s) { s->csr[34] = s->csr[35] = 0; if (s->tdra) { - target_phys_addr_t cxda = s->tdra + + hwaddr cxda = s->tdra + (CSR_XMTRL(s) - CSR_XMTRC(s)) * (BCR_SWSTYLE(s) ? 16 : 8); int bad = 0; @@ -1062,32 +1004,30 @@ static int pcnet_tdte_poll(PCNetState *s) return !!(CSR_CXST(s) & 0x8000); } -static int pcnet_can_receive(VLANClientState *vc) +int pcnet_can_receive(NetClientState *nc) { - PCNetState *s = vc->opaque; + PCNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; if (CSR_STOP(s) || CSR_SPND(s)) return 0; - if (s->recv_pos > 0) - return 0; - return sizeof(s->buffer)-16; } #define MIN_BUF_SIZE 60 -static ssize_t pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t size_) +ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) { - PCNetState *s = vc->opaque; + PCNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; int is_padr = 0, is_bcast = 0, is_ladr = 0; uint8_t buf1[60]; int remaining; int crc_err = 0; int size = size_; - if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size) + if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size || + (CSR_LOOP(s) && !s->looptest)) { return -1; - + } #ifdef PCNET_DEBUG printf("pcnet_receive size=%d\n", size); #endif @@ -1110,7 +1050,7 @@ static ssize_t pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t siz if (!(CSR_CRST(s) & 0x8000) && s->rdra) { struct pcnet_RMD rmd; int rcvrc = CSR_RCVRC(s)-1,i; - target_phys_addr_t nrda; + hwaddr nrda; for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) { if (rcvrc <= 1) rcvrc = CSR_RCVRL(s); @@ -1138,7 +1078,7 @@ static ssize_t pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t siz CSR_MISSC(s)++; } else { uint8_t *src = s->buffer; - target_phys_addr_t crda = CSR_CRDA(s); + hwaddr crda = CSR_CRDA(s); struct pcnet_RMD rmd; int pktcount = 0; @@ -1178,7 +1118,7 @@ static ssize_t pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t siz #define PCNET_RECV_STORE() do { \ int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),remaining); \ - target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr); \ + hwaddr rbadr = PHYSADDR(s, rmd.rbadr); \ s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \ src += count; remaining -= count; \ SET_FIELD(&rmd.status, RMDS, OWN, 0); \ @@ -1189,7 +1129,7 @@ static ssize_t pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t siz remaining = size; PCNET_RECV_STORE(); if ((remaining > 0) && CSR_NRDA(s)) { - target_phys_addr_t nrda = CSR_NRDA(s); + hwaddr nrda = CSR_NRDA(s); #ifdef PCNET_DEBUG_RMD PRINT_RMD(&rmd); #endif @@ -1257,9 +1197,16 @@ static ssize_t pcnet_receive(VLANClientState *vc, const uint8_t *buf, size_t siz return size_; } +void pcnet_set_link_status(NetClientState *nc) +{ + PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; + + d->lnkst = nc->link_down ? 0 : 0x40; +} + static void pcnet_transmit(PCNetState *s) { - target_phys_addr_t xmit_cxda = 0; + hwaddr xmit_cxda = 0; int count = CSR_XMTRL(s)-1; int add_crc = 0; @@ -1288,6 +1235,15 @@ static void pcnet_transmit(PCNetState *s) if (BCR_SWSTYLE(s) != 1) add_crc = GET_FIELD(tmd.status, TMDS, ADDFCS); } + if (s->lnkst == 0 && + (!CSR_LOOP(s) || (!CSR_INTL(s) && !BCR_TMAULOOP(s)))) { + SET_FIELD(&tmd.misc, TMDM, LCAR, 1); + SET_FIELD(&tmd.status, TMDS, ERR, 1); + SET_FIELD(&tmd.status, TMDS, OWN, 0); + s->csr[0] |= 0xa000; /* ERR | CERR */ + s->xmit_pos = -1; + goto txdone; + } if (!GET_FIELD(tmd.status, TMDS, ENP)) { int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr), @@ -1305,17 +1261,18 @@ static void pcnet_transmit(PCNetState *s) if (BCR_SWSTYLE(s) == 1) add_crc = !GET_FIELD(tmd.status, TMDS, NOFCS); s->looptest = add_crc ? PCNET_LOOPTEST_CRC : PCNET_LOOPTEST_NOCRC; - pcnet_receive(s->vc, s->buffer, s->xmit_pos); + pcnet_receive(&s->nic->nc, s->buffer, s->xmit_pos); s->looptest = 0; } else - if (s->vc) - qemu_send_packet(s->vc, s->buffer, s->xmit_pos); + if (s->nic) + qemu_send_packet(&s->nic->nc, s->buffer, s->xmit_pos); s->csr[0] &= ~0x0008; /* clear TDMD */ s->csr[4] |= 0x0004; /* set TXSTRT */ s->xmit_pos = -1; } + txdone: SET_FIELD(&tmd.status, TMDS, OWN, 0); TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s))); if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT))) @@ -1378,7 +1335,7 @@ static void pcnet_poll_timer(void *opaque) pcnet_update_irq(s); if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) { - uint64_t now = qemu_get_clock(vm_clock) * 33; + uint64_t now = qemu_get_clock_ns(vm_clock) * 33; if (!s->timer || !now) s->timer = now; else { @@ -1390,7 +1347,7 @@ static void pcnet_poll_timer(void *opaque) CSR_POLL(s) = t; } qemu_mod_timer(s->poll_timer, - pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock))); + pcnet_get_next_poll_time(s,qemu_get_clock_ns(vm_clock))); } } @@ -1558,6 +1515,7 @@ static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val) #ifdef PCNET_DEBUG printf("BCR_SWS=0x%04x\n", val); #endif + /* fall through */ case BCR_LNKST: case BCR_LED1: case BCR_LED2: @@ -1574,7 +1532,7 @@ static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val) } } -static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) +uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) { uint32_t val; rap &= 127; @@ -1596,22 +1554,9 @@ static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) return val; } -static void pcnet_h_reset(void *opaque) +void pcnet_h_reset(void *opaque) { PCNetState *s = opaque; - int i; - uint16_t checksum; - - /* Initialize the PROM */ - - memcpy(s->prom, s->macaddr, 6); - s->prom[12] = s->prom[13] = 0x00; - s->prom[14] = s->prom[15] = 0x57; - - for (i = 0,checksum = 0; i < 16; i++) - checksum += s->prom[i]; - *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum); - s->bcr[BCR_MSRDA] = 0x0005; s->bcr[BCR_MSWRA] = 0x0005; @@ -1627,30 +1572,11 @@ static void pcnet_h_reset(void *opaque) s->bcr[BCR_PLAT ] = 0xff06; pcnet_s_reset(s); + pcnet_update_irq(s); + pcnet_poll_timer(s); } -static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) -{ - PCNetState *s = opaque; -#ifdef PCNET_DEBUG - printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); -#endif - /* Check APROMWE bit to enable write access */ - if (pcnet_bcr_readw(s,2) & 0x80) - s->prom[addr & 15] = val; -} - -static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) -{ - PCNetState *s = opaque; - uint32_t val = s->prom[addr &= 15]; -#ifdef PCNET_DEBUG - printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val); -#endif - return val; -} - -static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val) +void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val) { PCNetState *s = opaque; pcnet_poll_timer(s); @@ -1673,7 +1599,7 @@ static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val) pcnet_update_irq(s); } -static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr) +uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr) { PCNetState *s = opaque; uint32_t val = -1; @@ -1702,7 +1628,7 @@ static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr) return val; } -static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) +void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) { PCNetState *s = opaque; pcnet_poll_timer(s); @@ -1732,7 +1658,7 @@ static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) pcnet_update_irq(s); } -static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) +uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) { PCNetState *s = opaque; uint32_t val = -1; @@ -1761,394 +1687,81 @@ static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) return val; } -static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) +static bool is_version_2(void *opaque, int version_id) { - PCNetState *d = &((PCIPCNetState *)pci_dev)->state; - -#ifdef PCNET_DEBUG_IO - printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size); -#endif - - register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); - register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); - - register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); - register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); - register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); - register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d); -} - -static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCNetState *d = opaque; -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr, - val); -#endif - if (!(addr & 0x10)) - pcnet_aprom_writeb(d, addr & 0x0f, val); -} - -static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) -{ - PCNetState *d = opaque; - uint32_t val = -1; - if (!(addr & 0x10)) - val = pcnet_aprom_readb(d, addr & 0x0f); -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, - val & 0xff); -#endif - return val; + return version_id == 2; } -static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - PCNetState *d = opaque; -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, - val); -#endif - if (addr & 0x10) - pcnet_ioport_writew(d, addr & 0x0f, val); - else { - addr &= 0x0f; - pcnet_aprom_writeb(d, addr, val & 0xff); - pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); +const VMStateDescription vmstate_pcnet = { + .name = "pcnet", + .version_id = 3, + .minimum_version_id = 2, + .minimum_version_id_old = 2, + .fields = (VMStateField []) { + VMSTATE_INT32(rap, PCNetState), + VMSTATE_INT32(isr, PCNetState), + VMSTATE_INT32(lnkst, PCNetState), + VMSTATE_UINT32(rdra, PCNetState), + VMSTATE_UINT32(tdra, PCNetState), + VMSTATE_BUFFER(prom, PCNetState), + VMSTATE_UINT16_ARRAY(csr, PCNetState, 128), + VMSTATE_UINT16_ARRAY(bcr, PCNetState, 32), + VMSTATE_UINT64(timer, PCNetState), + VMSTATE_INT32(xmit_pos, PCNetState), + VMSTATE_BUFFER(buffer, PCNetState), + VMSTATE_UNUSED_TEST(is_version_2, 4), + VMSTATE_INT32(tx_busy, PCNetState), + VMSTATE_TIMER(poll_timer, PCNetState), + VMSTATE_END_OF_LIST() } -} +}; -static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) +void pcnet_common_cleanup(PCNetState *d) { - PCNetState *d = opaque; - uint32_t val = -1; - if (addr & 0x10) - val = pcnet_ioport_readw(d, addr & 0x0f); - else { - addr &= 0x0f; - val = pcnet_aprom_readb(d, addr+1); - val <<= 8; - val |= pcnet_aprom_readb(d, addr); - } -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr, - val & 0xffff); -#endif - return val; + d->nic = NULL; } -static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info) { - PCNetState *d = opaque; -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr, - val); -#endif - if (addr & 0x10) - pcnet_ioport_writel(d, addr & 0x0f, val); - else { - addr &= 0x0f; - pcnet_aprom_writeb(d, addr, val & 0xff); - pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); - pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); - pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); - } -} + int i; + uint16_t checksum; -static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) -{ - PCNetState *d = opaque; - uint32_t val; - if (addr & 0x10) - val = pcnet_ioport_readl(d, addr & 0x0f); - else { - addr &= 0x0f; - val = pcnet_aprom_readb(d, addr+3); - val <<= 8; - val |= pcnet_aprom_readb(d, addr+2); - val <<= 8; - val |= pcnet_aprom_readb(d, addr+1); - val <<= 8; - val |= pcnet_aprom_readb(d, addr); - } -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, - val); -#endif - return val; -} + s->poll_timer = qemu_new_timer_ns(vm_clock, pcnet_poll_timer, s); + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(info, &s->conf, object_get_typename(OBJECT(dev)), dev->id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); -static void pcnet_save(QEMUFile *f, void *opaque) -{ - PCNetState *s = opaque; - unsigned int i; - - if (s->pci_dev) - pci_device_save(s->pci_dev, f); - - qemu_put_sbe32(f, s->rap); - qemu_put_sbe32(f, s->isr); - qemu_put_sbe32(f, s->lnkst); - qemu_put_be32s(f, &s->rdra); - qemu_put_be32s(f, &s->tdra); - qemu_put_buffer(f, s->prom, 16); - for (i = 0; i < 128; i++) - qemu_put_be16s(f, &s->csr[i]); - for (i = 0; i < 32; i++) - qemu_put_be16s(f, &s->bcr[i]); - qemu_put_be64s(f, &s->timer); - qemu_put_sbe32(f, s->xmit_pos); - qemu_put_sbe32(f, s->recv_pos); - qemu_put_buffer(f, s->buffer, 4096); - qemu_put_sbe32(f, s->tx_busy); - qemu_put_timer(f, s->poll_timer); -} + add_boot_device_path(s->conf.bootindex, dev, "/ethernet-phy@0"); -static int pcnet_load(QEMUFile *f, void *opaque, int version_id) -{ - PCNetState *s = opaque; - int i, ret; + /* Initialize the PROM */ - if (version_id != 2) - return -EINVAL; + /* + Datasheet: http://pdfdata.datasheetsite.com/web/24528/AM79C970A.pdf + page 95 + */ + memcpy(s->prom, s->conf.macaddr.a, 6); + /* Reserved Location: must be 00h */ + s->prom[6] = s->prom[7] = 0x00; + /* Reserved Location: must be 00h */ + s->prom[8] = 0x00; + /* Hardware ID: must be 11h if compatibility to AMD drivers is desired */ + s->prom[9] = 0x11; + /* User programmable space, init with 0 */ + s->prom[10] = s->prom[11] = 0x00; + /* LSByte of two-byte checksum, which is the sum of bytes 00h-0Bh + and bytes 0Eh and 0Fh, must therefore be initialized with 0! */ + s->prom[12] = s->prom[13] = 0x00; + /* Must be ASCII W (57h) if compatibility to AMD + driver software is desired */ + s->prom[14] = s->prom[15] = 0x57; - if (s->pci_dev) { - ret = pci_device_load(s->pci_dev, f); - if (ret < 0) - return ret; + for (i = 0, checksum = 0; i < 16; i++) { + checksum += s->prom[i]; } + *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum); - qemu_get_sbe32s(f, &s->rap); - qemu_get_sbe32s(f, &s->isr); - qemu_get_sbe32s(f, &s->lnkst); - qemu_get_be32s(f, &s->rdra); - qemu_get_be32s(f, &s->tdra); - qemu_get_buffer(f, s->prom, 16); - for (i = 0; i < 128; i++) - qemu_get_be16s(f, &s->csr[i]); - for (i = 0; i < 32; i++) - qemu_get_be16s(f, &s->bcr[i]); - qemu_get_be64s(f, &s->timer); - qemu_get_sbe32s(f, &s->xmit_pos); - qemu_get_sbe32s(f, &s->recv_pos); - qemu_get_buffer(f, s->buffer, 4096); - qemu_get_sbe32s(f, &s->tx_busy); - qemu_get_timer(f, s->poll_timer); - - return 0; -} - -static void pcnet_common_cleanup(PCNetState *d) -{ - unregister_savevm("pcnet", d); - - qemu_del_timer(d->poll_timer); - qemu_free_timer(d->poll_timer); -} - -static void pcnet_common_init(DeviceState *dev, PCNetState *s, - NetCleanup *cleanup) -{ - s->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, s); - - qdev_get_macaddr(dev, s->macaddr); - s->vc = qdev_get_vlan_client(dev, - pcnet_can_receive, pcnet_receive, NULL, - cleanup, s); - pcnet_h_reset(s); - register_savevm("pcnet", -1, 2, pcnet_save, pcnet_load, s); -} - -/* PCI interface */ - -static CPUWriteMemoryFunc *pcnet_mmio_write[] = { - (CPUWriteMemoryFunc *)&pcnet_mmio_writeb, - (CPUWriteMemoryFunc *)&pcnet_mmio_writew, - (CPUWriteMemoryFunc *)&pcnet_mmio_writel -}; - -static CPUReadMemoryFunc *pcnet_mmio_read[] = { - (CPUReadMemoryFunc *)&pcnet_mmio_readb, - (CPUReadMemoryFunc *)&pcnet_mmio_readw, - (CPUReadMemoryFunc *)&pcnet_mmio_readl -}; - -static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, - uint32_t addr, uint32_t size, int type) -{ - PCIPCNetState *d = (PCIPCNetState *)pci_dev; - -#ifdef PCNET_DEBUG_IO - printf("pcnet_mmio_map addr=0x%08x 0x%08x\n", addr, size); -#endif - - cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index); -} - -static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int do_bswap) -{ - cpu_physical_memory_write(addr, buf, len); -} - -static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int do_bswap) -{ - cpu_physical_memory_read(addr, buf, len); -} - -static void pci_pcnet_cleanup(VLANClientState *vc) -{ - PCNetState *d = vc->opaque; - - pcnet_common_cleanup(d); -} - -static int pci_pcnet_uninit(PCIDevice *dev) -{ - PCIPCNetState *d = (PCIPCNetState *)dev; - - cpu_unregister_io_memory(d->state.mmio_index); + s->lnkst = 0x40; /* initial link state: up */ return 0; } - -static void pci_pcnet_init(PCIDevice *pci_dev) -{ - PCIPCNetState *d = (PCIPCNetState *)pci_dev; - PCNetState *s = &d->state; - uint8_t *pci_conf; - -#if 0 - printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", - sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD)); -#endif - - pci_dev->unregister = pci_pcnet_uninit; - - pci_conf = pci_dev->config; - - pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD); - pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE); - *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007); - *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280); - pci_conf[0x08] = 0x10; - pci_conf[0x09] = 0x00; - pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET); - pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type - - *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001); - *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000); - - pci_conf[0x3d] = 1; // interrupt pin 0 - pci_conf[0x3e] = 0x06; - pci_conf[0x3f] = 0xff; - - /* Handler for memory-mapped I/O */ - s->mmio_index = - cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, &d->state); - - pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, - PCI_ADDRESS_SPACE_IO, pcnet_ioport_map); - - pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, - PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); - - s->irq = pci_dev->irq[0]; - s->phys_mem_read = pci_physical_memory_read; - s->phys_mem_write = pci_physical_memory_write; - s->pci_dev = pci_dev; - - pcnet_common_init(&pci_dev->qdev, s, pci_pcnet_cleanup); -} - -/* SPARC32 interface */ - -#if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) // Avoid compile failure -#include "sun4m.h" - -static void parent_lance_reset(void *opaque, int irq, int level) -{ - SysBusPCNetState *d = opaque; - if (level) - pcnet_h_reset(&d->state); -} - -static void lance_mem_writew(void *opaque, target_phys_addr_t addr, - uint32_t val) -{ - SysBusPCNetState *d = opaque; -#ifdef PCNET_DEBUG_IO - printf("lance_mem_writew addr=" TARGET_FMT_plx " val=0x%04x\n", addr, - val & 0xffff); -#endif - pcnet_ioport_writew(&d->state, addr, val & 0xffff); -} - -static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) -{ - SysBusPCNetState *d = opaque; - uint32_t val; - - val = pcnet_ioport_readw(&d->state, addr); -#ifdef PCNET_DEBUG_IO - printf("lance_mem_readw addr=" TARGET_FMT_plx " val = 0x%04x\n", addr, - val & 0xffff); -#endif - - return val & 0xffff; -} - -static CPUReadMemoryFunc *lance_mem_read[3] = { - NULL, - lance_mem_readw, - NULL, -}; - -static CPUWriteMemoryFunc *lance_mem_write[3] = { - NULL, - lance_mem_writew, - NULL, -}; - -static void lance_cleanup(VLANClientState *vc) -{ - PCNetState *d = vc->opaque; - - pcnet_common_cleanup(d); -} - -static void lance_init(SysBusDevice *dev) -{ - SysBusPCNetState *d = FROM_SYSBUS(SysBusPCNetState, dev); - PCNetState *s = &d->state; - - s->mmio_index = - cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); - - s->dma_opaque = qdev_get_prop_ptr(&dev->qdev, "dma"); - - qdev_init_gpio_in(&dev->qdev, parent_lance_reset, 1); - - sysbus_init_mmio(dev, 4, s->mmio_index); - - sysbus_init_irq(dev, &s->irq); - - s->phys_mem_read = ledma_memory_read; - s->phys_mem_write = ledma_memory_write; - - pcnet_common_init(&dev->qdev, s, lance_cleanup); -} -#endif /* TARGET_SPARC */ - -static void pcnet_register_devices(void) -{ - pci_qdev_register("pcnet", sizeof(PCIPCNetState), pci_pcnet_init); -#if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) - sysbus_register_dev("lance", sizeof(SysBusPCNetState), lance_init); -#endif -} - -device_init(pcnet_register_devices)