/**
* QEMU RTL8139 emulation
- *
+ *
* Copyright (c) 2006 Igor Kovalenko
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
-
+
* Modifications:
* 2006-Jan-28 Mark Malakanov : TSAD and CSCR implementation (for Windows driver)
- *
+ *
* 2006-Apr-28 Juergen Lock : EEPROM emulation changes for FreeBSD driver
* HW revision ID changes for FreeBSD driver
- *
+ *
* 2006-Jul-01 Igor Kovalenko : Implemented loopback mode for FreeBSD driver
* Corrected packet transfer reassembly routine for 8139C+ mode
* Rearranged debugging print statements
* Added rx/tx buffer reset when enabling rx/tx operation
*/
-#include "vl.h"
+#include "hw.h"
+#include "pci.h"
+#include "qemu-timer.h"
+#include "net.h"
/* debug RTL8139 card */
//#define DEBUG_RTL8139 1
/* debug RTL8139 card C+ mode only */
//#define DEBUG_RTL8139CP 1
-/* RTL8139 provides frame CRC with received packet, this feature seems to be
- ignored by most drivers, disabled by default */
-//#define RTL8139_CALCULATE_RXCRC 1
+/* Calculate CRCs properly on Rx packets */
+#define RTL8139_CALCULATE_RXCRC 1
/* Uncomment to enable on-board timer interrupts */
//#define RTL8139_ONBOARD_TIMER 1
CSCR_LinkDownCmd = 0x0f3c0,
*/
enum CSCRBits {
- CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
+ CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
CSCR_LD = 1<<9, /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/
CSCR_HEART_BIT = 1<<8, /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/
CSCR_JBEN = 1<<7, /* 1 = enable jabber function. 0 = disable jabber function, def 1*/
- CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/
+ CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/
CSCR_F_Connect = 1<<5, /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/
CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/
CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/
uint16_t CpCmd;
uint8_t TxThresh;
- int irq;
PCIDevice *pci_dev;
VLANClientState *vc;
uint8_t macaddr[6];
} RTL8139State;
-void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
+static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
{
DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command));
}
}
-void prom9346_shift_clock(EEprom9346 *eeprom)
+static void prom9346_shift_clock(EEprom9346 *eeprom)
{
int bit = eeprom->eedi?1:0;
}
}
-int prom9346_get_wire(RTL8139State *s)
+static int prom9346_get_wire(RTL8139State *s)
{
EEprom9346 *eeprom = &s->eeprom;
if (!eeprom->eecs)
return eeprom->eedo;
}
-void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi)
+/* FIXME: This should be merged into/replaced by eeprom93xx.c. */
+static void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi)
{
EEprom9346 *eeprom = &s->eeprom;
uint8_t old_eecs = eeprom->eecs;
int isr;
isr = (s->IntrStatus & s->IntrMask) & 0xffff;
- DEBUG_PRINT(("RTL8139: Set IRQ line %d to %d (%04x %04x)\n",
- s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask));
+ DEBUG_PRINT(("RTL8139: Set IRQ to %d (%04x %04x)\n",
+ isr ? 1 : 0, s->IntrStatus, s->IntrMask));
- if (s->irq == 16) {
- /* PCI irq */
- pci_set_irq(s->pci_dev, 0, (isr != 0));
- } else {
- /* ISA irq */
- pic_set_irq(s->irq, (isr != 0));
- }
+ qemu_set_irq(s->pci_dev->irq[0], (isr != 0));
}
#define POLYNOMIAL 0x04c11db6
int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize);
/* write packet data */
- if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s))
+ if (wrapped && !(s->RxBufferSize < 65536 && rtl8139_RxWrap(s)))
{
DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped));
RTL8139State *s = opaque;
int avail;
- /* Recieve (drop) packets if card is disabled. */
+ /* Receive (drop) packets if card is disabled. */
if (!s->clock_enabled)
return 1;
if (!rtl8139_receiver_enabled(s))
uint32_t packet_header = 0;
uint8_t buf1[60];
- static const uint8_t broadcast_macaddr[6] =
+ static const uint8_t broadcast_macaddr[6] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
DEBUG_PRINT((">>> RTL8139: received len=%d\n", size));
++s->tally_counters.RxOkMul;
} else if (s->phys[0] == buf[0] &&
- s->phys[1] == buf[1] &&
- s->phys[2] == buf[2] &&
- s->phys[3] == buf[3] &&
- s->phys[4] == buf[4] &&
+ s->phys[1] == buf[1] &&
+ s->phys[2] == buf[2] &&
+ s->phys[3] == buf[3] &&
+ s->phys[4] == buf[4] &&
s->phys[5] == buf[5]) {
/* match */
if (!(s->RxConfig & AcceptMyPhys))
/* write checksum */
#if defined (RTL8139_CALCULATE_RXCRC)
- val = cpu_to_le32(crc32(~0, buf, size));
+ val = cpu_to_le32(crc32(0, buf, size));
#else
val = 0;
#endif
/* write checksum */
#if defined (RTL8139_CALCULATE_RXCRC)
- val = cpu_to_le32(crc32(~0, buf, size));
+ val = cpu_to_le32(crc32(0, buf, size));
#else
val = 0;
#endif
s->eeprom.contents[1] = 0x10ec;
s->eeprom.contents[2] = 0x8139;
#endif
- memcpy(&s->eeprom.contents[7], s->macaddr, 6);
+
+ s->eeprom.contents[7] = s->macaddr[0] | s->macaddr[1] << 8;
+ s->eeprom.contents[8] = s->macaddr[2] | s->macaddr[3] << 8;
+ s->eeprom.contents[9] = s->macaddr[4] | s->macaddr[5] << 8;
/* mark all status registers as owned by host */
for (i = 0; i < 4; ++i)
s->Config3 = 0x1; /* fast back-to-back compatible */
s->Config5 = 0x0;
- s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
+ s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
s->CpCmd = 0x0; /* reset C+ mode */
return ret;
}
-int rtl8139_config_writeable(RTL8139State *s)
+static int rtl8139_config_writeable(RTL8139State *s)
{
if (s->Cfg9346 & Cfg9346_Unlock)
{
DEBUG_PRINT(("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val));
/* mask unwriteable bits */
- uint32 mask = 0x4cff;
+ uint32_t mask = 0x4cff;
if (1 || !rtl8139_config_writeable(s))
{
while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
{
s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
- s->cplus_txbuffer = realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
+ s->cplus_txbuffer = qemu_realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len));
}
|((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0)
|((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0)
|((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0)
-
+
|((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0)
|((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0)
|((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0)
|((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0)
-
+
|((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0)
|((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0)
|((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0)
|((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ;
-
+
DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret));
{
DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val));
- s->TxAddr[txAddrOffset/4] = le32_to_cpu(val);
+ s->TxAddr[txAddrOffset/4] = val;
}
static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset)
{
- uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]);
+ uint32_t ret = s->TxAddr[txAddrOffset/4];
DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret));
default:
DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val));
-#ifdef TARGET_WORDS_BIGENDIAN
- rtl8139_io_writeb(opaque, addr, (val >> 8) & 0xff);
- rtl8139_io_writeb(opaque, addr + 1, val & 0xff);
-#else
rtl8139_io_writeb(opaque, addr, val & 0xff);
rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
break;
}
}
default:
DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val));
-#ifdef TARGET_WORDS_BIGENDIAN
- rtl8139_io_writeb(opaque, addr, (val >> 24) & 0xff);
- rtl8139_io_writeb(opaque, addr + 1, (val >> 16) & 0xff);
- rtl8139_io_writeb(opaque, addr + 2, (val >> 8) & 0xff);
- rtl8139_io_writeb(opaque, addr + 3, val & 0xff);
-#else
rtl8139_io_writeb(opaque, addr, val & 0xff);
rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff);
rtl8139_io_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-#endif
break;
}
}
default:
DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr));
-#ifdef TARGET_WORDS_BIGENDIAN
- ret = rtl8139_io_readb(opaque, addr) << 8;
- ret |= rtl8139_io_readb(opaque, addr + 1);
-#else
ret = rtl8139_io_readb(opaque, addr);
ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
-#endif
DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret));
break;
default:
DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr));
-#ifdef TARGET_WORDS_BIGENDIAN
- ret = rtl8139_io_readb(opaque, addr) << 24;
- ret |= rtl8139_io_readb(opaque, addr + 1) << 16;
- ret |= rtl8139_io_readb(opaque, addr + 2) << 8;
- ret |= rtl8139_io_readb(opaque, addr + 3);
-#else
ret = rtl8139_io_readb(opaque, addr);
ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
ret |= rtl8139_io_readb(opaque, addr + 2) << 16;
ret |= rtl8139_io_readb(opaque, addr + 3) << 24;
-#endif
DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret));
break;
static void rtl8139_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
{
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
rtl8139_io_writew(opaque, addr & 0xFF, val);
}
static void rtl8139_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
rtl8139_io_writel(opaque, addr & 0xFF, val);
}
static uint32_t rtl8139_mmio_readw(void *opaque, target_phys_addr_t addr)
{
- return rtl8139_io_readw(opaque, addr & 0xFF);
+ uint32_t val = rtl8139_io_readw(opaque, addr & 0xFF);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ return val;
}
static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr)
{
- return rtl8139_io_readl(opaque, addr & 0xFF);
+ uint32_t val = rtl8139_io_readl(opaque, addr & 0xFF);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
}
/* */
static void rtl8139_save(QEMUFile* f,void* opaque)
{
RTL8139State* s=(RTL8139State*)opaque;
- int i;
+ unsigned int i;
+
+ pci_device_save(s->pci_dev, f);
qemu_put_buffer(f, s->phys, 6);
qemu_put_buffer(f, s->mult, 8);
qemu_put_be16s(f, &s->CpCmd);
qemu_put_8s(f, &s->TxThresh);
- qemu_put_be32s(f, &s->irq);
+ i = 0;
+ qemu_put_be32s(f, &i); /* unused. */
qemu_put_buffer(f, s->macaddr, 6);
- qemu_put_be32s(f, &s->rtl8139_mmio_io_addr);
+ qemu_put_be32(f, s->rtl8139_mmio_io_addr);
qemu_put_be32s(f, &s->currTxDesc);
qemu_put_be32s(f, &s->currCPlusRxDesc);
{
qemu_put_be16s(f, &s->eeprom.contents[i]);
}
- qemu_put_be32s(f, &s->eeprom.mode);
+ qemu_put_be32(f, s->eeprom.mode);
qemu_put_be32s(f, &s->eeprom.tick);
qemu_put_8s(f, &s->eeprom.address);
qemu_put_be16s(f, &s->eeprom.input);
qemu_put_be32s(f, &s->TCTR);
qemu_put_be32s(f, &s->TimerInt);
- qemu_put_be64s(f, &s->TCTR_base);
+ qemu_put_be64(f, s->TCTR_base);
RTL8139TallyCounters_save(f, &s->tally_counters);
}
static int rtl8139_load(QEMUFile* f,void* opaque,int version_id)
{
RTL8139State* s=(RTL8139State*)opaque;
- int i;
+ unsigned int i;
+ int ret;
/* just 2 versions for now */
- if (version_id > 2)
+ if (version_id > 3)
return -EINVAL;
+ if (version_id >= 3) {
+ ret = pci_device_load(s->pci_dev, f);
+ if (ret < 0)
+ return ret;
+ }
+
/* saved since version 1 */
qemu_get_buffer(f, s->phys, 6);
qemu_get_buffer(f, s->mult, 8);
qemu_get_be16s(f, &s->CpCmd);
qemu_get_8s(f, &s->TxThresh);
- qemu_get_be32s(f, &s->irq);
+ qemu_get_be32s(f, &i); /* unused. */
qemu_get_buffer(f, s->macaddr, 6);
- qemu_get_be32s(f, &s->rtl8139_mmio_io_addr);
+ s->rtl8139_mmio_io_addr=qemu_get_be32(f);
qemu_get_be32s(f, &s->currTxDesc);
qemu_get_be32s(f, &s->currCPlusRxDesc);
{
qemu_get_be16s(f, &s->eeprom.contents[i]);
}
- qemu_get_be32s(f, &s->eeprom.mode);
+ s->eeprom.mode=qemu_get_be32(f);
qemu_get_be32s(f, &s->eeprom.tick);
qemu_get_8s(f, &s->eeprom.address);
qemu_get_be16s(f, &s->eeprom.input);
{
qemu_get_be32s(f, &s->TCTR);
qemu_get_be32s(f, &s->TimerInt);
- qemu_get_be64s(f, &s->TCTR_base);
+ s->TCTR_base=qemu_get_be64(f);
RTL8139TallyCounters_load(f, &s->tally_counters);
}
RTL8139State rtl8139;
} PCIRTL8139State;
-static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num,
+static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
PCIRTL8139State *d = (PCIRTL8139State *)pci_dev;
cpu_register_physical_memory(addr + 0, 0x100, s->rtl8139_mmio_io_addr);
}
-static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num,
+static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
PCIRTL8139State *d = (PCIRTL8139State *)pci_dev;
static inline int64_t rtl8139_get_next_tctr_time(RTL8139State *s, int64_t current_time)
{
- int64_t next_time = current_time +
+ int64_t next_time = current_time +
muldiv64(1, ticks_per_sec, PCI_FREQUENCY);
if (next_time <= current_time)
next_time = current_time + 1;
return next_time;
}
-#if RTL8139_ONBOARD_TIMER
+#ifdef RTL8139_ONBOARD_TIMER
static void rtl8139_timer(void *opaque)
{
RTL8139State *s = opaque;
rtl8139_update_irq(s);
}
- qemu_mod_timer(s->timer,
+ qemu_mod_timer(s->timer,
rtl8139_get_next_tctr_time(s,curr_time));
}
#endif /* RTL8139_ONBOARD_TIMER */
-void pci_rtl8139_init(PCIBus *bus, NICInfo *nd)
+void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn)
{
PCIRTL8139State *d;
RTL8139State *s;
uint8_t *pci_conf;
-
+
d = (PCIRTL8139State *)pci_register_device(bus,
"RTL8139", sizeof(PCIRTL8139State),
- -1,
+ devfn,
NULL, NULL);
pci_conf = d->dev.config;
pci_conf[0x00] = 0xec; /* Realtek 8139 */
s->rtl8139_mmio_io_addr =
cpu_register_io_memory(0, rtl8139_mmio_read, rtl8139_mmio_write, s);
- pci_register_io_region(&d->dev, 0, 0x100,
+ pci_register_io_region(&d->dev, 0, 0x100,
PCI_ADDRESS_SPACE_IO, rtl8139_ioport_map);
- pci_register_io_region(&d->dev, 1, 0x100,
+ pci_register_io_region(&d->dev, 1, 0x100,
PCI_ADDRESS_SPACE_MEM, rtl8139_mmio_map);
- s->irq = 16; /* PCI interrupt */
s->pci_dev = (PCIDevice *)d;
memcpy(s->macaddr, nd->macaddr, 6);
rtl8139_reset(s);
s->cplus_txbuffer = NULL;
s->cplus_txbuffer_len = 0;
s->cplus_txbuffer_offset = 0;
-
- /* XXX: instance number ? */
- register_savevm("rtl8139", 0, 2, rtl8139_save, rtl8139_load, s);
- register_savevm("rtl8139_pci", 0, 1, generic_pci_save, generic_pci_load,
- &d->dev);
-#if RTL8139_ONBOARD_TIMER
+ register_savevm("rtl8139", -1, 3, rtl8139_save, rtl8139_load, s);
+
+#ifdef RTL8139_ONBOARD_TIMER
s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s);
- qemu_mod_timer(s->timer,
+ qemu_mod_timer(s->timer,
rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock)));
#endif /* RTL8139_ONBOARD_TIMER */
}