#include "hw.h"
#include "pci.h"
+#include "dma.h"
#include "qemu-timer.h"
#include "net.h"
#include "loader.h"
#define PCI_FREQUENCY 33000000L
-/* debug RTL8139 card C+ mode only */
-//#define DEBUG_RTL8139CP 1
-
#define SET_MASKED(input, mask, curr) \
( ( (input) & ~(mask) ) | ( (curr) & (mask) ) )
PCIErr = 0x8000,
PCSTimeout = 0x4000,
RxFIFOOver = 0x40,
- RxUnderrun = 0x20,
+ RxUnderrun = 0x20, /* Packet Underrun / Link Change */
RxOverflow = 0x10,
TxErr = 0x08,
TxOK = 0x04,
};
enum Cfg9346Bits {
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
+ Cfg9346_Normal = 0x00,
+ Cfg9346_Autoload = 0x40,
+ Cfg9346_Programming = 0x80,
+ Cfg9346_ConfigWrite = 0xC0,
};
typedef enum {
/* Clears all tally counters */
static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters);
-/* Writes tally counters to specified physical memory address */
-static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* counters);
-
typedef struct RTL8139State {
PCIDevice dev;
uint8_t phys[8]; /* mac address */
int rtl8139_mmio_io_addr_dummy;
} RTL8139State;
+/* Writes tally counters to memory via DMA */
+static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr);
+
static void rtl8139_set_next_tctr_time(RTL8139State *s, int64_t current_time);
static void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
qemu_set_irq(s->dev.irq[0], (isr != 0));
}
-#define POLYNOMIAL 0x04c11db6
-
-/* From FreeBSD */
-/* XXX: optimize */
-static int compute_mcast_idx(const uint8_t *ep)
-{
- uint32_t crc;
- int carry, i, j;
- uint8_t b;
-
- crc = 0xffffffff;
- for (i = 0; i < 6; i++) {
- b = *ep++;
- for (j = 0; j < 8; j++) {
- carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
- crc <<= 1;
- b >>= 1;
- if (carry)
- crc = ((crc ^ POLYNOMIAL) | carry);
- }
- }
- return (crc >> 26);
-}
-
static int rtl8139_RxWrap(RTL8139State *s)
{
/* wrapping enabled; assume 1.5k more buffer space if size < 65536 */
if (size > wrapped)
{
- cpu_physical_memory_write( s->RxBuf + s->RxBufAddr,
- buf, size-wrapped );
+ pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr,
+ buf, size-wrapped);
}
/* reset buffer pointer */
s->RxBufAddr = 0;
- cpu_physical_memory_write( s->RxBuf + s->RxBufAddr,
- buf + (size-wrapped), wrapped );
+ pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr,
+ buf + (size-wrapped), wrapped);
s->RxBufAddr = wrapped;
}
/* non-wrapping path or overwrapping enabled */
- cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, buf, size );
+ pci_dma_write(&s->dev, s->RxBuf + s->RxBufAddr, buf, size);
s->RxBufAddr += size;
}
#define MIN_BUF_SIZE 60
-static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
+static inline dma_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
{
-#if TARGET_PHYS_ADDR_BITS > 32
- return low | ((target_phys_addr_t)high << 32);
-#else
- return low;
-#endif
+ return low | ((uint64_t)high << 32);
}
-static int rtl8139_can_receive(VLANClientState *nc)
+/* Workaround for buggy guest driver such as linux who allocates rx
+ * rings after the receiver were enabled. */
+static bool rtl8139_cp_rx_valid(RTL8139State *s)
+{
+ return !(s->RxRingAddrLO == 0 && s->RxRingAddrHI == 0);
+}
+
+static int rtl8139_can_receive(NetClientState *nc)
{
RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
int avail;
if (!rtl8139_receiver_enabled(s))
return 1;
- if (rtl8139_cp_receiver_enabled(s)) {
+ if (rtl8139_cp_receiver_enabled(s) && rtl8139_cp_rx_valid(s)) {
/* ??? Flow control not implemented in c+ mode.
This is a hack to work around slirp deficiencies anyway. */
return 1;
} else {
avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
s->RxBufferSize);
- return (avail == 0 || avail >= 1514);
+ return (avail == 0 || avail >= 1514 || (s->IntrMask & RxOverflow));
}
}
-static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt)
+static ssize_t rtl8139_do_receive(NetClientState *nc, const uint8_t *buf, size_t size_, int do_interrupt)
{
RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
/* size is the length of the buffer passed to the driver */
if (rtl8139_cp_receiver_enabled(s))
{
+ if (!rtl8139_cp_rx_valid(s)) {
+ return size;
+ }
+
DPRINTF("in C+ Rx mode ================\n");
/* begin C+ receiver mode */
/* w3 high 32bit of Rx buffer ptr */
int descriptor = s->currCPlusRxDesc;
- target_phys_addr_t cplus_rx_ring_desc;
+ dma_addr_t cplus_rx_ring_desc;
cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI);
cplus_rx_ring_desc += 16 * descriptor;
DPRINTF("+++ C+ mode reading RX descriptor %d from host memory at "
- "%08x %08x = "TARGET_FMT_plx"\n", descriptor, s->RxRingAddrHI,
+ "%08x %08x = "DMA_ADDR_FMT"\n", descriptor, s->RxRingAddrHI,
s->RxRingAddrLO, cplus_rx_ring_desc);
uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
- cpu_physical_memory_read(cplus_rx_ring_desc, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_rx_ring_desc, &val, 4);
rxdw0 = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_rx_ring_desc+4, &val, 4);
rxdw1 = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_rx_ring_desc+8, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_rx_ring_desc+8, &val, 4);
rxbufLO = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_rx_ring_desc+12, &val, 4);
rxbufHI = le32_to_cpu(val);
DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
return size_;
}
- target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
+ dma_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
/* receive/copy to target memory */
if (dot1q_buf) {
- cpu_physical_memory_write(rx_addr, buf, 2 * ETHER_ADDR_LEN);
- cpu_physical_memory_write(rx_addr + 2 * ETHER_ADDR_LEN,
- buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN,
- size - 2 * ETHER_ADDR_LEN);
+ pci_dma_write(&s->dev, rx_addr, buf, 2 * ETHER_ADDR_LEN);
+ pci_dma_write(&s->dev, rx_addr + 2 * ETHER_ADDR_LEN,
+ buf + 2 * ETHER_ADDR_LEN + VLAN_HLEN,
+ size - 2 * ETHER_ADDR_LEN);
} else {
- cpu_physical_memory_write(rx_addr, buf, size);
+ pci_dma_write(&s->dev, rx_addr, buf, size);
}
if (s->CpCmd & CPlusRxChkSum)
/* write checksum */
val = cpu_to_le32(crc32(0, buf, size_));
- cpu_physical_memory_write( rx_addr+size, (uint8_t *)&val, 4);
+ pci_dma_write(&s->dev, rx_addr+size, (uint8_t *)&val, 4);
/* first segment of received packet flag */
#define CP_RX_STATUS_FS (1<<29)
/* update ring data */
val = cpu_to_le32(rxdw0);
- cpu_physical_memory_write(cplus_rx_ring_desc, (uint8_t *)&val, 4);
+ pci_dma_write(&s->dev, cplus_rx_ring_desc, (uint8_t *)&val, 4);
val = cpu_to_le32(rxdw1);
- cpu_physical_memory_write(cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
+ pci_dma_write(&s->dev, cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
/* update tally counter */
++s->tally_counters.RxOk;
return size_;
}
-static ssize_t rtl8139_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
+static ssize_t rtl8139_receive(NetClientState *nc, const uint8_t *buf, size_t size)
{
return rtl8139_do_receive(nc, buf, size, 1);
}
counters->TxUndrn = 0;
}
-static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* tally_counters)
+static void RTL8139TallyCounters_dma_write(RTL8139State *s, dma_addr_t tc_addr)
{
+ RTL8139TallyCounters *tally_counters = &s->tally_counters;
uint16_t val16;
uint32_t val32;
uint64_t val64;
val64 = cpu_to_le64(tally_counters->TxOk);
- cpu_physical_memory_write(tc_addr + 0, (uint8_t *)&val64, 8);
+ pci_dma_write(&s->dev, tc_addr + 0, (uint8_t *)&val64, 8);
val64 = cpu_to_le64(tally_counters->RxOk);
- cpu_physical_memory_write(tc_addr + 8, (uint8_t *)&val64, 8);
+ pci_dma_write(&s->dev, tc_addr + 8, (uint8_t *)&val64, 8);
val64 = cpu_to_le64(tally_counters->TxERR);
- cpu_physical_memory_write(tc_addr + 16, (uint8_t *)&val64, 8);
+ pci_dma_write(&s->dev, tc_addr + 16, (uint8_t *)&val64, 8);
val32 = cpu_to_le32(tally_counters->RxERR);
- cpu_physical_memory_write(tc_addr + 24, (uint8_t *)&val32, 4);
+ pci_dma_write(&s->dev, tc_addr + 24, (uint8_t *)&val32, 4);
val16 = cpu_to_le16(tally_counters->MissPkt);
- cpu_physical_memory_write(tc_addr + 28, (uint8_t *)&val16, 2);
+ pci_dma_write(&s->dev, tc_addr + 28, (uint8_t *)&val16, 2);
val16 = cpu_to_le16(tally_counters->FAE);
- cpu_physical_memory_write(tc_addr + 30, (uint8_t *)&val16, 2);
+ pci_dma_write(&s->dev, tc_addr + 30, (uint8_t *)&val16, 2);
val32 = cpu_to_le32(tally_counters->Tx1Col);
- cpu_physical_memory_write(tc_addr + 32, (uint8_t *)&val32, 4);
+ pci_dma_write(&s->dev, tc_addr + 32, (uint8_t *)&val32, 4);
val32 = cpu_to_le32(tally_counters->TxMCol);
- cpu_physical_memory_write(tc_addr + 36, (uint8_t *)&val32, 4);
+ pci_dma_write(&s->dev, tc_addr + 36, (uint8_t *)&val32, 4);
val64 = cpu_to_le64(tally_counters->RxOkPhy);
- cpu_physical_memory_write(tc_addr + 40, (uint8_t *)&val64, 8);
+ pci_dma_write(&s->dev, tc_addr + 40, (uint8_t *)&val64, 8);
val64 = cpu_to_le64(tally_counters->RxOkBrd);
- cpu_physical_memory_write(tc_addr + 48, (uint8_t *)&val64, 8);
+ pci_dma_write(&s->dev, tc_addr + 48, (uint8_t *)&val64, 8);
val32 = cpu_to_le32(tally_counters->RxOkMul);
- cpu_physical_memory_write(tc_addr + 56, (uint8_t *)&val32, 4);
+ pci_dma_write(&s->dev, tc_addr + 56, (uint8_t *)&val32, 4);
val16 = cpu_to_le16(tally_counters->TxAbt);
- cpu_physical_memory_write(tc_addr + 60, (uint8_t *)&val16, 2);
+ pci_dma_write(&s->dev, tc_addr + 60, (uint8_t *)&val16, 2);
val16 = cpu_to_le16(tally_counters->TxUndrn);
- cpu_physical_memory_write(tc_addr + 62, (uint8_t *)&val16, 2);
+ pci_dma_write(&s->dev, tc_addr + 62, (uint8_t *)&val16, 2);
}
/* Loads values of tally counters from VM state file */
static int rtl8139_config_writable(RTL8139State *s)
{
- if (s->Cfg9346 & Cfg9346_Unlock)
+ if ((s->Cfg9346 & Chip9346_op_mask) == Cfg9346_ConfigWrite)
{
return 1;
}
if (iov) {
buf2_size = iov_size(iov, 3);
buf2 = g_malloc(buf2_size);
- iov_to_buf(iov, 3, buf2, 0, buf2_size);
+ iov_to_buf(iov, 3, 0, buf2, buf2_size);
buf = buf2;
}
DPRINTF("+++ transmit reading %d bytes from host memory at 0x%08x\n",
txsize, s->TxAddr[descriptor]);
- cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize);
+ pci_dma_read(&s->dev, s->TxAddr[descriptor], txbuffer, txsize);
/* Mark descriptor as transferred */
s->TxStatus[descriptor] |= TxHostOwns;
int descriptor = s->currCPlusTxDesc;
- target_phys_addr_t cplus_tx_ring_desc =
- rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]);
+ dma_addr_t cplus_tx_ring_desc = rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]);
/* Normal priority ring */
cplus_tx_ring_desc += 16 * descriptor;
DPRINTF("+++ C+ mode reading TX descriptor %d from host memory at "
- "%08x0x%08x = 0x"TARGET_FMT_plx"\n", descriptor, s->TxAddr[1],
+ "%08x %08x = 0x"DMA_ADDR_FMT"\n", descriptor, s->TxAddr[1],
s->TxAddr[0], cplus_tx_ring_desc);
uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
- cpu_physical_memory_read(cplus_tx_ring_desc, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_tx_ring_desc, (uint8_t *)&val, 4);
txdw0 = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_tx_ring_desc+4, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_tx_ring_desc+4, (uint8_t *)&val, 4);
txdw1 = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_tx_ring_desc+8, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_tx_ring_desc+8, (uint8_t *)&val, 4);
txbufLO = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
txbufHI = le32_to_cpu(val);
DPRINTF("+++ C+ mode TX descriptor %d %08x %08x %08x %08x\n", descriptor,
}
int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK;
- target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
+ dma_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
/* make sure we have enough space to assemble the packet */
if (!s->cplus_txbuffer)
s->cplus_txbuffer_len);
}
- while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
+ if (s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
{
- s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
- s->cplus_txbuffer = g_realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
-
- DPRINTF("+++ C+ mode transmission buffer space changed to %d\n",
- s->cplus_txbuffer_len);
+ /* The spec didn't tell the maximum size, stick to CP_TX_BUFFER_SIZE */
+ txsize = s->cplus_txbuffer_len - s->cplus_txbuffer_offset;
+ DPRINTF("+++ C+ mode transmission buffer overrun, truncated descriptor"
+ "length to %d\n", txsize);
}
if (!s->cplus_txbuffer)
/* append more data to the packet */
DPRINTF("+++ C+ mode transmit reading %d bytes from host memory at "
- TARGET_FMT_plx" to offset %d\n", txsize, tx_addr,
- s->cplus_txbuffer_offset);
+ DMA_ADDR_FMT" to offset %d\n", txsize, tx_addr,
+ s->cplus_txbuffer_offset);
- cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
+ pci_dma_read(&s->dev, tx_addr,
+ s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
s->cplus_txbuffer_offset += txsize;
/* seek to next Rx descriptor */
/* update ring data */
val = cpu_to_le32(txdw0);
- cpu_physical_memory_write(cplus_tx_ring_desc, (uint8_t *)&val, 4);
+ pci_dma_write(&s->dev, cplus_tx_ring_desc, (uint8_t *)&val, 4);
/* Now decide if descriptor being processed is holding the last segment of packet */
if (txdw0 & CP_TX_LS)
if (descriptor == 0 && (val & 0x8))
{
- target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]);
+ hwaddr tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]);
/* dump tally counters to specified memory location */
- RTL8139TallyCounters_physical_memory_write( tc_addr, &s->tally_counters);
+ RTL8139TallyCounters_dma_write(s, tc_addr);
/* mark dump completed */
s->TxStatus[0] &= ~0x8;
rtl8139_transmit(s);
}
-static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint32_t txRegOffset)
+static uint32_t rtl8139_TxStatus_TxAddr_read(RTL8139State *s, uint32_t regs[],
+ uint32_t base, uint8_t addr,
+ int size)
{
- uint32_t ret = s->TxStatus[txRegOffset/4];
+ uint32_t reg = (addr - base) / 4;
+ uint32_t offset = addr & 0x3;
+ uint32_t ret = 0;
- DPRINTF("TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret);
+ if (addr & (size - 1)) {
+ DPRINTF("not implemented read for TxStatus/TxAddr "
+ "addr=0x%x size=0x%x\n", addr, size);
+ return ret;
+ }
+
+ switch (size) {
+ case 1: /* fall through */
+ case 2: /* fall through */
+ case 4:
+ ret = (regs[reg] >> offset * 8) & (((uint64_t)1 << (size * 8)) - 1);
+ DPRINTF("TxStatus/TxAddr[%d] read addr=0x%x size=0x%x val=0x%08x\n",
+ reg, addr, size, ret);
+ break;
+ default:
+ DPRINTF("unsupported size 0x%x of TxStatus/TxAddr reading\n", size);
+ break;
+ }
return ret;
}
* Computing if we miss an interrupt here is not that correct but
* considered that we should have had already an interrupt
* and probably emulated is slower is better to assume this resetting was
- * done before testing on previous rtl8139_update_irq lead to IRQ loosing
+ * done before testing on previous rtl8139_update_irq lead to IRQ losing
*/
rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
rtl8139_update_irq(s);
{
RTL8139State *s = opaque;
- addr &= 0xff;
-
switch (addr)
{
case MAC0 ... MAC0+5:
{
RTL8139State *s = opaque;
- addr &= 0xfe;
-
switch (addr)
{
case IntrMask:
{
RTL8139State *s = opaque;
- addr &= 0xfc;
-
switch (addr)
{
case RxMissed:
RTL8139State *s = opaque;
int ret;
- addr &= 0xff;
-
switch (addr)
{
case MAC0 ... MAC0+5:
case MAR0 ... MAR0+7:
ret = s->mult[addr - MAR0];
break;
+ case TxStatus0 ... TxStatus0+4*4-1:
+ ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
+ addr, 1);
+ break;
case ChipCmd:
ret = rtl8139_ChipCmd_read(s);
break;
break;
case MediaStatus:
- ret = 0xd0;
+ /* The LinkDown bit of MediaStatus is inverse with link status */
+ ret = 0xd0 | (~s->BasicModeStatus & 0x04);
DPRINTF("MediaStatus read 0x%x\n", ret);
break;
RTL8139State *s = opaque;
uint32_t ret;
- addr &= 0xfe; /* mask lower bit */
-
switch (addr)
{
+ case TxAddr0 ... TxAddr0+4*4-1:
+ ret = rtl8139_TxStatus_TxAddr_read(s, s->TxAddr, TxAddr0, addr, 2);
+ break;
case IntrMask:
ret = rtl8139_IntrMask_read(s);
break;
RTL8139State *s = opaque;
uint32_t ret;
- addr &= 0xfc; /* also mask low 2 bits */
-
switch (addr)
{
case RxMissed:
break;
case TxStatus0 ... TxStatus0+4*4-1:
- ret = rtl8139_TxStatus_read(s, addr-TxStatus0);
+ ret = rtl8139_TxStatus_TxAddr_read(s, s->TxStatus, TxStatus0,
+ addr, 4);
break;
case TxAddr0 ... TxAddr0+4*4-1:
/* */
-static void rtl8139_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void rtl8139_mmio_writeb(void *opaque, hwaddr addr, uint32_t val)
{
rtl8139_io_writeb(opaque, addr & 0xFF, val);
}
-static void rtl8139_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void rtl8139_mmio_writew(void *opaque, hwaddr addr, uint32_t val)
{
rtl8139_io_writew(opaque, addr & 0xFF, val);
}
-static void rtl8139_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void rtl8139_mmio_writel(void *opaque, hwaddr addr, uint32_t val)
{
rtl8139_io_writel(opaque, addr & 0xFF, val);
}
-static uint32_t rtl8139_mmio_readb(void *opaque, target_phys_addr_t addr)
+static uint32_t rtl8139_mmio_readb(void *opaque, hwaddr addr)
{
return rtl8139_io_readb(opaque, addr & 0xFF);
}
-static uint32_t rtl8139_mmio_readw(void *opaque, target_phys_addr_t addr)
+static uint32_t rtl8139_mmio_readw(void *opaque, hwaddr addr)
{
uint32_t val = rtl8139_io_readw(opaque, addr & 0xFF);
return val;
}
-static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr)
+static uint32_t rtl8139_mmio_readl(void *opaque, hwaddr addr)
{
uint32_t val = rtl8139_io_readl(opaque, addr & 0xFF);
return val;
s->cplus_enabled = s->CpCmd != 0;
}
+ /* nc.link_down can't be migrated, so infer link_down according
+ * to link status bit in BasicModeStatus */
+ s->nic->nc.link_down = (s->BasicModeStatus & 0x04) == 0;
+
return 0;
}
rtl8139_set_next_tctr_time(s, qemu_get_clock_ns(vm_clock));
}
-static void rtl8139_cleanup(VLANClientState *nc)
+static void rtl8139_cleanup(NetClientState *nc)
{
RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
s->nic = NULL;
}
-static int pci_rtl8139_uninit(PCIDevice *dev)
+static void pci_rtl8139_uninit(PCIDevice *dev)
{
RTL8139State *s = DO_UPCAST(RTL8139State, dev, dev);
}
qemu_del_timer(s->timer);
qemu_free_timer(s->timer);
- qemu_del_vlan_client(&s->nic->nc);
- return 0;
+ qemu_del_net_client(&s->nic->nc);
+}
+
+static void rtl8139_set_link_status(NetClientState *nc)
+{
+ RTL8139State *s = DO_UPCAST(NICState, nc, nc)->opaque;
+
+ if (nc->link_down) {
+ s->BasicModeStatus &= ~0x04;
+ } else {
+ s->BasicModeStatus |= 0x04;
+ }
+
+ s->IntrStatus |= RxUnderrun;
+ rtl8139_update_irq(s);
}
static NetClientInfo net_rtl8139_info = {
- .type = NET_CLIENT_TYPE_NIC,
+ .type = NET_CLIENT_OPTIONS_KIND_NIC,
.size = sizeof(NICState),
.can_receive = rtl8139_can_receive,
.receive = rtl8139_receive,
.cleanup = rtl8139_cleanup,
+ .link_status_changed = rtl8139_set_link_status,
};
static int pci_rtl8139_init(PCIDevice *dev)
uint8_t *pci_conf;
pci_conf = s->dev.config;
- pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin 0 */
+ pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
/* TODO: start of capability list, but no capability
* list bit in status register, and offset 0xdc seems unused. */
pci_conf[PCI_CAPABILITY_LIST] = 0xdc;
s->eeprom.contents[9] = s->conf.macaddr.a[4] | s->conf.macaddr.a[5] << 8;
s->nic = qemu_new_nic(&net_rtl8139_info, &s->conf,
- dev->qdev.info->name, dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->qdev.id, s);
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
s->cplus_txbuffer = NULL;
return 0;
}
-static PCIDeviceInfo rtl8139_info = {
- .qdev.name = "rtl8139",
- .qdev.size = sizeof(RTL8139State),
- .qdev.reset = rtl8139_reset,
- .qdev.vmsd = &vmstate_rtl8139,
- .init = pci_rtl8139_init,
- .exit = pci_rtl8139_uninit,
- .romfile = "pxe-rtl8139.rom",
- .vendor_id = PCI_VENDOR_ID_REALTEK,
- .device_id = PCI_DEVICE_ID_REALTEK_8139,
- .revision = RTL8139_PCI_REVID, /* >=0x20 is for 8139C+ */
- .class_id = PCI_CLASS_NETWORK_ETHERNET,
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(RTL8139State, conf),
- DEFINE_PROP_END_OF_LIST(),
- }
+static Property rtl8139_properties[] = {
+ DEFINE_NIC_PROPERTIES(RTL8139State, conf),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void rtl8139_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = pci_rtl8139_init;
+ k->exit = pci_rtl8139_uninit;
+ k->romfile = "pxe-rtl8139.rom";
+ k->vendor_id = PCI_VENDOR_ID_REALTEK;
+ k->device_id = PCI_DEVICE_ID_REALTEK_8139;
+ k->revision = RTL8139_PCI_REVID; /* >=0x20 is for 8139C+ */
+ k->class_id = PCI_CLASS_NETWORK_ETHERNET;
+ dc->reset = rtl8139_reset;
+ dc->vmsd = &vmstate_rtl8139;
+ dc->props = rtl8139_properties;
+}
+
+static TypeInfo rtl8139_info = {
+ .name = "rtl8139",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(RTL8139State),
+ .class_init = rtl8139_class_init,
};
-static void rtl8139_register_devices(void)
+static void rtl8139_register_types(void)
{
- pci_qdev_register(&rtl8139_info);
+ type_register_static(&rtl8139_info);
}
-device_init(rtl8139_register_devices)
+type_init(rtl8139_register_types)