aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2011-05-05 13:05:32 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2011-05-05 13:05:32 -0500
commit3964f535c35c08470ac69bd553282af500bc8bb0 (patch)
treeba83992b5bcfda451371174ce3e8be1496c70c73 /hw
parenta69fb35079f682f99dd4d077b76232763d832d42 (diff)
parent5300f1a5487f67f0bde8ee1081b799108668cb1d (diff)
Merge remote-tracking branch 'mst/for_anthony' into staging
Diffstat (limited to 'hw')
-rw-r--r--hw/cirrus_vga.c30
-rw-r--r--hw/eepro100.c342
-rw-r--r--hw/ide/ahci.c9
-rw-r--r--hw/ide/ahci.h3
-rw-r--r--hw/ide/ich.c8
-rw-r--r--hw/intel-hda.c15
-rw-r--r--hw/lsi53c895a.c12
-rw-r--r--hw/msi.c12
-rw-r--r--hw/pci.c25
-rw-r--r--hw/pci.h4
-rw-r--r--hw/pcnet-pci.c16
-rw-r--r--hw/piix_pci.c129
-rw-r--r--hw/rtl8139.c11
-rw-r--r--hw/usb-ohci.c10
-rw-r--r--hw/vhost.c61
-rw-r--r--hw/wdt_i6300esb.c42
16 files changed, 470 insertions, 259 deletions
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 2724f7b480..722cac7544 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2489,7 +2489,9 @@ static void map_linear_vram(CirrusVGAState *s)
if (!s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
s->vga.map_addr = s->vga.lfb_addr;
s->vga.map_end = s->vga.lfb_end;
- cpu_register_physical_memory(s->vga.map_addr, s->vga.map_end - s->vga.map_addr, s->vga.vram_offset);
+ cpu_register_physical_memory_log(s->vga.map_addr,
+ s->vga.map_end - s->vga.map_addr,
+ s->vga.vram_offset, 0, true);
}
if (!s->vga.map_addr)
@@ -2502,10 +2504,14 @@ static void map_linear_vram(CirrusVGAState *s)
&& !((s->vga.gr[0x0B] & 0x14) == 0x14)
&& !(s->vga.gr[0x0B] & 0x02)) {
- cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
- (s->vga.vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM);
- cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
- (s->vga.vram_offset + s->cirrus_bank_base[1]) | IO_MEM_RAM);
+ cpu_register_physical_memory_log(isa_mem_base + 0xa0000, 0x8000,
+ (s->vga.vram_offset +
+ s->cirrus_bank_base[0]) |
+ IO_MEM_RAM, 0, true);
+ cpu_register_physical_memory_log(isa_mem_base + 0xa8000, 0x8000,
+ (s->vga.vram_offset +
+ s->cirrus_bank_base[1]) |
+ IO_MEM_RAM, 0, true);
s->vga.lfb_vram_mapped = 1;
}
@@ -3024,7 +3030,6 @@ static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
s->vga.cursor_draw_line = cirrus_cursor_draw_line;
qemu_register_reset(cirrus_reset, s);
- cirrus_reset(s);
}
/***************************************
@@ -3076,15 +3081,6 @@ static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
vga_dirty_log_start(&s->vga);
}
-static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- CirrusVGAState *s = &DO_UPCAST(PCICirrusVGAState, dev, d)->cirrus_vga;
-
- cpu_register_physical_memory(addr, CIRRUS_PNPMMIO_SIZE,
- s->cirrus_mmio_io_addr);
-}
-
static void pci_cirrus_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len)
{
@@ -3123,8 +3119,8 @@ static int pci_cirrus_vga_initfn(PCIDevice *dev)
pci_register_bar(&d->dev, 0, 0x2000000,
PCI_BASE_ADDRESS_MEM_PREFETCH, cirrus_pci_lfb_map);
if (device_id == CIRRUS_ID_CLGD5446) {
- pci_register_bar(&d->dev, 1, CIRRUS_PNPMMIO_SIZE,
- PCI_BASE_ADDRESS_SPACE_MEMORY, cirrus_pci_mmio_map);
+ pci_register_bar_simple(&d->dev, 1, CIRRUS_PNPMMIO_SIZE, 0,
+ s->cirrus_mmio_io_addr);
}
return 0;
}
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 369ad7f840..05450e859e 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -1,7 +1,7 @@
/*
* QEMU i8255x (PRO100) emulation
*
- * Copyright (C) 2006-2010 Stefan Weil
+ * Copyright (C) 2006-2011 Stefan Weil
*
* Portions of the code are copies from grub / etherboot eepro100.c
* and linux e100.c.
@@ -20,11 +20,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Tested features (i82559):
- * PXE boot (i386) ok
+ * PXE boot (i386 guest, i386 / mips / mipsel / ppc host) ok
* Linux networking (i386) ok
*
* Untested:
- * non-i386 platforms
* Windows networking
*
* References:
@@ -48,6 +47,15 @@
#include "eeprom93xx.h"
#include "sysemu.h"
+/* QEMU sends frames smaller than 60 bytes to ethernet nics.
+ * Such frames are rejected by real nics and their emulations.
+ * To avoid this behaviour, other nic emulations pad received
+ * frames. The following definition enables this padding for
+ * eepro100, too. We keep the define around in case it might
+ * become useful the future if the core networking is ever
+ * changed to pad short packets itself. */
+#define CONFIG_PAD_RECEIVED_FRAMES
+
#define KiB 1024
/* Debug EEPRO100 card. */
@@ -130,7 +138,7 @@ typedef struct {
/* Offsets to the various registers.
All accesses need not be longword aligned. */
-enum speedo_offsets {
+typedef enum {
SCBStatus = 0, /* Status Word. */
SCBAck = 1,
SCBCmd = 2, /* Rx/Command Unit command and status. */
@@ -145,7 +153,7 @@ enum speedo_offsets {
SCBpmdr = 27, /* Power Management Driver. */
SCBgctrl = 28, /* General Control. */
SCBgstat = 29, /* General Status. */
-};
+} E100RegisterOffset;
/* A speedo3 transmit buffer descriptor with two buffers... */
typedef struct {
@@ -173,7 +181,7 @@ typedef struct {
uint32_t rx_buf_addr; /* void * */
uint16_t count;
uint16_t size;
- char packet[MAX_ETH_FRAME_SIZE + 4];
+ /* Ethernet frame data follows. */
} eepro100_rx_t;
typedef enum {
@@ -228,11 +236,10 @@ typedef struct {
uint8_t scb_stat; /* SCB stat/ack byte */
uint8_t int_stat; /* PCI interrupt status */
/* region must not be saved by nic_save. */
- uint32_t region[3]; /* PCI region addresses */
+ uint32_t region1; /* PCI region 1 address */
uint16_t mdimem[32];
eeprom_t *eeprom;
uint32_t device; /* device variant */
- uint32_t pointer;
/* (cu_base + cu_offset) address the next command block in the command block list. */
uint32_t cu_base; /* CU base address */
uint32_t cu_offset; /* CU address offset */
@@ -249,11 +256,13 @@ typedef struct {
/* Statistical counters. Also used for wake-up packet (i82559). */
eepro100_stats_t statistics;
+ /* Data in mem is always in the byte order of the controller (le).
+ * It must be dword aligned to allow direct access to 32 bit values. */
+ uint8_t mem[PCI_MEM_SIZE] __attribute__((aligned(8)));;
+
/* Configuration bytes. */
uint8_t configuration[22];
- /* Data in mem is always in the byte order of the controller (le). */
- uint8_t mem[PCI_MEM_SIZE];
/* vmstate for each particular nic */
VMStateDescription *vmstate;
@@ -307,11 +316,36 @@ static const uint16_t eepro100_mdi_mask[] = {
0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
};
-/* XXX: optimize */
-static void stl_le_phys(target_phys_addr_t addr, uint32_t val)
+/* Read a 16 bit little endian value from physical memory. */
+static uint16_t e100_ldw_le_phys(target_phys_addr_t addr)
+{
+ /* Load 16 bit (little endian) word from emulated hardware. */
+ uint16_t val;
+ cpu_physical_memory_read(addr, &val, sizeof(val));
+ return le16_to_cpu(val);
+}
+
+/* Read a 32 bit little endian value from physical memory. */
+static uint32_t e100_ldl_le_phys(target_phys_addr_t addr)
+{
+ /* Load 32 bit (little endian) word from emulated hardware. */
+ uint32_t val;
+ cpu_physical_memory_read(addr, &val, sizeof(val));
+ return le32_to_cpu(val);
+}
+
+/* Write a 16 bit little endian value to physical memory. */
+static void e100_stw_le_phys(target_phys_addr_t addr, uint16_t val)
+{
+ val = cpu_to_le16(val);
+ cpu_physical_memory_write(addr, &val, sizeof(val));
+}
+
+/* Write a 32 bit little endian value to physical memory. */
+static void e100_stl_le_phys(target_phys_addr_t addr, uint32_t val)
{
val = cpu_to_le32(val);
- cpu_physical_memory_write(addr, (const uint8_t *)&val, sizeof(val));
+ cpu_physical_memory_write(addr, &val, sizeof(val));
}
#define POLYNOMIAL 0x04c11db6
@@ -339,6 +373,36 @@ static unsigned compute_mcast_idx(const uint8_t * ep)
return (crc & BITS(7, 2)) >> 2;
}
+/* Read a 16 bit control/status (CSR) register. */
+static uint16_t e100_read_reg2(EEPRO100State *s, E100RegisterOffset addr)
+{
+ assert(!((uintptr_t)&s->mem[addr] & 1));
+ return le16_to_cpup((uint16_t *)&s->mem[addr]);
+}
+
+/* Read a 32 bit control/status (CSR) register. */
+static uint32_t e100_read_reg4(EEPRO100State *s, E100RegisterOffset addr)
+{
+ assert(!((uintptr_t)&s->mem[addr] & 3));
+ return le32_to_cpup((uint32_t *)&s->mem[addr]);
+}
+
+/* Write a 16 bit control/status (CSR) register. */
+static void e100_write_reg2(EEPRO100State *s, E100RegisterOffset addr,
+ uint16_t val)
+{
+ assert(!((uintptr_t)&s->mem[addr] & 1));
+ cpu_to_le16w((uint16_t *)&s->mem[addr], val);
+}
+
+/* Read a 32 bit control/status (CSR) register. */
+static void e100_write_reg4(EEPRO100State *s, E100RegisterOffset addr,
+ uint32_t val)
+{
+ assert(!((uintptr_t)&s->mem[addr] & 3));
+ cpu_to_le32w((uint32_t *)&s->mem[addr], val);
+}
+
#if defined(DEBUG_EEPRO100)
static const char *nic_dump(const uint8_t * buf, unsigned size)
{
@@ -590,8 +654,7 @@ static void nic_selective_reset(EEPRO100State * s)
TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE - 1]));
memset(s->mem, 0, sizeof(s->mem));
- uint32_t val = BIT(21);
- memcpy(&s->mem[SCBCtrlMDI], &val, sizeof(val));
+ e100_write_reg4(s, SCBCtrlMDI, BIT(21));
assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem));
@@ -694,22 +757,21 @@ static void dump_statistics(EEPRO100State * s)
* values which really matter.
* Number of data should check configuration!!!
*/
- cpu_physical_memory_write(s->statsaddr,
- (uint8_t *) & s->statistics, s->stats_size);
- stl_le_phys(s->statsaddr + 0, s->statistics.tx_good_frames);
- stl_le_phys(s->statsaddr + 36, s->statistics.rx_good_frames);
- stl_le_phys(s->statsaddr + 48, s->statistics.rx_resource_errors);
- stl_le_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors);
+ cpu_physical_memory_write(s->statsaddr, &s->statistics, s->stats_size);
+ e100_stl_le_phys(s->statsaddr + 0, s->statistics.tx_good_frames);
+ e100_stl_le_phys(s->statsaddr + 36, s->statistics.rx_good_frames);
+ e100_stl_le_phys(s->statsaddr + 48, s->statistics.rx_resource_errors);
+ e100_stl_le_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors);
#if 0
- stw_le_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames);
- stw_le_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames);
+ e100_stw_le_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames);
+ e100_stw_le_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames);
missing("CU dump statistical counters");
#endif
}
static void read_cb(EEPRO100State *s)
{
- cpu_physical_memory_read(s->cb_address, (uint8_t *) &s->tx, sizeof(s->tx));
+ cpu_physical_memory_read(s->cb_address, &s->tx, sizeof(s->tx));
s->tx.status = le16_to_cpu(s->tx.status);
s->tx.command = le16_to_cpu(s->tx.command);
s->tx.link = le32_to_cpu(s->tx.link);
@@ -739,10 +801,10 @@ static void tx_command(EEPRO100State *s)
}
assert(tcb_bytes <= sizeof(buf));
while (size < tcb_bytes) {
- uint32_t tx_buffer_address = ldl_phys(tbd_address);
- uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
+ uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
+ uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
#if 0
- uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+ uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6);
#endif
tbd_address += 8;
TRACE(RXTX, logout
@@ -761,9 +823,9 @@ static void tx_command(EEPRO100State *s)
if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) {
/* Extended Flexible TCB. */
for (; tbd_count < 2; tbd_count++) {
- uint32_t tx_buffer_address = ldl_phys(tbd_address);
- uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
- uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+ uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
+ uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
+ uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6);
tbd_address += 8;
TRACE(RXTX, logout
("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
@@ -779,9 +841,9 @@ static void tx_command(EEPRO100State *s)
}
tbd_address = tbd_array;
for (; tbd_count < s->tx.tbd_count; tbd_count++) {
- uint32_t tx_buffer_address = ldl_phys(tbd_address);
- uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
- uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+ uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
+ uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
+ uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6);
tbd_address += 8;
TRACE(RXTX, logout
("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
@@ -889,7 +951,7 @@ static void action_command(EEPRO100State *s)
break;
}
/* Write new status. */
- stw_phys(s->cb_address, s->tx.status | ok_status | STATUS_C);
+ e100_stw_le_phys(s->cb_address, s->tx.status | ok_status | STATUS_C);
if (bit_i) {
/* CU completed action. */
eepro100_cx_interrupt(s);
@@ -928,7 +990,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
logout("unexpected CU state is %u\n", cu_state);
}
set_cu_state(s, cu_active);
- s->cu_offset = s->pointer;
+ s->cu_offset = e100_read_reg4(s, SCBPointer);
action_command(s);
break;
case CU_RESUME:
@@ -949,25 +1011,25 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
break;
case CU_STATSADDR:
/* Load dump counters address. */
- s->statsaddr = s->pointer;
+ s->statsaddr = e100_read_reg4(s, SCBPointer);
TRACE(OTHER, logout("val=0x%02x (status address)\n", val));
break;
case CU_SHOWSTATS:
/* Dump statistical counters. */
TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val));
dump_statistics(s);
- stl_le_phys(s->statsaddr + s->stats_size, 0xa005);
+ e100_stl_le_phys(s->statsaddr + s->stats_size, 0xa005);
break;
case CU_CMD_BASE:
/* Load CU base. */
TRACE(OTHER, logout("val=0x%02x (CU base address)\n", val));
- s->cu_base = s->pointer;
+ s->cu_base = e100_read_reg4(s, SCBPointer);
break;
case CU_DUMPSTATS:
/* Dump and reset statistical counters. */
TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val));
dump_statistics(s);
- stl_le_phys(s->statsaddr + s->stats_size, 0xa007);
+ e100_stl_le_phys(s->statsaddr + s->stats_size, 0xa007);
memset(&s->statistics, 0, sizeof(s->statistics));
break;
case CU_SRESUME:
@@ -994,7 +1056,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
#endif
}
set_ru_state(s, ru_ready);
- s->ru_offset = s->pointer;
+ s->ru_offset = e100_read_reg4(s, SCBPointer);
TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
break;
case RX_RESUME:
@@ -1018,7 +1080,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
case RX_ADDR_LOAD:
/* Load RU base. */
TRACE(OTHER, logout("val=0x%02x (RU base address)\n", val));
- s->ru_base = s->pointer;
+ s->ru_base = e100_read_reg4(s, SCBPointer);
break;
default:
logout("val=0x%02x (undefined RU command)\n", val);
@@ -1050,8 +1112,7 @@ static void eepro100_write_command(EEPRO100State * s, uint8_t val)
static uint16_t eepro100_read_eeprom(EEPRO100State * s)
{
- uint16_t val;
- memcpy(&val, &s->mem[SCBeeprom], sizeof(val));
+ uint16_t val = e100_read_reg2(s, SCBeeprom);
if (eeprom93xx_read(s->eeprom)) {
val |= EEPROM_DO;
} else {
@@ -1076,12 +1137,6 @@ static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
eeprom93xx_write(eeprom, eecs, eesk, eedi);
}
-static void eepro100_write_pointer(EEPRO100State * s, uint32_t val)
-{
- s->pointer = le32_to_cpu(val);
- TRACE(OTHER, logout("val=0x%08x\n", val));
-}
-
/*****************************************************************************
*
* MDI emulation.
@@ -1121,8 +1176,7 @@ static const char *reg2name(uint8_t reg)
static uint32_t eepro100_read_mdi(EEPRO100State * s)
{
- uint32_t val;
- memcpy(&val, &s->mem[0x10], sizeof(val));
+ uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
#ifdef DEBUG_EEPRO100
uint8_t raiseint = (val & BIT(29)) >> 29;
@@ -1139,8 +1193,9 @@ static uint32_t eepro100_read_mdi(EEPRO100State * s)
return val;
}
-static void eepro100_write_mdi(EEPRO100State * s, uint32_t val)
+static void eepro100_write_mdi(EEPRO100State *s)
{
+ uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
uint8_t raiseint = (val & BIT(29)) >> 29;
uint8_t opcode = (val & BITS(27, 26)) >> 26;
uint8_t phy = (val & BITS(25, 21)) >> 21;
@@ -1231,7 +1286,7 @@ static void eepro100_write_mdi(EEPRO100State * s, uint32_t val)
}
}
val = (val & 0xffff0000) + data;
- memcpy(&s->mem[0x10], &val, sizeof(val));
+ e100_write_reg4(s, SCBCtrlMDI, val);
}
/*****************************************************************************
@@ -1256,9 +1311,9 @@ static uint32_t eepro100_read_port(EEPRO100State * s)
return 0;
}
-static void eepro100_write_port(EEPRO100State * s, uint32_t val)
+static void eepro100_write_port(EEPRO100State *s)
{
- val = le32_to_cpu(val);
+ uint32_t val = e100_read_reg4(s, SCBPort);
uint32_t address = (val & ~PORT_SELECTION_MASK);
uint8_t selection = (val & PORT_SELECTION_MASK);
switch (selection) {
@@ -1268,10 +1323,10 @@ static void eepro100_write_port(EEPRO100State * s, uint32_t val)
case PORT_SELFTEST:
TRACE(OTHER, logout("selftest address=0x%08x\n", address));
eepro100_selftest_t data;
- cpu_physical_memory_read(address, (uint8_t *) & data, sizeof(data));
+ cpu_physical_memory_read(address, &data, sizeof(data));
data.st_sign = 0xffffffff;
data.st_result = 0;
- cpu_physical_memory_write(address, (uint8_t *) & data, sizeof(data));
+ cpu_physical_memory_write(address, &data, sizeof(data));
break;
case PORT_SELECTIVE_RESET:
TRACE(OTHER, logout("selective reset, selftest address=0x%08x\n", address));
@@ -1293,7 +1348,7 @@ static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
{
uint8_t val = 0;
if (addr <= sizeof(s->mem) - sizeof(val)) {
- memcpy(&val, &s->mem[addr], sizeof(val));
+ val = s->mem[addr];
}
switch (addr) {
@@ -1316,10 +1371,20 @@ static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
case SCBeeprom:
val = eepro100_read_eeprom(s);
break;
+ case SCBCtrlMDI:
+ case SCBCtrlMDI + 1:
+ case SCBCtrlMDI + 2:
+ case SCBCtrlMDI + 3:
+ val = (uint8_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+ break;
case SCBpmdr: /* Power Management Driver Register */
val = 0;
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
break;
+ case SCBgctrl: /* General Control Register */
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+ break;
case SCBgstat: /* General Status Register */
/* 100 Mbps full duplex, valid link */
val = 0x07;
@@ -1336,7 +1401,7 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
{
uint16_t val = 0;
if (addr <= sizeof(s->mem) - sizeof(val)) {
- memcpy(&val, &s->mem[addr], sizeof(val));
+ val = e100_read_reg2(s, addr);
}
switch (addr) {
@@ -1348,6 +1413,11 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
val = eepro100_read_eeprom(s);
TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
break;
+ case SCBCtrlMDI:
+ case SCBCtrlMDI + 2:
+ val = (uint16_t)(eepro100_read_mdi(s) >> (8 * (addr & 3)));
+ TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+ break;
default:
logout("addr=%s val=0x%04x\n", regname(addr), val);
missing("unknown word read");
@@ -1359,7 +1429,7 @@ static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
{
uint32_t val = 0;
if (addr <= sizeof(s->mem) - sizeof(val)) {
- memcpy(&val, &s->mem[addr], sizeof(val));
+ val = e100_read_reg4(s, addr);
}
switch (addr) {
@@ -1367,15 +1437,16 @@ static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
break;
case SCBPointer:
-#if 0
- val = eepro100_read_pointer(s);
-#endif
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
break;
case SCBPort:
val = eepro100_read_port(s);
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
break;
+ case SCBflash:
+ val = eepro100_read_eeprom(s);
+ TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+ break;
case SCBCtrlMDI:
val = eepro100_read_mdi(s);
break;
@@ -1390,27 +1461,43 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
{
/* SCBStatus is readonly. */
if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
- memcpy(&s->mem[addr], &val, sizeof(val));
+ s->mem[addr] = val;
}
- TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
-
switch (addr) {
case SCBStatus:
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
break;
case SCBAck:
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
eepro100_acknowledge(s);
break;
case SCBCmd:
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
eepro100_write_command(s, val);
break;
case SCBIntmask:
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
if (val & BIT(1)) {
eepro100_swi_interrupt(s);
}
eepro100_interrupt(s, 0);
break;
+ case SCBPointer:
+ case SCBPointer + 1:
+ case SCBPointer + 2:
+ case SCBPointer + 3:
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+ break;
+ case SCBPort:
+ case SCBPort + 1:
+ case SCBPort + 2:
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+ break;
case SCBPort + 3:
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+ eepro100_write_port(s);
+ break;
case SCBFlow: /* does not exist on 82557 */
case SCBFlow + 1:
case SCBFlow + 2:
@@ -1418,8 +1505,18 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
break;
case SCBeeprom:
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
eepro100_write_eeprom(s->eeprom, val);
break;
+ case SCBCtrlMDI:
+ case SCBCtrlMDI + 1:
+ case SCBCtrlMDI + 2:
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+ break;
+ case SCBCtrlMDI + 3:
+ TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
+ eepro100_write_mdi(s);
+ break;
default:
logout("addr=%s val=0x%02x\n", regname(addr), val);
missing("unknown byte write");
@@ -1430,23 +1527,42 @@ static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
{
/* SCBStatus is readonly. */
if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
- memcpy(&s->mem[addr], &val, sizeof(val));
+ e100_write_reg2(s, addr, val);
}
- TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
-
switch (addr) {
case SCBStatus:
+ TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
s->mem[SCBAck] = (val >> 8);
eepro100_acknowledge(s);
break;
case SCBCmd:
+ TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
eepro100_write_command(s, val);
eepro100_write1(s, SCBIntmask, val >> 8);
break;
+ case SCBPointer:
+ case SCBPointer + 2:
+ TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+ break;
+ case SCBPort:
+ TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+ break;
+ case SCBPort + 2:
+ TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+ eepro100_write_port(s);
+ break;
case SCBeeprom:
+ TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
eepro100_write_eeprom(s->eeprom, val);
break;
+ case SCBCtrlMDI:
+ TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+ break;
+ case SCBCtrlMDI + 2:
+ TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
+ eepro100_write_mdi(s);
+ break;
default:
logout("addr=%s val=0x%04x\n", regname(addr), val);
missing("unknown word write");
@@ -1456,19 +1572,25 @@ static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
{
if (addr <= sizeof(s->mem) - sizeof(val)) {
- memcpy(&s->mem[addr], &val, sizeof(val));
+ e100_write_reg4(s, addr, val);
}
switch (addr) {
case SCBPointer:
- eepro100_write_pointer(s, val);
+ TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
break;
case SCBPort:
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
- eepro100_write_port(s, val);
+ eepro100_write_port(s);
+ break;
+ case SCBflash:
+ TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+ val = val >> 16;
+ eepro100_write_eeprom(s->eeprom, val);
break;
case SCBCtrlMDI:
- eepro100_write_mdi(s, val);
+ TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
+ eepro100_write_mdi(s);
break;
default:
logout("addr=%s val=0x%08x\n", regname(addr), val);
@@ -1488,19 +1610,19 @@ static uint32_t ioport_read1(void *opaque, uint32_t addr)
#if 0
logout("addr=%s\n", regname(addr));
#endif
- return eepro100_read1(s, addr - s->region[1]);
+ return eepro100_read1(s, addr - s->region1);
}
static uint32_t ioport_read2(void *opaque, uint32_t addr)
{
EEPRO100State *s = opaque;
- return eepro100_read2(s, addr - s->region[1]);
+ return eepro100_read2(s, addr - s->region1);
}
static uint32_t ioport_read4(void *opaque, uint32_t addr)
{
EEPRO100State *s = opaque;
- return eepro100_read4(s, addr - s->region[1]);
+ return eepro100_read4(s, addr - s->region1);
}
static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
@@ -1509,19 +1631,19 @@ static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
#if 0
logout("addr=%s val=0x%02x\n", regname(addr), val);
#endif
- eepro100_write1(s, addr - s->region[1], val);
+ eepro100_write1(s, addr - s->region1, val);
}
static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
{
EEPRO100State *s = opaque;
- eepro100_write2(s, addr - s->region[1], val);
+ eepro100_write2(s, addr - s->region1, val);
}
static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
{
EEPRO100State *s = opaque;
- eepro100_write4(s, addr - s->region[1], val);
+ eepro100_write4(s, addr - s->region1, val);
}
/***********************************************************/
@@ -1544,7 +1666,7 @@ static void pci_map(PCIDevice * pci_dev, int region_num,
register_ioport_write(addr, size, 4, ioport_write4, s);
register_ioport_read(addr, size, 4, ioport_read4, s);
- s->region[region_num] = addr;
+ s->region1 = addr;
}
/*****************************************************************************
@@ -1619,22 +1741,6 @@ static CPUReadMemoryFunc * const pci_mmio_read[] = {
pci_mmio_readl
};
-static void pci_mmio_map(PCIDevice * pci_dev, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- EEPRO100State *s = DO_UPCAST(EEPRO100State, dev, pci_dev);
-
- TRACE(OTHER, logout("region %d, addr=0x%08"FMT_PCIBUS", "
- "size=0x%08"FMT_PCIBUS", type=%d\n",
- region_num, addr, size, type));
-
- assert(region_num == 0 || region_num == 2);
-
- /* Map control / status registers and flash. */
- cpu_register_physical_memory(addr, size, s->mmio_index);
- s->region[region_num] = addr;
-}
-
static int nic_can_receive(VLANClientState *nc)
{
EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
@@ -1653,19 +1759,32 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
*/
EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
uint16_t rfd_status = 0xa000;
+#if defined(CONFIG_PAD_RECEIVED_FRAMES)
+ uint8_t min_buf[60];
+#endif
static const uint8_t broadcast_macaddr[6] =
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+#if defined(CONFIG_PAD_RECEIVED_FRAMES)
+ /* Pad to minimum Ethernet frame length */
+ if (size < sizeof(min_buf)) {
+ memcpy(min_buf, buf, size);
+ memset(&min_buf[size], 0, sizeof(min_buf) - size);
+ buf = min_buf;
+ size = sizeof(min_buf);
+ }
+#endif
+
if (s->configuration[8] & 0x80) {
/* CSMA is disabled. */
logout("%p received while CSMA is disabled\n", s);
return -1;
+#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
} else if (size < 64 && (s->configuration[7] & BIT(0))) {
/* Short frame and configuration byte 7/0 (discard short receive) set:
* Short frame is discarded */
logout("%p received short frame (%zu byte)\n", s, size);
s->statistics.rx_short_frame_errors++;
-#if 0
return -1;
#endif
} else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & BIT(3))) {
@@ -1734,8 +1853,8 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
}
/* !!! */
eepro100_rx_t rx;
- cpu_physical_memory_read(s->ru_base + s->ru_offset, (uint8_t *) & rx,
- offsetof(eepro100_rx_t, packet));
+ cpu_physical_memory_read(s->ru_base + s->ru_offset, &rx,
+ sizeof(eepro100_rx_t));
uint16_t rfd_command = le16_to_cpu(rx.command);
uint16_t rfd_size = le16_to_cpu(rx.size);
@@ -1744,14 +1863,17 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
"(%zu bytes); data truncated\n", rfd_size, size);
size = rfd_size;
}
+#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
if (size < 64) {
rfd_status |= 0x0080;
}
+#endif
TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n",
rfd_command, rx.link, rx.rx_buf_addr, rfd_size));
- stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, status),
- rfd_status);
- stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, count), size);
+ e100_stw_le_phys(s->ru_base + s->ru_offset +
+ offsetof(eepro100_rx_t, status), rfd_status);
+ e100_stw_le_phys(s->ru_base + s->ru_offset +
+ offsetof(eepro100_rx_t, count), size);
/* Early receive interrupt not supported. */
#if 0
eepro100_er_interrupt(s);
@@ -1766,7 +1888,7 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
assert(!(s->configuration[17] & BIT(0)));
#endif
cpu_physical_memory_write(s->ru_base + s->ru_offset +
- offsetof(eepro100_rx_t, packet), buf, size);
+ sizeof(eepro100_rx_t), buf, size);
s->statistics.rx_good_frames++;
eepro100_fr_interrupt(s);
s->ru_offset = le32_to_cpu(rx.link);
@@ -1801,7 +1923,6 @@ static const VMStateDescription vmstate_eepro100 = {
/* The eeprom should be saved and restored by its own routines. */
VMSTATE_UINT32(device, EEPRO100State),
/* TODO check device. */
- VMSTATE_UINT32(pointer, EEPRO100State),
VMSTATE_UINT32(cu_base, EEPRO100State),
VMSTATE_UINT32(cu_offset, EEPRO100State),
VMSTATE_UINT32(ru_base, EEPRO100State),
@@ -1880,19 +2001,18 @@ static int e100_nic_init(PCIDevice *pci_dev)
/* Handler for memory-mapped I/O */
s->mmio_index =
cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s,
- DEVICE_NATIVE_ENDIAN);
+ DEVICE_LITTLE_ENDIAN);
+
+ pci_register_bar_simple(&s->dev, 0, PCI_MEM_SIZE,
+ PCI_BASE_ADDRESS_MEM_PREFETCH, s->mmio_index);
- pci_register_bar(&s->dev, 0, PCI_MEM_SIZE,
- PCI_BASE_ADDRESS_SPACE_MEMORY |
- PCI_BASE_ADDRESS_MEM_PREFETCH, pci_mmio_map);
pci_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO,
pci_map);
- pci_register_bar(&s->dev, 2, PCI_FLASH_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY,
- pci_mmio_map);
+ pci_register_bar_simple(&s->dev, 2, PCI_FLASH_SIZE, 0, s->mmio_index);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
- assert(s->region[1] == 0);
+ assert(s->region1 == 0);
nic_reset(s);
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 98bdf7059a..c6e0c7767e 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1129,15 +1129,6 @@ void ahci_uninit(AHCIState *s)
qemu_free(s->dev);
}
-void ahci_pci_map(PCIDevice *pci_dev, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- struct AHCIPCIState *d = (struct AHCIPCIState *)pci_dev;
- AHCIState *s = &d->ahci;
-
- cpu_register_physical_memory(addr, size, s->mem);
-}
-
void ahci_reset(void *opaque)
{
struct AHCIPCIState *d = opaque;
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index a4560c41b6..dc86951ebf 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -325,9 +325,6 @@ typedef struct NCQFrame {
void ahci_init(AHCIState *s, DeviceState *qdev, int ports);
void ahci_uninit(AHCIState *s);
-void ahci_pci_map(PCIDevice *pci_dev, int region_num,
- pcibus_t addr, pcibus_t size, int type);
-
void ahci_reset(void *opaque);
#endif /* HW_IDE_AHCI_H */
diff --git a/hw/ide/ich.c b/hw/ide/ich.c
index a3d475c59a..e44339b078 100644
--- a/hw/ide/ich.c
+++ b/hw/ide/ich.c
@@ -94,8 +94,7 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
qemu_register_reset(ahci_reset, d);
/* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
- pci_register_bar(&d->card, 5, 0x1000, PCI_BASE_ADDRESS_SPACE_MEMORY,
- ahci_pci_map);
+ pci_register_bar_simple(&d->card, 5, 0x1000, 0, d->ahci.mem);
msi_init(dev, 0x50, 1, true, false);
@@ -110,10 +109,7 @@ static int pci_ich9_uninit(PCIDevice *dev)
struct AHCIPCIState *d;
d = DO_UPCAST(struct AHCIPCIState, card, dev);
- if (msi_enabled(dev)) {
- msi_uninit(dev);
- }
-
+ msi_uninit(dev);
qemu_unregister_reset(ahci_reset, d);
ahci_uninit(&d->ahci);
diff --git a/hw/intel-hda.c b/hw/intel-hda.c
index b0b1d1292a..5485745e85 100644
--- a/hw/intel-hda.c
+++ b/hw/intel-hda.c
@@ -1109,14 +1109,6 @@ static CPUWriteMemoryFunc * const intel_hda_mmio_write[3] = {
intel_hda_mmio_writel,
};
-static void intel_hda_map(PCIDevice *pci, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
-
- cpu_register_physical_memory(addr, 0x4000, d->mmio_addr);
-}
-
/* --------------------------------------------------------------------- */
static void intel_hda_reset(DeviceState *dev)
@@ -1158,8 +1150,7 @@ static int intel_hda_init(PCIDevice *pci)
d->mmio_addr = cpu_register_io_memory(intel_hda_mmio_read,
intel_hda_mmio_write, d,
DEVICE_NATIVE_ENDIAN);
- pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
- intel_hda_map);
+ pci_register_bar_simple(&d->pci, 0, 0x4000, 0, d->mmio_addr);
if (d->msi) {
msi_init(&d->pci, 0x50, 1, true, false);
}
@@ -1174,9 +1165,7 @@ static int intel_hda_exit(PCIDevice *pci)
{
IntelHDAState *d = DO_UPCAST(IntelHDAState, pci, pci);
- if (d->msi) {
- msi_uninit(&d->pci);
- }
+ msi_uninit(&d->pci);
cpu_unregister_io_memory(d->mmio_addr);
return 0;
}
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index e4b51a8eaf..be4df589d8 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -2094,15 +2094,6 @@ static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num,
cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr);
}
-static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- LSIState *s = DO_UPCAST(LSIState, dev, pci_dev);
-
- DPRINTF("Mapping registers at %08"FMT_PCIBUS"\n", addr);
- cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr);
-}
-
static void lsi_scsi_reset(DeviceState *dev)
{
LSIState *s = DO_UPCAST(LSIState, dev.qdev, dev);
@@ -2245,8 +2236,7 @@ static int lsi_scsi_init(PCIDevice *dev)
pci_register_bar(&s->dev, 0, 256,
PCI_BASE_ADDRESS_SPACE_IO, lsi_io_mapfunc);
- pci_register_bar(&s->dev, 1, 0x400,
- PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc);
+ pci_register_bar_simple(&s->dev, 1, 0x400, 0, s->mmio_io_addr);
pci_register_bar(&s->dev, 2, 0x2000,
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
QTAILQ_INIT(&s->queue);
diff --git a/hw/msi.c b/hw/msi.c
index 3dc3a24b77..b0795bd708 100644
--- a/hw/msi.c
+++ b/hw/msi.c
@@ -164,9 +164,17 @@ int msi_init(struct PCIDevice *dev, uint8_t offset,
void msi_uninit(struct PCIDevice *dev)
{
- uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
- uint8_t cap_size = msi_cap_sizeof(flags);
+ uint16_t flags;
+ uint8_t cap_size;
+
+ if (!(dev->cap_present & QEMU_PCI_CAP_MSI)) {
+ return;
+ }
+ flags = pci_get_word(dev->config + msi_flags_off(dev));
+ cap_size = msi_cap_sizeof(flags);
pci_del_capability(dev, PCI_CAP_ID_MSIX, cap_size);
+ dev->cap_present &= ~QEMU_PCI_CAP_MSI;
+
MSI_DEV_PRINTF(dev, "uninit\n");
}
diff --git a/hw/pci.c b/hw/pci.c
index 6b577e1e3e..0875654253 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -126,6 +126,13 @@ static void pci_change_irq_level(PCIDevice *pci_dev, int irq_num, int change)
bus->set_irq(bus->irq_opaque, irq_num, bus->irq_count[irq_num] != 0);
}
+int pci_bus_get_irq_level(PCIBus *bus, int irq_num)
+{
+ assert(irq_num >= 0);
+ assert(irq_num < bus->nirq);
+ return !!bus->irq_count[irq_num];
+}
+
/* Update interrupt status bit in config space on interrupt
* state change. */
static void pci_update_irq_status(PCIDevice *dev)
@@ -859,6 +866,7 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
r->filtered_size = size;
r->type = type;
r->map_func = map_func;
+ r->ram_addr = IO_MEM_UNASSIGNED;
wmask = ~(size - 1);
addr = pci_bar(pci_dev, region_num);
@@ -877,6 +885,22 @@ void pci_register_bar(PCIDevice *pci_dev, int region_num,
}
}
+static void pci_simple_bar_mapfunc(PCIDevice *pci_dev, int region_num,
+ pcibus_t addr, pcibus_t size, int type)
+{
+ cpu_register_physical_memory(addr, size,
+ pci_dev->io_regions[region_num].ram_addr);
+}
+
+void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
+ pcibus_t size, uint8_t attr, ram_addr_t ram_addr)
+{
+ pci_register_bar(pci_dev, region_num, size,
+ PCI_BASE_ADDRESS_SPACE_MEMORY | attr,
+ pci_simple_bar_mapfunc);
+ pci_dev->io_regions[region_num].ram_addr = ram_addr;
+}
+
static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
uint8_t type)
{
@@ -1145,6 +1169,7 @@ static const pci_class_desc pci_class_descriptions[] =
{ 0x0400, "Video controller", "video"},
{ 0x0401, "Audio controller", "sound"},
{ 0x0402, "Phone"},
+ { 0x0403, "Audio controller", "sound"},
{ 0x0480, "Multimedia controller"},
{ 0x0500, "RAM controller", "memory"},
{ 0x0501, "Flash controller", "flash"},
diff --git a/hw/pci.h b/hw/pci.h
index 52ee8c9c5b..c6a6eb67b6 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -92,6 +92,7 @@ typedef struct PCIIORegion {
pcibus_t filtered_size;
uint8_t type;
PCIMapIORegionFunc *map_func;
+ ram_addr_t ram_addr;
} PCIIORegion;
#define PCI_ROM_SLOT 6
@@ -200,6 +201,8 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
void pci_register_bar(PCIDevice *pci_dev, int region_num,
pcibus_t size, uint8_t type,
PCIMapIORegionFunc *map_func);
+void pci_register_bar_simple(PCIDevice *pci_dev, int region_num,
+ pcibus_t size, uint8_t attr, ram_addr_t ram_addr);
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
uint8_t offset, uint8_t size);
@@ -234,6 +237,7 @@ void pci_bus_new_inplace(PCIBus *bus, DeviceState *parent,
PCIBus *pci_bus_new(DeviceState *parent, const char *name, uint8_t devfn_min);
void pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
void *irq_opaque, int nirq);
+int pci_bus_get_irq_level(PCIBus *bus, int irq_num);
void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
PCIBus *pci_register_bus(DeviceState *parent, const char *name,
pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index 40ee29d38b..9415a1ecf5 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -214,19 +214,6 @@ static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
&pcnet_mmio_readl
};
-static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
-
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\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)
{
@@ -300,8 +287,7 @@ static int pci_pcnet_init(PCIDevice *pci_dev)
pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
- pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE,
- PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
+ pci_register_bar_simple(pci_dev, 1, PCNET_PNPMMIO_SIZE, 0, s->mmio_index);
s->irq = pci_dev->irq[0];
s->phys_mem_read = pci_physical_memory_read;
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
index 358da58a80..5f0d92f10d 100644
--- a/hw/piix_pci.c
+++ b/hw/piix_pci.c
@@ -37,10 +37,31 @@
typedef PCIHostState I440FXState;
+#define PIIX_NUM_PIC_IRQS 16 /* i8259 * 2 */
+#define PIIX_NUM_PIRQS 4ULL /* PIRQ[A-D] */
+#define PIIX_PIRQC 0x60
+
typedef struct PIIX3State {
PCIDevice dev;
- int pci_irq_levels[4];
+
+ /*
+ * bitmap to track pic levels.
+ * The pic level is the logical OR of all the PCI irqs mapped to it
+ * So one PIC level is tracked by PIIX_NUM_PIRQS bits.
+ *
+ * PIRQ is mapped to PIC pins, we track it by
+ * PIIX_NUM_PIRQS * PIIX_NUM_PIC_IRQS = 64 bits with
+ * pic_irq * PIIX_NUM_PIRQS + pirq
+ */
+#if PIIX_NUM_PIC_IRQS * PIIX_NUM_PIRQS > 64
+#error "unable to encode pic state in 64bit in pic_levels."
+#endif
+ uint64_t pic_levels;
+
qemu_irq *pic;
+
+ /* This member isn't used. Just for save/load compatibility */
+ int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
} PIIX3State;
struct PCII440FXState {
@@ -55,16 +76,16 @@ struct PCII440FXState {
#define I440FX_PAM_SIZE 7
#define I440FX_SMRAM 0x72
-static void piix3_set_irq(void *opaque, int irq_num, int level);
+static void piix3_set_irq(void *opaque, int pirq, int level);
/* return the global irq number corresponding to a given device irq
pin. We could also use the bus number to have a more precise
mapping. */
-static int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
+static int pci_slot_get_pirq(PCIDevice *pci_dev, int pci_intx)
{
int slot_addend;
slot_addend = (pci_dev->devfn >> 3) - 1;
- return (irq_num + slot_addend) & 3;
+ return (pci_intx + slot_addend) & 3;
}
static void update_pam(PCII440FXState *d, uint32_t start, uint32_t end, int r)
@@ -162,9 +183,11 @@ static int i440fx_load_old(QEMUFile* f, void *opaque, int version_id)
i440fx_update_memory_mappings(d);
qemu_get_8s(f, &d->smm_enabled);
- if (version_id == 2)
- for (i = 0; i < 4; i++)
- d->piix3->pci_irq_levels[i] = qemu_get_be32(f);
+ if (version_id == 2) {
+ for (i = 0; i < PIIX_NUM_PIRQS; i++) {
+ qemu_get_be32(f); /* dummy load for compatibility */
+ }
+ }
return 0;
}
@@ -236,7 +259,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *
piix3 = DO_UPCAST(PIIX3State, dev,
pci_create_simple_multifunction(b, -1, true, "PIIX3"));
piix3->pic = pic;
- pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, 4);
+ pci_bus_irqs(b, piix3_set_irq, pci_slot_get_pirq, piix3, PIIX_NUM_PIRQS);
(*pi440fx_state)->piix3 = piix3;
*piix3_devfn = piix3->dev.devfn;
@@ -250,26 +273,60 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *
}
/* PIIX3 PCI to ISA bridge */
+static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
+{
+ qemu_set_irq(piix3->pic[pic_irq],
+ !!(piix3->pic_levels &
+ (((1UL << PIIX_NUM_PIRQS) - 1) <<
+ (pic_irq * PIIX_NUM_PIRQS))));
+}
+
+static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
+{
+ int pic_irq;
+ uint64_t mask;
+
+ pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
+ if (pic_irq >= PIIX_NUM_PIC_IRQS) {
+ return;
+ }
-static void piix3_set_irq(void *opaque, int irq_num, int level)
+ mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
+ piix3->pic_levels &= ~mask;
+ piix3->pic_levels |= mask * !!level;
+
+ piix3_set_irq_pic(piix3, pic_irq);
+}
+
+static void piix3_set_irq(void *opaque, int pirq, int level)
{
- int i, pic_irq, pic_level;
PIIX3State *piix3 = opaque;
+ piix3_set_irq_level(piix3, pirq, level);
+}
+
+/* irq routing is changed. so rebuild bitmap */
+static void piix3_update_irq_levels(PIIX3State *piix3)
+{
+ int pirq;
- piix3->pci_irq_levels[irq_num] = level;
-
- /* now we change the pic irq level according to the piix irq mappings */
- /* XXX: optimize */
- pic_irq = piix3->dev.config[0x60 + irq_num];
- if (pic_irq < 16) {
- /* The pic level is the logical OR of all the PCI irqs mapped
- to it */
- pic_level = 0;
- for (i = 0; i < 4; i++) {
- if (pic_irq == piix3->dev.config[0x60 + i])
- pic_level |= piix3->pci_irq_levels[i];
+ piix3->pic_levels = 0;
+ for (pirq = 0; pirq < PIIX_NUM_PIRQS; pirq++) {
+ piix3_set_irq_level(piix3, pirq,
+ pci_bus_get_irq_level(piix3->dev.bus, pirq));
+ }
+}
+
+static void piix3_write_config(PCIDevice *dev,
+ uint32_t address, uint32_t val, int len)
+{
+ pci_default_write_config(dev, address, val, len);
+ if (ranges_overlap(address, len, PIIX_PIRQC, 4)) {
+ PIIX3State *piix3 = DO_UPCAST(PIIX3State, dev, dev);
+ int pic_irq;
+ piix3_update_irq_levels(piix3);
+ for (pic_irq = 0; pic_irq < PIIX_NUM_PIC_IRQS; pic_irq++) {
+ piix3_set_irq_pic(piix3, pic_irq);
}
- qemu_set_irq(piix3->pic[pic_irq], pic_level);
}
}
@@ -310,7 +367,25 @@ static void piix3_reset(void *opaque)
pci_conf[0xac] = 0x00;
pci_conf[0xae] = 0x00;
- memset(d->pci_irq_levels, 0, sizeof(d->pci_irq_levels));
+ d->pic_levels = 0;
+}
+
+static int piix3_post_load(void *opaque, int version_id)
+{
+ PIIX3State *piix3 = opaque;
+ piix3_update_irq_levels(piix3);
+ return 0;
+}
+
+static void piix3_pre_save(void *opaque)
+{
+ int i;
+ PIIX3State *piix3 = opaque;
+
+ for (i = 0; i < ARRAY_SIZE(piix3->pci_irq_levels_vmstate); i++) {
+ piix3->pci_irq_levels_vmstate[i] =
+ pci_bus_get_irq_level(piix3->dev.bus, i);
+ }
}
static const VMStateDescription vmstate_piix3 = {
@@ -318,9 +393,12 @@ static const VMStateDescription vmstate_piix3 = {
.version_id = 3,
.minimum_version_id = 2,
.minimum_version_id_old = 2,
+ .post_load = piix3_post_load,
+ .pre_save = piix3_pre_save,
.fields = (VMStateField []) {
VMSTATE_PCI_DEVICE(dev, PIIX3State),
- VMSTATE_INT32_ARRAY_V(pci_irq_levels, PIIX3State, 4, 3),
+ VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
+ PIIX_NUM_PIRQS, 3),
VMSTATE_END_OF_LIST()
}
};
@@ -359,6 +437,7 @@ static PCIDeviceInfo i440fx_info[] = {
.qdev.no_user = 1,
.no_hotplug = 1,
.init = piix3_initfn,
+ .config_write = piix3_write_config,
},{
/* end of list */
}
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 515652f270..c7c7a3cdfb 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3375,14 +3375,6 @@ static const VMStateDescription vmstate_rtl8139 = {
/***********************************************************/
/* PCI RTL8139 definitions */
-static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- RTL8139State *s = DO_UPCAST(RTL8139State, dev, 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,
pcibus_t addr, pcibus_t size, int type)
{
@@ -3478,8 +3470,7 @@ static int pci_rtl8139_init(PCIDevice *dev)
pci_register_bar(&s->dev, 0, 0x100,
PCI_BASE_ADDRESS_SPACE_IO, rtl8139_ioport_map);
- pci_register_bar(&s->dev, 1, 0x100,
- PCI_BASE_ADDRESS_SPACE_MEMORY, rtl8139_mmio_map);
+ pci_register_bar_simple(&s->dev, 1, 0x100, 0, s->rtl8139_mmio_io_addr);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c
index 8090c17c63..32913ebb06 100644
--- a/hw/usb-ohci.c
+++ b/hw/usb-ohci.c
@@ -1708,13 +1708,6 @@ typedef struct {
OHCIState state;
} OHCIPCIState;
-static void ohci_mapfunc(PCIDevice *pci_dev, int i,
- pcibus_t addr, pcibus_t size, int type)
-{
- OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, pci_dev);
- cpu_register_physical_memory(addr, size, ohci->state.mem);
-}
-
static int usb_ohci_initfn_pci(struct PCIDevice *dev)
{
OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, dev);
@@ -1732,8 +1725,7 @@ static int usb_ohci_initfn_pci(struct PCIDevice *dev)
ohci->state.irq = ohci->pci_dev.irq[0];
/* TODO: avoid cast below by using dev */
- pci_register_bar(&ohci->pci_dev, 0, 256,
- PCI_BASE_ADDRESS_SPACE_MEMORY, ohci_mapfunc);
+ pci_register_bar_simple(&ohci->pci_dev, 0, 256, 0, ohci->state.mem);
return 0;
}
diff --git a/hw/vhost.c b/hw/vhost.c
index 14b571d07c..80f771e448 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -297,10 +297,50 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev,
return 0;
}
+static struct vhost_memory_region *vhost_dev_find_reg(struct vhost_dev *dev,
+ uint64_t start_addr,
+ uint64_t size)
+{
+ int i, n = dev->mem->nregions;
+ for (i = 0; i < n; ++i) {
+ struct vhost_memory_region *reg = dev->mem->regions + i;
+ if (ranges_overlap(reg->guest_phys_addr, reg->memory_size,
+ start_addr, size)) {
+ return reg;
+ }
+ }
+ return NULL;
+}
+
+static bool vhost_dev_cmp_memory(struct vhost_dev *dev,
+ uint64_t start_addr,
+ uint64_t size,
+ uint64_t uaddr)
+{
+ struct vhost_memory_region *reg = vhost_dev_find_reg(dev, start_addr, size);
+ uint64_t reglast;
+ uint64_t memlast;
+
+ if (!reg) {
+ return true;
+ }
+
+ reglast = range_get_last(reg->guest_phys_addr, reg->memory_size);
+ memlast = range_get_last(start_addr, size);
+
+ /* Need to extend region? */
+ if (start_addr < reg->guest_phys_addr || memlast > reglast) {
+ return true;
+ }
+ /* userspace_addr changed? */
+ return uaddr != reg->userspace_addr + start_addr - reg->guest_phys_addr;
+}
+
static void vhost_client_set_memory(CPUPhysMemoryClient *client,
target_phys_addr_t start_addr,
ram_addr_t size,
- ram_addr_t phys_offset)
+ ram_addr_t phys_offset,
+ bool log_dirty)
{
struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
@@ -308,10 +348,29 @@ static void vhost_client_set_memory(CPUPhysMemoryClient *client,
(dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
uint64_t log_size;
int r;
+
dev->mem = qemu_realloc(dev->mem, s);
+ if (log_dirty) {
+ flags = IO_MEM_UNASSIGNED;
+ }
+
assert(size);
+ /* Optimize no-change case. At least cirrus_vga does this a lot at this time. */
+ if (flags == IO_MEM_RAM) {
+ if (!vhost_dev_cmp_memory(dev, start_addr, size,
+ (uintptr_t)qemu_get_ram_ptr(phys_offset))) {
+ /* Region exists with same address. Nothing to do. */
+ return;
+ }
+ } else {
+ if (!vhost_dev_find_reg(dev, start_addr, size)) {
+ /* Removing region that we don't access. Nothing to do. */
+ return;
+ }
+ }
+
vhost_dev_unassign_memory(dev, start_addr, size);
if (flags == IO_MEM_RAM) {
/* Add given mapping, merging adjacent regions if any */
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c
index 4a7fba7f2a..07917212c3 100644
--- a/hw/wdt_i6300esb.c
+++ b/hw/wdt_i6300esb.c
@@ -355,31 +355,6 @@ static void i6300esb_mem_writel(void *vp, target_phys_addr_t addr, uint32_t val)
}
}
-static void i6300esb_map(PCIDevice *dev, int region_num,
- pcibus_t addr, pcibus_t size, int type)
-{
- static CPUReadMemoryFunc * const mem_read[3] = {
- i6300esb_mem_readb,
- i6300esb_mem_readw,
- i6300esb_mem_readl,
- };
- static CPUWriteMemoryFunc * const mem_write[3] = {
- i6300esb_mem_writeb,
- i6300esb_mem_writew,
- i6300esb_mem_writel,
- };
- I6300State *d = DO_UPCAST(I6300State, dev, dev);
- int io_mem;
-
- i6300esb_debug("addr = %"FMT_PCIBUS", size = %"FMT_PCIBUS", type = %d\n",
- addr, size, type);
-
- io_mem = cpu_register_io_memory(mem_read, mem_write, d,
- DEVICE_NATIVE_ENDIAN);
- cpu_register_physical_memory (addr, 0x10, io_mem);
- /* qemu_register_coalesced_mmio (addr, 0x10); ? */
-}
-
static const VMStateDescription vmstate_i6300esb = {
.name = "i6300esb_wdt",
.version_id = sizeof(I6300State),
@@ -407,6 +382,17 @@ static int i6300esb_init(PCIDevice *dev)
{
I6300State *d = DO_UPCAST(I6300State, dev, dev);
uint8_t *pci_conf;
+ int io_mem;
+ static CPUReadMemoryFunc * const mem_read[3] = {
+ i6300esb_mem_readb,
+ i6300esb_mem_readw,
+ i6300esb_mem_readl,
+ };
+ static CPUWriteMemoryFunc * const mem_write[3] = {
+ i6300esb_mem_writeb,
+ i6300esb_mem_writew,
+ i6300esb_mem_writel,
+ };
i6300esb_debug("I6300State = %p\n", d);
@@ -418,8 +404,10 @@ static int i6300esb_init(PCIDevice *dev)
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_INTEL_ESB_9);
pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER);
- pci_register_bar(&d->dev, 0, 0x10,
- PCI_BASE_ADDRESS_SPACE_MEMORY, i6300esb_map);
+ io_mem = cpu_register_io_memory(mem_read, mem_write, d,
+ DEVICE_NATIVE_ENDIAN);
+ pci_register_bar_simple(&d->dev, 0, 0x10, 0, io_mem);
+ /* qemu_register_coalesced_mmio (addr, 0x10); ? */
return 0;
}