Merge remote-tracking branch 'mst/for_anthony' into staging
This commit is contained in:
commit
3964f535c3
22
cpu-common.h
22
cpu-common.h
@ -34,10 +34,21 @@ typedef unsigned long ram_addr_t;
|
||||
typedef void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
|
||||
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
|
||||
|
||||
void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
|
||||
ram_addr_t size,
|
||||
ram_addr_t phys_offset,
|
||||
ram_addr_t region_offset);
|
||||
void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
|
||||
ram_addr_t size,
|
||||
ram_addr_t phys_offset,
|
||||
ram_addr_t region_offset,
|
||||
bool log_dirty);
|
||||
|
||||
static inline void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
|
||||
ram_addr_t size,
|
||||
ram_addr_t phys_offset,
|
||||
ram_addr_t region_offset)
|
||||
{
|
||||
cpu_register_physical_memory_log(start_addr, size, phys_offset,
|
||||
region_offset, false);
|
||||
}
|
||||
|
||||
static inline void cpu_register_physical_memory(target_phys_addr_t start_addr,
|
||||
ram_addr_t size,
|
||||
ram_addr_t phys_offset)
|
||||
@ -91,7 +102,8 @@ struct CPUPhysMemoryClient {
|
||||
void (*set_memory)(struct 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);
|
||||
int (*sync_dirty_bitmap)(struct CPUPhysMemoryClient *client,
|
||||
target_phys_addr_t start_addr,
|
||||
target_phys_addr_t end_addr);
|
||||
|
30
exec.c
30
exec.c
@ -1718,11 +1718,12 @@ static QLIST_HEAD(memory_client_list, CPUPhysMemoryClient) memory_client_list
|
||||
|
||||
static void cpu_notify_set_memory(target_phys_addr_t start_addr,
|
||||
ram_addr_t size,
|
||||
ram_addr_t phys_offset)
|
||||
ram_addr_t phys_offset,
|
||||
bool log_dirty)
|
||||
{
|
||||
CPUPhysMemoryClient *client;
|
||||
QLIST_FOREACH(client, &memory_client_list, list) {
|
||||
client->set_memory(client, start_addr, size, phys_offset);
|
||||
client->set_memory(client, start_addr, size, phys_offset, log_dirty);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1749,8 +1750,14 @@ static int cpu_notify_migration_log(int enable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The l1_phys_map provides the upper P_L1_BITs of the guest physical
|
||||
* address. Each intermediate table provides the next L2_BITs of guest
|
||||
* physical address space. The number of levels vary based on host and
|
||||
* guest configuration, making it efficient to build the final guest
|
||||
* physical address by seeding the L1 offset and shifting and adding in
|
||||
* each L2 offset as we recurse through them. */
|
||||
static void phys_page_for_each_1(CPUPhysMemoryClient *client,
|
||||
int level, void **lp)
|
||||
int level, void **lp, target_phys_addr_t addr)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -1759,16 +1766,18 @@ static void phys_page_for_each_1(CPUPhysMemoryClient *client,
|
||||
}
|
||||
if (level == 0) {
|
||||
PhysPageDesc *pd = *lp;
|
||||
addr <<= L2_BITS + TARGET_PAGE_BITS;
|
||||
for (i = 0; i < L2_SIZE; ++i) {
|
||||
if (pd[i].phys_offset != IO_MEM_UNASSIGNED) {
|
||||
client->set_memory(client, pd[i].region_offset,
|
||||
TARGET_PAGE_SIZE, pd[i].phys_offset);
|
||||
client->set_memory(client, addr | i << TARGET_PAGE_BITS,
|
||||
TARGET_PAGE_SIZE, pd[i].phys_offset, false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
void **pp = *lp;
|
||||
for (i = 0; i < L2_SIZE; ++i) {
|
||||
phys_page_for_each_1(client, level - 1, pp + i);
|
||||
phys_page_for_each_1(client, level - 1, pp + i,
|
||||
(addr << L2_BITS) | i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1778,7 +1787,7 @@ static void phys_page_for_each(CPUPhysMemoryClient *client)
|
||||
int i;
|
||||
for (i = 0; i < P_L1_SIZE; ++i) {
|
||||
phys_page_for_each_1(client, P_L1_SHIFT / L2_BITS - 1,
|
||||
l1_phys_map + 1);
|
||||
l1_phys_map + i, i);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2607,10 +2616,11 @@ static subpage_t *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
|
||||
start_addr and region_offset are rounded down to a page boundary
|
||||
before calculating this offset. This should not be a problem unless
|
||||
the low bits of start_addr and region_offset differ. */
|
||||
void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
|
||||
void cpu_register_physical_memory_log(target_phys_addr_t start_addr,
|
||||
ram_addr_t size,
|
||||
ram_addr_t phys_offset,
|
||||
ram_addr_t region_offset)
|
||||
ram_addr_t region_offset,
|
||||
bool log_dirty)
|
||||
{
|
||||
target_phys_addr_t addr, end_addr;
|
||||
PhysPageDesc *p;
|
||||
@ -2619,7 +2629,7 @@ void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
|
||||
subpage_t *subpage;
|
||||
|
||||
assert(size);
|
||||
cpu_notify_set_memory(start_addr, size, phys_offset);
|
||||
cpu_notify_set_memory(start_addr, size, phys_offset, log_dirty);
|
||||
|
||||
if (phys_offset == IO_MEM_UNASSIGNED) {
|
||||
region_offset = start_addr;
|
||||
|
@ -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;
|
||||
}
|
||||
|
342
hw/eepro100.c
342
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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
12
hw/msi.c
12
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");
|
||||
}
|
||||
|
||||
|
25
hw/pci.c
25
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"},
|
||||
|
4
hw/pci.h
4
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,
|
||||
|
@ -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;
|
||||
|
129
hw/piix_pci.c
129
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(void *opaque, int irq_num, int level)
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
piix3->pci_irq_levels[irq_num] = level;
|
||||
/* irq routing is changed. so rebuild bitmap */
|
||||
static void piix3_update_irq_levels(PIIX3State *piix3)
|
||||
{
|
||||
int pirq;
|
||||
|
||||
/* 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 */
|
||||
}
|
||||
|
11
hw/rtl8139.c
11
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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
61
hw/vhost.c
61
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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
62
kvm-all.c
62
kvm-all.c
@ -245,48 +245,60 @@ err:
|
||||
/*
|
||||
* dirty pages logging control
|
||||
*/
|
||||
static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr,
|
||||
ram_addr_t size, int flags, int mask)
|
||||
|
||||
static int kvm_mem_flags(KVMState *s, bool log_dirty)
|
||||
{
|
||||
return log_dirty ? KVM_MEM_LOG_DIRTY_PAGES : 0;
|
||||
}
|
||||
|
||||
static int kvm_slot_dirty_pages_log_change(KVMSlot *mem, bool log_dirty)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
KVMSlot *mem = kvm_lookup_matching_slot(s, phys_addr, phys_addr + size);
|
||||
int flags, mask = KVM_MEM_LOG_DIRTY_PAGES;
|
||||
int old_flags;
|
||||
|
||||
if (mem == NULL) {
|
||||
fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-"
|
||||
TARGET_FMT_plx "\n", __func__, phys_addr,
|
||||
(target_phys_addr_t)(phys_addr + size - 1));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
old_flags = mem->flags;
|
||||
|
||||
flags = (mem->flags & ~mask) | flags;
|
||||
flags = (mem->flags & ~mask) | kvm_mem_flags(s, log_dirty);
|
||||
mem->flags = flags;
|
||||
|
||||
/* If nothing changed effectively, no need to issue ioctl */
|
||||
if (s->migration_log) {
|
||||
flags |= KVM_MEM_LOG_DIRTY_PAGES;
|
||||
}
|
||||
|
||||
if (flags == old_flags) {
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return kvm_set_user_memory_region(s, mem);
|
||||
}
|
||||
|
||||
static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr,
|
||||
ram_addr_t size, bool log_dirty)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
KVMSlot *mem = kvm_lookup_matching_slot(s, phys_addr, phys_addr + size);
|
||||
|
||||
if (mem == NULL) {
|
||||
fprintf(stderr, "BUG: %s: invalid parameters " TARGET_FMT_plx "-"
|
||||
TARGET_FMT_plx "\n", __func__, phys_addr,
|
||||
(target_phys_addr_t)(phys_addr + size - 1));
|
||||
return -EINVAL;
|
||||
}
|
||||
return kvm_slot_dirty_pages_log_change(mem, log_dirty);
|
||||
}
|
||||
|
||||
static int kvm_log_start(CPUPhysMemoryClient *client,
|
||||
target_phys_addr_t phys_addr, ram_addr_t size)
|
||||
{
|
||||
return kvm_dirty_pages_log_change(phys_addr, size, KVM_MEM_LOG_DIRTY_PAGES,
|
||||
KVM_MEM_LOG_DIRTY_PAGES);
|
||||
return kvm_dirty_pages_log_change(phys_addr, size, true);
|
||||
}
|
||||
|
||||
static int kvm_log_stop(CPUPhysMemoryClient *client,
|
||||
target_phys_addr_t phys_addr, ram_addr_t size)
|
||||
{
|
||||
return kvm_dirty_pages_log_change(phys_addr, size, 0,
|
||||
KVM_MEM_LOG_DIRTY_PAGES);
|
||||
return kvm_dirty_pages_log_change(phys_addr, size, false);
|
||||
}
|
||||
|
||||
static int kvm_set_migration_log(int enable)
|
||||
@ -508,7 +520,7 @@ kvm_check_extension_list(KVMState *s, const KVMCapabilityInfo *list)
|
||||
}
|
||||
|
||||
static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
|
||||
ram_addr_t phys_offset)
|
||||
ram_addr_t phys_offset, bool log_dirty)
|
||||
{
|
||||
KVMState *s = kvm_state;
|
||||
ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
|
||||
@ -533,7 +545,8 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
|
||||
(start_addr + size <= mem->start_addr + mem->memory_size) &&
|
||||
(phys_offset - start_addr == mem->phys_offset - mem->start_addr)) {
|
||||
/* The new slot fits into the existing one and comes with
|
||||
* identical parameters - nothing to be done. */
|
||||
* identical parameters - update flags and done. */
|
||||
kvm_slot_dirty_pages_log_change(mem, log_dirty);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -563,7 +576,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
|
||||
mem->memory_size = old.memory_size;
|
||||
mem->start_addr = old.start_addr;
|
||||
mem->phys_offset = old.phys_offset;
|
||||
mem->flags = 0;
|
||||
mem->flags = kvm_mem_flags(s, log_dirty);
|
||||
|
||||
err = kvm_set_user_memory_region(s, mem);
|
||||
if (err) {
|
||||
@ -584,7 +597,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
|
||||
mem->memory_size = start_addr - old.start_addr;
|
||||
mem->start_addr = old.start_addr;
|
||||
mem->phys_offset = old.phys_offset;
|
||||
mem->flags = 0;
|
||||
mem->flags = kvm_mem_flags(s, log_dirty);
|
||||
|
||||
err = kvm_set_user_memory_region(s, mem);
|
||||
if (err) {
|
||||
@ -603,7 +616,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
|
||||
size_delta = mem->start_addr - old.start_addr;
|
||||
mem->memory_size = old.memory_size - size_delta;
|
||||
mem->phys_offset = old.phys_offset + size_delta;
|
||||
mem->flags = 0;
|
||||
mem->flags = kvm_mem_flags(s, log_dirty);
|
||||
|
||||
err = kvm_set_user_memory_region(s, mem);
|
||||
if (err) {
|
||||
@ -626,7 +639,7 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
|
||||
mem->memory_size = size;
|
||||
mem->start_addr = start_addr;
|
||||
mem->phys_offset = phys_offset;
|
||||
mem->flags = 0;
|
||||
mem->flags = kvm_mem_flags(s, log_dirty);
|
||||
|
||||
err = kvm_set_user_memory_region(s, mem);
|
||||
if (err) {
|
||||
@ -638,9 +651,10 @@ static void kvm_set_phys_mem(target_phys_addr_t start_addr, ram_addr_t size,
|
||||
|
||||
static void kvm_client_set_memory(struct CPUPhysMemoryClient *client,
|
||||
target_phys_addr_t start_addr,
|
||||
ram_addr_t size, ram_addr_t phys_offset)
|
||||
ram_addr_t size, ram_addr_t phys_offset,
|
||||
bool log_dirty)
|
||||
{
|
||||
kvm_set_phys_mem(start_addr, size, phys_offset);
|
||||
kvm_set_phys_mem(start_addr, size, phys_offset, log_dirty);
|
||||
}
|
||||
|
||||
static int kvm_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
|
||||
|
Loading…
Reference in New Issue
Block a user