Merge remote-tracking branch 'mst/for_anthony' into staging
This commit is contained in:
commit
3964f535c3
18
cpu-common.h
18
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 void CPUWriteMemoryFunc(void *opaque, target_phys_addr_t addr, uint32_t value);
|
||||||
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
|
typedef uint32_t CPUReadMemoryFunc(void *opaque, target_phys_addr_t addr);
|
||||||
|
|
||||||
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 size,
|
||||||
ram_addr_t phys_offset,
|
ram_addr_t phys_offset,
|
||||||
ram_addr_t region_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,
|
static inline void cpu_register_physical_memory(target_phys_addr_t start_addr,
|
||||||
ram_addr_t size,
|
ram_addr_t size,
|
||||||
ram_addr_t phys_offset)
|
ram_addr_t phys_offset)
|
||||||
@ -91,7 +102,8 @@ struct CPUPhysMemoryClient {
|
|||||||
void (*set_memory)(struct CPUPhysMemoryClient *client,
|
void (*set_memory)(struct CPUPhysMemoryClient *client,
|
||||||
target_phys_addr_t start_addr,
|
target_phys_addr_t start_addr,
|
||||||
ram_addr_t size,
|
ram_addr_t size,
|
||||||
ram_addr_t phys_offset);
|
ram_addr_t phys_offset,
|
||||||
|
bool log_dirty);
|
||||||
int (*sync_dirty_bitmap)(struct CPUPhysMemoryClient *client,
|
int (*sync_dirty_bitmap)(struct CPUPhysMemoryClient *client,
|
||||||
target_phys_addr_t start_addr,
|
target_phys_addr_t start_addr,
|
||||||
target_phys_addr_t end_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,
|
static void cpu_notify_set_memory(target_phys_addr_t start_addr,
|
||||||
ram_addr_t size,
|
ram_addr_t size,
|
||||||
ram_addr_t phys_offset)
|
ram_addr_t phys_offset,
|
||||||
|
bool log_dirty)
|
||||||
{
|
{
|
||||||
CPUPhysMemoryClient *client;
|
CPUPhysMemoryClient *client;
|
||||||
QLIST_FOREACH(client, &memory_client_list, list) {
|
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;
|
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,
|
static void phys_page_for_each_1(CPUPhysMemoryClient *client,
|
||||||
int level, void **lp)
|
int level, void **lp, target_phys_addr_t addr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -1759,16 +1766,18 @@ static void phys_page_for_each_1(CPUPhysMemoryClient *client,
|
|||||||
}
|
}
|
||||||
if (level == 0) {
|
if (level == 0) {
|
||||||
PhysPageDesc *pd = *lp;
|
PhysPageDesc *pd = *lp;
|
||||||
|
addr <<= L2_BITS + TARGET_PAGE_BITS;
|
||||||
for (i = 0; i < L2_SIZE; ++i) {
|
for (i = 0; i < L2_SIZE; ++i) {
|
||||||
if (pd[i].phys_offset != IO_MEM_UNASSIGNED) {
|
if (pd[i].phys_offset != IO_MEM_UNASSIGNED) {
|
||||||
client->set_memory(client, pd[i].region_offset,
|
client->set_memory(client, addr | i << TARGET_PAGE_BITS,
|
||||||
TARGET_PAGE_SIZE, pd[i].phys_offset);
|
TARGET_PAGE_SIZE, pd[i].phys_offset, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
void **pp = *lp;
|
void **pp = *lp;
|
||||||
for (i = 0; i < L2_SIZE; ++i) {
|
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;
|
int i;
|
||||||
for (i = 0; i < P_L1_SIZE; ++i) {
|
for (i = 0; i < P_L1_SIZE; ++i) {
|
||||||
phys_page_for_each_1(client, P_L1_SHIFT / L2_BITS - 1,
|
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
|
start_addr and region_offset are rounded down to a page boundary
|
||||||
before calculating this offset. This should not be a problem unless
|
before calculating this offset. This should not be a problem unless
|
||||||
the low bits of start_addr and region_offset differ. */
|
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 size,
|
||||||
ram_addr_t phys_offset,
|
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;
|
target_phys_addr_t addr, end_addr;
|
||||||
PhysPageDesc *p;
|
PhysPageDesc *p;
|
||||||
@ -2619,7 +2629,7 @@ void cpu_register_physical_memory_offset(target_phys_addr_t start_addr,
|
|||||||
subpage_t *subpage;
|
subpage_t *subpage;
|
||||||
|
|
||||||
assert(size);
|
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) {
|
if (phys_offset == IO_MEM_UNASSIGNED) {
|
||||||
region_offset = start_addr;
|
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) {
|
if (!s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
|
||||||
s->vga.map_addr = s->vga.lfb_addr;
|
s->vga.map_addr = s->vga.lfb_addr;
|
||||||
s->vga.map_end = s->vga.lfb_end;
|
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)
|
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] & 0x14) == 0x14)
|
||||||
&& !(s->vga.gr[0x0B] & 0x02)) {
|
&& !(s->vga.gr[0x0B] & 0x02)) {
|
||||||
|
|
||||||
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x8000,
|
cpu_register_physical_memory_log(isa_mem_base + 0xa0000, 0x8000,
|
||||||
(s->vga.vram_offset + s->cirrus_bank_base[0]) | IO_MEM_RAM);
|
(s->vga.vram_offset +
|
||||||
cpu_register_physical_memory(isa_mem_base + 0xa8000, 0x8000,
|
s->cirrus_bank_base[0]) |
|
||||||
(s->vga.vram_offset + s->cirrus_bank_base[1]) | IO_MEM_RAM);
|
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;
|
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;
|
s->vga.cursor_draw_line = cirrus_cursor_draw_line;
|
||||||
|
|
||||||
qemu_register_reset(cirrus_reset, s);
|
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);
|
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,
|
static void pci_cirrus_write_config(PCIDevice *d,
|
||||||
uint32_t address, uint32_t val, int len)
|
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_register_bar(&d->dev, 0, 0x2000000,
|
||||||
PCI_BASE_ADDRESS_MEM_PREFETCH, cirrus_pci_lfb_map);
|
PCI_BASE_ADDRESS_MEM_PREFETCH, cirrus_pci_lfb_map);
|
||||||
if (device_id == CIRRUS_ID_CLGD5446) {
|
if (device_id == CIRRUS_ID_CLGD5446) {
|
||||||
pci_register_bar(&d->dev, 1, CIRRUS_PNPMMIO_SIZE,
|
pci_register_bar_simple(&d->dev, 1, CIRRUS_PNPMMIO_SIZE, 0,
|
||||||
PCI_BASE_ADDRESS_SPACE_MEMORY, cirrus_pci_mmio_map);
|
s->cirrus_mmio_io_addr);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
342
hw/eepro100.c
342
hw/eepro100.c
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* QEMU i8255x (PRO100) emulation
|
* 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
|
* Portions of the code are copies from grub / etherboot eepro100.c
|
||||||
* and linux e100.c.
|
* and linux e100.c.
|
||||||
@ -20,11 +20,10 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* Tested features (i82559):
|
* Tested features (i82559):
|
||||||
* PXE boot (i386) ok
|
* PXE boot (i386 guest, i386 / mips / mipsel / ppc host) ok
|
||||||
* Linux networking (i386) ok
|
* Linux networking (i386) ok
|
||||||
*
|
*
|
||||||
* Untested:
|
* Untested:
|
||||||
* non-i386 platforms
|
|
||||||
* Windows networking
|
* Windows networking
|
||||||
*
|
*
|
||||||
* References:
|
* References:
|
||||||
@ -48,6 +47,15 @@
|
|||||||
#include "eeprom93xx.h"
|
#include "eeprom93xx.h"
|
||||||
#include "sysemu.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
|
#define KiB 1024
|
||||||
|
|
||||||
/* Debug EEPRO100 card. */
|
/* Debug EEPRO100 card. */
|
||||||
@ -130,7 +138,7 @@ typedef struct {
|
|||||||
|
|
||||||
/* Offsets to the various registers.
|
/* Offsets to the various registers.
|
||||||
All accesses need not be longword aligned. */
|
All accesses need not be longword aligned. */
|
||||||
enum speedo_offsets {
|
typedef enum {
|
||||||
SCBStatus = 0, /* Status Word. */
|
SCBStatus = 0, /* Status Word. */
|
||||||
SCBAck = 1,
|
SCBAck = 1,
|
||||||
SCBCmd = 2, /* Rx/Command Unit command and status. */
|
SCBCmd = 2, /* Rx/Command Unit command and status. */
|
||||||
@ -145,7 +153,7 @@ enum speedo_offsets {
|
|||||||
SCBpmdr = 27, /* Power Management Driver. */
|
SCBpmdr = 27, /* Power Management Driver. */
|
||||||
SCBgctrl = 28, /* General Control. */
|
SCBgctrl = 28, /* General Control. */
|
||||||
SCBgstat = 29, /* General Status. */
|
SCBgstat = 29, /* General Status. */
|
||||||
};
|
} E100RegisterOffset;
|
||||||
|
|
||||||
/* A speedo3 transmit buffer descriptor with two buffers... */
|
/* A speedo3 transmit buffer descriptor with two buffers... */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -173,7 +181,7 @@ typedef struct {
|
|||||||
uint32_t rx_buf_addr; /* void * */
|
uint32_t rx_buf_addr; /* void * */
|
||||||
uint16_t count;
|
uint16_t count;
|
||||||
uint16_t size;
|
uint16_t size;
|
||||||
char packet[MAX_ETH_FRAME_SIZE + 4];
|
/* Ethernet frame data follows. */
|
||||||
} eepro100_rx_t;
|
} eepro100_rx_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@ -228,11 +236,10 @@ typedef struct {
|
|||||||
uint8_t scb_stat; /* SCB stat/ack byte */
|
uint8_t scb_stat; /* SCB stat/ack byte */
|
||||||
uint8_t int_stat; /* PCI interrupt status */
|
uint8_t int_stat; /* PCI interrupt status */
|
||||||
/* region must not be saved by nic_save. */
|
/* 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];
|
uint16_t mdimem[32];
|
||||||
eeprom_t *eeprom;
|
eeprom_t *eeprom;
|
||||||
uint32_t device; /* device variant */
|
uint32_t device; /* device variant */
|
||||||
uint32_t pointer;
|
|
||||||
/* (cu_base + cu_offset) address the next command block in the command block list. */
|
/* (cu_base + cu_offset) address the next command block in the command block list. */
|
||||||
uint32_t cu_base; /* CU base address */
|
uint32_t cu_base; /* CU base address */
|
||||||
uint32_t cu_offset; /* CU address offset */
|
uint32_t cu_offset; /* CU address offset */
|
||||||
@ -249,11 +256,13 @@ typedef struct {
|
|||||||
/* Statistical counters. Also used for wake-up packet (i82559). */
|
/* Statistical counters. Also used for wake-up packet (i82559). */
|
||||||
eepro100_stats_t statistics;
|
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. */
|
/* Configuration bytes. */
|
||||||
uint8_t configuration[22];
|
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 */
|
/* vmstate for each particular nic */
|
||||||
VMStateDescription *vmstate;
|
VMStateDescription *vmstate;
|
||||||
|
|
||||||
@ -307,11 +316,36 @@ static const uint16_t eepro100_mdi_mask[] = {
|
|||||||
0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* XXX: optimize */
|
/* Read a 16 bit little endian value from physical memory. */
|
||||||
static void stl_le_phys(target_phys_addr_t addr, uint32_t val)
|
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);
|
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
|
#define POLYNOMIAL 0x04c11db6
|
||||||
@ -339,6 +373,36 @@ static unsigned compute_mcast_idx(const uint8_t * ep)
|
|||||||
return (crc & BITS(7, 2)) >> 2;
|
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)
|
#if defined(DEBUG_EEPRO100)
|
||||||
static const char *nic_dump(const uint8_t * buf, unsigned size)
|
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]));
|
TRACE(EEPROM, logout("checksum=0x%04x\n", eeprom_contents[EEPROM_SIZE - 1]));
|
||||||
|
|
||||||
memset(s->mem, 0, sizeof(s->mem));
|
memset(s->mem, 0, sizeof(s->mem));
|
||||||
uint32_t val = BIT(21);
|
e100_write_reg4(s, SCBCtrlMDI, BIT(21));
|
||||||
memcpy(&s->mem[SCBCtrlMDI], &val, sizeof(val));
|
|
||||||
|
|
||||||
assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
|
assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
|
||||||
memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem));
|
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.
|
* values which really matter.
|
||||||
* Number of data should check configuration!!!
|
* Number of data should check configuration!!!
|
||||||
*/
|
*/
|
||||||
cpu_physical_memory_write(s->statsaddr,
|
cpu_physical_memory_write(s->statsaddr, &s->statistics, s->stats_size);
|
||||||
(uint8_t *) & s->statistics, s->stats_size);
|
e100_stl_le_phys(s->statsaddr + 0, s->statistics.tx_good_frames);
|
||||||
stl_le_phys(s->statsaddr + 0, s->statistics.tx_good_frames);
|
e100_stl_le_phys(s->statsaddr + 36, s->statistics.rx_good_frames);
|
||||||
stl_le_phys(s->statsaddr + 36, s->statistics.rx_good_frames);
|
e100_stl_le_phys(s->statsaddr + 48, s->statistics.rx_resource_errors);
|
||||||
stl_le_phys(s->statsaddr + 48, s->statistics.rx_resource_errors);
|
e100_stl_le_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors);
|
||||||
stl_le_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors);
|
|
||||||
#if 0
|
#if 0
|
||||||
stw_le_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames);
|
e100_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 + 78, s->statistics.rcv_tco_frames);
|
||||||
missing("CU dump statistical counters");
|
missing("CU dump statistical counters");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_cb(EEPRO100State *s)
|
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.status = le16_to_cpu(s->tx.status);
|
||||||
s->tx.command = le16_to_cpu(s->tx.command);
|
s->tx.command = le16_to_cpu(s->tx.command);
|
||||||
s->tx.link = le32_to_cpu(s->tx.link);
|
s->tx.link = le32_to_cpu(s->tx.link);
|
||||||
@ -739,10 +801,10 @@ static void tx_command(EEPRO100State *s)
|
|||||||
}
|
}
|
||||||
assert(tcb_bytes <= sizeof(buf));
|
assert(tcb_bytes <= sizeof(buf));
|
||||||
while (size < tcb_bytes) {
|
while (size < tcb_bytes) {
|
||||||
uint32_t tx_buffer_address = ldl_phys(tbd_address);
|
uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
|
||||||
uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
|
uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
|
||||||
#if 0
|
#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
|
#endif
|
||||||
tbd_address += 8;
|
tbd_address += 8;
|
||||||
TRACE(RXTX, logout
|
TRACE(RXTX, logout
|
||||||
@ -761,9 +823,9 @@ static void tx_command(EEPRO100State *s)
|
|||||||
if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) {
|
if (s->has_extended_tcb_support && !(s->configuration[6] & BIT(4))) {
|
||||||
/* Extended Flexible TCB. */
|
/* Extended Flexible TCB. */
|
||||||
for (; tbd_count < 2; tbd_count++) {
|
for (; tbd_count < 2; tbd_count++) {
|
||||||
uint32_t tx_buffer_address = ldl_phys(tbd_address);
|
uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
|
||||||
uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
|
uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
|
||||||
uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
|
uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6);
|
||||||
tbd_address += 8;
|
tbd_address += 8;
|
||||||
TRACE(RXTX, logout
|
TRACE(RXTX, logout
|
||||||
("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
|
("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;
|
tbd_address = tbd_array;
|
||||||
for (; tbd_count < s->tx.tbd_count; tbd_count++) {
|
for (; tbd_count < s->tx.tbd_count; tbd_count++) {
|
||||||
uint32_t tx_buffer_address = ldl_phys(tbd_address);
|
uint32_t tx_buffer_address = e100_ldl_le_phys(tbd_address);
|
||||||
uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
|
uint16_t tx_buffer_size = e100_ldw_le_phys(tbd_address + 4);
|
||||||
uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
|
uint16_t tx_buffer_el = e100_ldw_le_phys(tbd_address + 6);
|
||||||
tbd_address += 8;
|
tbd_address += 8;
|
||||||
TRACE(RXTX, logout
|
TRACE(RXTX, logout
|
||||||
("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
|
("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
|
||||||
@ -889,7 +951,7 @@ static void action_command(EEPRO100State *s)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* Write new status. */
|
/* 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) {
|
if (bit_i) {
|
||||||
/* CU completed action. */
|
/* CU completed action. */
|
||||||
eepro100_cx_interrupt(s);
|
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);
|
logout("unexpected CU state is %u\n", cu_state);
|
||||||
}
|
}
|
||||||
set_cu_state(s, cu_active);
|
set_cu_state(s, cu_active);
|
||||||
s->cu_offset = s->pointer;
|
s->cu_offset = e100_read_reg4(s, SCBPointer);
|
||||||
action_command(s);
|
action_command(s);
|
||||||
break;
|
break;
|
||||||
case CU_RESUME:
|
case CU_RESUME:
|
||||||
@ -949,25 +1011,25 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
|
|||||||
break;
|
break;
|
||||||
case CU_STATSADDR:
|
case CU_STATSADDR:
|
||||||
/* Load dump counters address. */
|
/* 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));
|
TRACE(OTHER, logout("val=0x%02x (status address)\n", val));
|
||||||
break;
|
break;
|
||||||
case CU_SHOWSTATS:
|
case CU_SHOWSTATS:
|
||||||
/* Dump statistical counters. */
|
/* Dump statistical counters. */
|
||||||
TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val));
|
TRACE(OTHER, logout("val=0x%02x (dump stats)\n", val));
|
||||||
dump_statistics(s);
|
dump_statistics(s);
|
||||||
stl_le_phys(s->statsaddr + s->stats_size, 0xa005);
|
e100_stl_le_phys(s->statsaddr + s->stats_size, 0xa005);
|
||||||
break;
|
break;
|
||||||
case CU_CMD_BASE:
|
case CU_CMD_BASE:
|
||||||
/* Load CU base. */
|
/* Load CU base. */
|
||||||
TRACE(OTHER, logout("val=0x%02x (CU base address)\n", val));
|
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;
|
break;
|
||||||
case CU_DUMPSTATS:
|
case CU_DUMPSTATS:
|
||||||
/* Dump and reset statistical counters. */
|
/* Dump and reset statistical counters. */
|
||||||
TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val));
|
TRACE(OTHER, logout("val=0x%02x (dump stats and reset)\n", val));
|
||||||
dump_statistics(s);
|
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));
|
memset(&s->statistics, 0, sizeof(s->statistics));
|
||||||
break;
|
break;
|
||||||
case CU_SRESUME:
|
case CU_SRESUME:
|
||||||
@ -994,7 +1056,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
set_ru_state(s, ru_ready);
|
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));
|
TRACE(OTHER, logout("val=0x%02x (rx start)\n", val));
|
||||||
break;
|
break;
|
||||||
case RX_RESUME:
|
case RX_RESUME:
|
||||||
@ -1018,7 +1080,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
|
|||||||
case RX_ADDR_LOAD:
|
case RX_ADDR_LOAD:
|
||||||
/* Load RU base. */
|
/* Load RU base. */
|
||||||
TRACE(OTHER, logout("val=0x%02x (RU base address)\n", val));
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
logout("val=0x%02x (undefined RU command)\n", val);
|
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)
|
static uint16_t eepro100_read_eeprom(EEPRO100State * s)
|
||||||
{
|
{
|
||||||
uint16_t val;
|
uint16_t val = e100_read_reg2(s, SCBeeprom);
|
||||||
memcpy(&val, &s->mem[SCBeeprom], sizeof(val));
|
|
||||||
if (eeprom93xx_read(s->eeprom)) {
|
if (eeprom93xx_read(s->eeprom)) {
|
||||||
val |= EEPROM_DO;
|
val |= EEPROM_DO;
|
||||||
} else {
|
} else {
|
||||||
@ -1076,12 +1137,6 @@ static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
|
|||||||
eeprom93xx_write(eeprom, eecs, eesk, eedi);
|
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.
|
* MDI emulation.
|
||||||
@ -1121,8 +1176,7 @@ static const char *reg2name(uint8_t reg)
|
|||||||
|
|
||||||
static uint32_t eepro100_read_mdi(EEPRO100State * s)
|
static uint32_t eepro100_read_mdi(EEPRO100State * s)
|
||||||
{
|
{
|
||||||
uint32_t val;
|
uint32_t val = e100_read_reg4(s, SCBCtrlMDI);
|
||||||
memcpy(&val, &s->mem[0x10], sizeof(val));
|
|
||||||
|
|
||||||
#ifdef DEBUG_EEPRO100
|
#ifdef DEBUG_EEPRO100
|
||||||
uint8_t raiseint = (val & BIT(29)) >> 29;
|
uint8_t raiseint = (val & BIT(29)) >> 29;
|
||||||
@ -1139,8 +1193,9 @@ static uint32_t eepro100_read_mdi(EEPRO100State * s)
|
|||||||
return val;
|
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 raiseint = (val & BIT(29)) >> 29;
|
||||||
uint8_t opcode = (val & BITS(27, 26)) >> 26;
|
uint8_t opcode = (val & BITS(27, 26)) >> 26;
|
||||||
uint8_t phy = (val & BITS(25, 21)) >> 21;
|
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;
|
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;
|
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);
|
uint32_t address = (val & ~PORT_SELECTION_MASK);
|
||||||
uint8_t selection = (val & PORT_SELECTION_MASK);
|
uint8_t selection = (val & PORT_SELECTION_MASK);
|
||||||
switch (selection) {
|
switch (selection) {
|
||||||
@ -1268,10 +1323,10 @@ static void eepro100_write_port(EEPRO100State * s, uint32_t val)
|
|||||||
case PORT_SELFTEST:
|
case PORT_SELFTEST:
|
||||||
TRACE(OTHER, logout("selftest address=0x%08x\n", address));
|
TRACE(OTHER, logout("selftest address=0x%08x\n", address));
|
||||||
eepro100_selftest_t data;
|
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_sign = 0xffffffff;
|
||||||
data.st_result = 0;
|
data.st_result = 0;
|
||||||
cpu_physical_memory_write(address, (uint8_t *) & data, sizeof(data));
|
cpu_physical_memory_write(address, &data, sizeof(data));
|
||||||
break;
|
break;
|
||||||
case PORT_SELECTIVE_RESET:
|
case PORT_SELECTIVE_RESET:
|
||||||
TRACE(OTHER, logout("selective reset, selftest address=0x%08x\n", address));
|
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;
|
uint8_t val = 0;
|
||||||
if (addr <= sizeof(s->mem) - sizeof(val)) {
|
if (addr <= sizeof(s->mem) - sizeof(val)) {
|
||||||
memcpy(&val, &s->mem[addr], sizeof(val));
|
val = s->mem[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
@ -1316,10 +1371,20 @@ static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
|
|||||||
case SCBeeprom:
|
case SCBeeprom:
|
||||||
val = eepro100_read_eeprom(s);
|
val = eepro100_read_eeprom(s);
|
||||||
break;
|
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 */
|
case SCBpmdr: /* Power Management Driver Register */
|
||||||
val = 0;
|
val = 0;
|
||||||
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
||||||
break;
|
break;
|
||||||
|
case SCBgctrl: /* General Control Register */
|
||||||
|
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
||||||
|
break;
|
||||||
case SCBgstat: /* General Status Register */
|
case SCBgstat: /* General Status Register */
|
||||||
/* 100 Mbps full duplex, valid link */
|
/* 100 Mbps full duplex, valid link */
|
||||||
val = 0x07;
|
val = 0x07;
|
||||||
@ -1336,7 +1401,7 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
|
|||||||
{
|
{
|
||||||
uint16_t val = 0;
|
uint16_t val = 0;
|
||||||
if (addr <= sizeof(s->mem) - sizeof(val)) {
|
if (addr <= sizeof(s->mem) - sizeof(val)) {
|
||||||
memcpy(&val, &s->mem[addr], sizeof(val));
|
val = e100_read_reg2(s, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
@ -1348,6 +1413,11 @@ static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
|
|||||||
val = eepro100_read_eeprom(s);
|
val = eepro100_read_eeprom(s);
|
||||||
TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
|
TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
|
||||||
break;
|
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:
|
default:
|
||||||
logout("addr=%s val=0x%04x\n", regname(addr), val);
|
logout("addr=%s val=0x%04x\n", regname(addr), val);
|
||||||
missing("unknown word read");
|
missing("unknown word read");
|
||||||
@ -1359,7 +1429,7 @@ static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
|
|||||||
{
|
{
|
||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
if (addr <= sizeof(s->mem) - sizeof(val)) {
|
if (addr <= sizeof(s->mem) - sizeof(val)) {
|
||||||
memcpy(&val, &s->mem[addr], sizeof(val));
|
val = e100_read_reg4(s, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (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));
|
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
|
||||||
break;
|
break;
|
||||||
case SCBPointer:
|
case SCBPointer:
|
||||||
#if 0
|
|
||||||
val = eepro100_read_pointer(s);
|
|
||||||
#endif
|
|
||||||
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
|
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
|
||||||
break;
|
break;
|
||||||
case SCBPort:
|
case SCBPort:
|
||||||
val = eepro100_read_port(s);
|
val = eepro100_read_port(s);
|
||||||
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
|
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
|
||||||
break;
|
break;
|
||||||
|
case SCBflash:
|
||||||
|
val = eepro100_read_eeprom(s);
|
||||||
|
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
|
||||||
|
break;
|
||||||
case SCBCtrlMDI:
|
case SCBCtrlMDI:
|
||||||
val = eepro100_read_mdi(s);
|
val = eepro100_read_mdi(s);
|
||||||
break;
|
break;
|
||||||
@ -1390,27 +1461,43 @@ static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
|
|||||||
{
|
{
|
||||||
/* SCBStatus is readonly. */
|
/* SCBStatus is readonly. */
|
||||||
if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
|
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) {
|
switch (addr) {
|
||||||
case SCBStatus:
|
case SCBStatus:
|
||||||
|
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
||||||
break;
|
break;
|
||||||
case SCBAck:
|
case SCBAck:
|
||||||
|
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
||||||
eepro100_acknowledge(s);
|
eepro100_acknowledge(s);
|
||||||
break;
|
break;
|
||||||
case SCBCmd:
|
case SCBCmd:
|
||||||
|
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
||||||
eepro100_write_command(s, val);
|
eepro100_write_command(s, val);
|
||||||
break;
|
break;
|
||||||
case SCBIntmask:
|
case SCBIntmask:
|
||||||
|
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
||||||
if (val & BIT(1)) {
|
if (val & BIT(1)) {
|
||||||
eepro100_swi_interrupt(s);
|
eepro100_swi_interrupt(s);
|
||||||
}
|
}
|
||||||
eepro100_interrupt(s, 0);
|
eepro100_interrupt(s, 0);
|
||||||
break;
|
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:
|
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: /* does not exist on 82557 */
|
||||||
case SCBFlow + 1:
|
case SCBFlow + 1:
|
||||||
case SCBFlow + 2:
|
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));
|
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
||||||
break;
|
break;
|
||||||
case SCBeeprom:
|
case SCBeeprom:
|
||||||
|
TRACE(OTHER, logout("addr=%s val=0x%02x\n", regname(addr), val));
|
||||||
eepro100_write_eeprom(s->eeprom, val);
|
eepro100_write_eeprom(s->eeprom, val);
|
||||||
break;
|
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:
|
default:
|
||||||
logout("addr=%s val=0x%02x\n", regname(addr), val);
|
logout("addr=%s val=0x%02x\n", regname(addr), val);
|
||||||
missing("unknown byte write");
|
missing("unknown byte write");
|
||||||
@ -1430,23 +1527,42 @@ static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
|
|||||||
{
|
{
|
||||||
/* SCBStatus is readonly. */
|
/* SCBStatus is readonly. */
|
||||||
if (addr > SCBStatus && addr <= sizeof(s->mem) - sizeof(val)) {
|
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) {
|
switch (addr) {
|
||||||
case SCBStatus:
|
case SCBStatus:
|
||||||
|
TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
|
||||||
s->mem[SCBAck] = (val >> 8);
|
s->mem[SCBAck] = (val >> 8);
|
||||||
eepro100_acknowledge(s);
|
eepro100_acknowledge(s);
|
||||||
break;
|
break;
|
||||||
case SCBCmd:
|
case SCBCmd:
|
||||||
|
TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
|
||||||
eepro100_write_command(s, val);
|
eepro100_write_command(s, val);
|
||||||
eepro100_write1(s, SCBIntmask, val >> 8);
|
eepro100_write1(s, SCBIntmask, val >> 8);
|
||||||
break;
|
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:
|
case SCBeeprom:
|
||||||
|
TRACE(OTHER, logout("addr=%s val=0x%04x\n", regname(addr), val));
|
||||||
eepro100_write_eeprom(s->eeprom, val);
|
eepro100_write_eeprom(s->eeprom, val);
|
||||||
break;
|
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:
|
default:
|
||||||
logout("addr=%s val=0x%04x\n", regname(addr), val);
|
logout("addr=%s val=0x%04x\n", regname(addr), val);
|
||||||
missing("unknown word write");
|
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)
|
static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
|
||||||
{
|
{
|
||||||
if (addr <= sizeof(s->mem) - sizeof(val)) {
|
if (addr <= sizeof(s->mem) - sizeof(val)) {
|
||||||
memcpy(&s->mem[addr], &val, sizeof(val));
|
e100_write_reg4(s, addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (addr) {
|
switch (addr) {
|
||||||
case SCBPointer:
|
case SCBPointer:
|
||||||
eepro100_write_pointer(s, val);
|
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
|
||||||
break;
|
break;
|
||||||
case SCBPort:
|
case SCBPort:
|
||||||
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
|
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;
|
break;
|
||||||
case SCBCtrlMDI:
|
case SCBCtrlMDI:
|
||||||
eepro100_write_mdi(s, val);
|
TRACE(OTHER, logout("addr=%s val=0x%08x\n", regname(addr), val));
|
||||||
|
eepro100_write_mdi(s);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logout("addr=%s val=0x%08x\n", regname(addr), val);
|
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
|
#if 0
|
||||||
logout("addr=%s\n", regname(addr));
|
logout("addr=%s\n", regname(addr));
|
||||||
#endif
|
#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)
|
static uint32_t ioport_read2(void *opaque, uint32_t addr)
|
||||||
{
|
{
|
||||||
EEPRO100State *s = opaque;
|
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)
|
static uint32_t ioport_read4(void *opaque, uint32_t addr)
|
||||||
{
|
{
|
||||||
EEPRO100State *s = opaque;
|
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)
|
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
|
#if 0
|
||||||
logout("addr=%s val=0x%02x\n", regname(addr), val);
|
logout("addr=%s val=0x%02x\n", regname(addr), val);
|
||||||
#endif
|
#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)
|
static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
|
||||||
{
|
{
|
||||||
EEPRO100State *s = opaque;
|
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)
|
static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
|
||||||
{
|
{
|
||||||
EEPRO100State *s = opaque;
|
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_write(addr, size, 4, ioport_write4, s);
|
||||||
register_ioport_read(addr, size, 4, ioport_read4, 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
|
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)
|
static int nic_can_receive(VLANClientState *nc)
|
||||||
{
|
{
|
||||||
EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
|
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;
|
EEPRO100State *s = DO_UPCAST(NICState, nc, nc)->opaque;
|
||||||
uint16_t rfd_status = 0xa000;
|
uint16_t rfd_status = 0xa000;
|
||||||
|
#if defined(CONFIG_PAD_RECEIVED_FRAMES)
|
||||||
|
uint8_t min_buf[60];
|
||||||
|
#endif
|
||||||
static const uint8_t broadcast_macaddr[6] =
|
static const uint8_t broadcast_macaddr[6] =
|
||||||
{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
{ 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) {
|
if (s->configuration[8] & 0x80) {
|
||||||
/* CSMA is disabled. */
|
/* CSMA is disabled. */
|
||||||
logout("%p received while CSMA is disabled\n", s);
|
logout("%p received while CSMA is disabled\n", s);
|
||||||
return -1;
|
return -1;
|
||||||
|
#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
|
||||||
} else if (size < 64 && (s->configuration[7] & BIT(0))) {
|
} else if (size < 64 && (s->configuration[7] & BIT(0))) {
|
||||||
/* Short frame and configuration byte 7/0 (discard short receive) set:
|
/* Short frame and configuration byte 7/0 (discard short receive) set:
|
||||||
* Short frame is discarded */
|
* Short frame is discarded */
|
||||||
logout("%p received short frame (%zu byte)\n", s, size);
|
logout("%p received short frame (%zu byte)\n", s, size);
|
||||||
s->statistics.rx_short_frame_errors++;
|
s->statistics.rx_short_frame_errors++;
|
||||||
#if 0
|
|
||||||
return -1;
|
return -1;
|
||||||
#endif
|
#endif
|
||||||
} else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & BIT(3))) {
|
} 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;
|
eepro100_rx_t rx;
|
||||||
cpu_physical_memory_read(s->ru_base + s->ru_offset, (uint8_t *) & rx,
|
cpu_physical_memory_read(s->ru_base + s->ru_offset, &rx,
|
||||||
offsetof(eepro100_rx_t, packet));
|
sizeof(eepro100_rx_t));
|
||||||
uint16_t rfd_command = le16_to_cpu(rx.command);
|
uint16_t rfd_command = le16_to_cpu(rx.command);
|
||||||
uint16_t rfd_size = le16_to_cpu(rx.size);
|
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);
|
"(%zu bytes); data truncated\n", rfd_size, size);
|
||||||
size = rfd_size;
|
size = rfd_size;
|
||||||
}
|
}
|
||||||
|
#if !defined(CONFIG_PAD_RECEIVED_FRAMES)
|
||||||
if (size < 64) {
|
if (size < 64) {
|
||||||
rfd_status |= 0x0080;
|
rfd_status |= 0x0080;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
TRACE(OTHER, logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n",
|
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));
|
rfd_command, rx.link, rx.rx_buf_addr, rfd_size));
|
||||||
stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, status),
|
e100_stw_le_phys(s->ru_base + s->ru_offset +
|
||||||
rfd_status);
|
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, count), size);
|
||||||
/* Early receive interrupt not supported. */
|
/* Early receive interrupt not supported. */
|
||||||
#if 0
|
#if 0
|
||||||
eepro100_er_interrupt(s);
|
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)));
|
assert(!(s->configuration[17] & BIT(0)));
|
||||||
#endif
|
#endif
|
||||||
cpu_physical_memory_write(s->ru_base + s->ru_offset +
|
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++;
|
s->statistics.rx_good_frames++;
|
||||||
eepro100_fr_interrupt(s);
|
eepro100_fr_interrupt(s);
|
||||||
s->ru_offset = le32_to_cpu(rx.link);
|
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. */
|
/* The eeprom should be saved and restored by its own routines. */
|
||||||
VMSTATE_UINT32(device, EEPRO100State),
|
VMSTATE_UINT32(device, EEPRO100State),
|
||||||
/* TODO check device. */
|
/* TODO check device. */
|
||||||
VMSTATE_UINT32(pointer, EEPRO100State),
|
|
||||||
VMSTATE_UINT32(cu_base, EEPRO100State),
|
VMSTATE_UINT32(cu_base, EEPRO100State),
|
||||||
VMSTATE_UINT32(cu_offset, EEPRO100State),
|
VMSTATE_UINT32(cu_offset, EEPRO100State),
|
||||||
VMSTATE_UINT32(ru_base, EEPRO100State),
|
VMSTATE_UINT32(ru_base, EEPRO100State),
|
||||||
@ -1880,19 +2001,18 @@ static int e100_nic_init(PCIDevice *pci_dev)
|
|||||||
/* Handler for memory-mapped I/O */
|
/* Handler for memory-mapped I/O */
|
||||||
s->mmio_index =
|
s->mmio_index =
|
||||||
cpu_register_io_memory(pci_mmio_read, pci_mmio_write, s,
|
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_register_bar(&s->dev, 1, PCI_IO_SIZE, PCI_BASE_ADDRESS_SPACE_IO,
|
||||||
pci_map);
|
pci_map);
|
||||||
pci_register_bar(&s->dev, 2, PCI_FLASH_SIZE, PCI_BASE_ADDRESS_SPACE_MEMORY,
|
pci_register_bar_simple(&s->dev, 2, PCI_FLASH_SIZE, 0, s->mmio_index);
|
||||||
pci_mmio_map);
|
|
||||||
|
|
||||||
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
||||||
logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
|
logout("macaddr: %s\n", nic_dump(&s->conf.macaddr.a[0], 6));
|
||||||
assert(s->region[1] == 0);
|
assert(s->region1 == 0);
|
||||||
|
|
||||||
nic_reset(s);
|
nic_reset(s);
|
||||||
|
|
||||||
|
@ -1129,15 +1129,6 @@ void ahci_uninit(AHCIState *s)
|
|||||||
qemu_free(s->dev);
|
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)
|
void ahci_reset(void *opaque)
|
||||||
{
|
{
|
||||||
struct AHCIPCIState *d = opaque;
|
struct AHCIPCIState *d = opaque;
|
||||||
|
@ -325,9 +325,6 @@ typedef struct NCQFrame {
|
|||||||
void ahci_init(AHCIState *s, DeviceState *qdev, int ports);
|
void ahci_init(AHCIState *s, DeviceState *qdev, int ports);
|
||||||
void ahci_uninit(AHCIState *s);
|
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);
|
void ahci_reset(void *opaque);
|
||||||
|
|
||||||
#endif /* HW_IDE_AHCI_H */
|
#endif /* HW_IDE_AHCI_H */
|
||||||
|
@ -94,8 +94,7 @@ static int pci_ich9_ahci_init(PCIDevice *dev)
|
|||||||
qemu_register_reset(ahci_reset, d);
|
qemu_register_reset(ahci_reset, d);
|
||||||
|
|
||||||
/* XXX BAR size should be 1k, but that breaks, so bump it to 4k for now */
|
/* 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,
|
pci_register_bar_simple(&d->card, 5, 0x1000, 0, d->ahci.mem);
|
||||||
ahci_pci_map);
|
|
||||||
|
|
||||||
msi_init(dev, 0x50, 1, true, false);
|
msi_init(dev, 0x50, 1, true, false);
|
||||||
|
|
||||||
@ -110,10 +109,7 @@ static int pci_ich9_uninit(PCIDevice *dev)
|
|||||||
struct AHCIPCIState *d;
|
struct AHCIPCIState *d;
|
||||||
d = DO_UPCAST(struct AHCIPCIState, card, dev);
|
d = DO_UPCAST(struct AHCIPCIState, card, dev);
|
||||||
|
|
||||||
if (msi_enabled(dev)) {
|
|
||||||
msi_uninit(dev);
|
msi_uninit(dev);
|
||||||
}
|
|
||||||
|
|
||||||
qemu_unregister_reset(ahci_reset, d);
|
qemu_unregister_reset(ahci_reset, d);
|
||||||
ahci_uninit(&d->ahci);
|
ahci_uninit(&d->ahci);
|
||||||
|
|
||||||
|
@ -1109,14 +1109,6 @@ static CPUWriteMemoryFunc * const intel_hda_mmio_write[3] = {
|
|||||||
intel_hda_mmio_writel,
|
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)
|
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,
|
d->mmio_addr = cpu_register_io_memory(intel_hda_mmio_read,
|
||||||
intel_hda_mmio_write, d,
|
intel_hda_mmio_write, d,
|
||||||
DEVICE_NATIVE_ENDIAN);
|
DEVICE_NATIVE_ENDIAN);
|
||||||
pci_register_bar(&d->pci, 0, 0x4000, PCI_BASE_ADDRESS_SPACE_MEMORY,
|
pci_register_bar_simple(&d->pci, 0, 0x4000, 0, d->mmio_addr);
|
||||||
intel_hda_map);
|
|
||||||
if (d->msi) {
|
if (d->msi) {
|
||||||
msi_init(&d->pci, 0x50, 1, true, false);
|
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);
|
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);
|
cpu_unregister_io_memory(d->mmio_addr);
|
||||||
return 0;
|
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);
|
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)
|
static void lsi_scsi_reset(DeviceState *dev)
|
||||||
{
|
{
|
||||||
LSIState *s = DO_UPCAST(LSIState, dev.qdev, 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_register_bar(&s->dev, 0, 256,
|
||||||
PCI_BASE_ADDRESS_SPACE_IO, lsi_io_mapfunc);
|
PCI_BASE_ADDRESS_SPACE_IO, lsi_io_mapfunc);
|
||||||
pci_register_bar(&s->dev, 1, 0x400,
|
pci_register_bar_simple(&s->dev, 1, 0x400, 0, s->mmio_io_addr);
|
||||||
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc);
|
|
||||||
pci_register_bar(&s->dev, 2, 0x2000,
|
pci_register_bar(&s->dev, 2, 0x2000,
|
||||||
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
|
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc);
|
||||||
QTAILQ_INIT(&s->queue);
|
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)
|
void msi_uninit(struct PCIDevice *dev)
|
||||||
{
|
{
|
||||||
uint16_t flags = pci_get_word(dev->config + msi_flags_off(dev));
|
uint16_t flags;
|
||||||
uint8_t cap_size = msi_cap_sizeof(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);
|
pci_del_capability(dev, PCI_CAP_ID_MSIX, cap_size);
|
||||||
|
dev->cap_present &= ~QEMU_PCI_CAP_MSI;
|
||||||
|
|
||||||
MSI_DEV_PRINTF(dev, "uninit\n");
|
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);
|
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
|
/* Update interrupt status bit in config space on interrupt
|
||||||
* state change. */
|
* state change. */
|
||||||
static void pci_update_irq_status(PCIDevice *dev)
|
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->filtered_size = size;
|
||||||
r->type = type;
|
r->type = type;
|
||||||
r->map_func = map_func;
|
r->map_func = map_func;
|
||||||
|
r->ram_addr = IO_MEM_UNASSIGNED;
|
||||||
|
|
||||||
wmask = ~(size - 1);
|
wmask = ~(size - 1);
|
||||||
addr = pci_bar(pci_dev, region_num);
|
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,
|
static void pci_bridge_filter(PCIDevice *d, pcibus_t *addr, pcibus_t *size,
|
||||||
uint8_t type)
|
uint8_t type)
|
||||||
{
|
{
|
||||||
@ -1145,6 +1169,7 @@ static const pci_class_desc pci_class_descriptions[] =
|
|||||||
{ 0x0400, "Video controller", "video"},
|
{ 0x0400, "Video controller", "video"},
|
||||||
{ 0x0401, "Audio controller", "sound"},
|
{ 0x0401, "Audio controller", "sound"},
|
||||||
{ 0x0402, "Phone"},
|
{ 0x0402, "Phone"},
|
||||||
|
{ 0x0403, "Audio controller", "sound"},
|
||||||
{ 0x0480, "Multimedia controller"},
|
{ 0x0480, "Multimedia controller"},
|
||||||
{ 0x0500, "RAM controller", "memory"},
|
{ 0x0500, "RAM controller", "memory"},
|
||||||
{ 0x0501, "Flash controller", "flash"},
|
{ 0x0501, "Flash controller", "flash"},
|
||||||
|
4
hw/pci.h
4
hw/pci.h
@ -92,6 +92,7 @@ typedef struct PCIIORegion {
|
|||||||
pcibus_t filtered_size;
|
pcibus_t filtered_size;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
PCIMapIORegionFunc *map_func;
|
PCIMapIORegionFunc *map_func;
|
||||||
|
ram_addr_t ram_addr;
|
||||||
} PCIIORegion;
|
} PCIIORegion;
|
||||||
|
|
||||||
#define PCI_ROM_SLOT 6
|
#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,
|
void pci_register_bar(PCIDevice *pci_dev, int region_num,
|
||||||
pcibus_t size, uint8_t type,
|
pcibus_t size, uint8_t type,
|
||||||
PCIMapIORegionFunc *map_func);
|
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,
|
int pci_add_capability(PCIDevice *pdev, uint8_t cap_id,
|
||||||
uint8_t offset, uint8_t size);
|
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);
|
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 pci_bus_irqs(PCIBus *bus, pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
|
||||||
void *irq_opaque, int nirq);
|
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);
|
void pci_bus_hotplug(PCIBus *bus, pci_hotplug_fn hotplug, DeviceState *dev);
|
||||||
PCIBus *pci_register_bus(DeviceState *parent, const char *name,
|
PCIBus *pci_register_bus(DeviceState *parent, const char *name,
|
||||||
pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
|
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
|
&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,
|
static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
|
||||||
uint8_t *buf, int len, int do_bswap)
|
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_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
|
||||||
PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
|
PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
|
||||||
|
|
||||||
pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE,
|
pci_register_bar_simple(pci_dev, 1, PCNET_PNPMMIO_SIZE, 0, s->mmio_index);
|
||||||
PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
|
|
||||||
|
|
||||||
s->irq = pci_dev->irq[0];
|
s->irq = pci_dev->irq[0];
|
||||||
s->phys_mem_read = pci_physical_memory_read;
|
s->phys_mem_read = pci_physical_memory_read;
|
||||||
|
131
hw/piix_pci.c
131
hw/piix_pci.c
@ -37,10 +37,31 @@
|
|||||||
|
|
||||||
typedef PCIHostState I440FXState;
|
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 {
|
typedef struct PIIX3State {
|
||||||
PCIDevice dev;
|
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;
|
qemu_irq *pic;
|
||||||
|
|
||||||
|
/* This member isn't used. Just for save/load compatibility */
|
||||||
|
int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
|
||||||
} PIIX3State;
|
} PIIX3State;
|
||||||
|
|
||||||
struct PCII440FXState {
|
struct PCII440FXState {
|
||||||
@ -55,16 +76,16 @@ struct PCII440FXState {
|
|||||||
#define I440FX_PAM_SIZE 7
|
#define I440FX_PAM_SIZE 7
|
||||||
#define I440FX_SMRAM 0x72
|
#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
|
/* return the global irq number corresponding to a given device irq
|
||||||
pin. We could also use the bus number to have a more precise
|
pin. We could also use the bus number to have a more precise
|
||||||
mapping. */
|
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;
|
int slot_addend;
|
||||||
slot_addend = (pci_dev->devfn >> 3) - 1;
|
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)
|
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);
|
i440fx_update_memory_mappings(d);
|
||||||
qemu_get_8s(f, &d->smm_enabled);
|
qemu_get_8s(f, &d->smm_enabled);
|
||||||
|
|
||||||
if (version_id == 2)
|
if (version_id == 2) {
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < PIIX_NUM_PIRQS; i++) {
|
||||||
d->piix3->pci_irq_levels[i] = qemu_get_be32(f);
|
qemu_get_be32(f); /* dummy load for compatibility */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -236,7 +259,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, qemu_irq *
|
|||||||
piix3 = DO_UPCAST(PIIX3State, dev,
|
piix3 = DO_UPCAST(PIIX3State, dev,
|
||||||
pci_create_simple_multifunction(b, -1, true, "PIIX3"));
|
pci_create_simple_multifunction(b, -1, true, "PIIX3"));
|
||||||
piix3->pic = pic;
|
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;
|
(*pi440fx_state)->piix3 = piix3;
|
||||||
|
|
||||||
*piix3_devfn = piix3->dev.devfn;
|
*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 */
|
/* PIIX3 PCI to ISA bridge */
|
||||||
|
static void piix3_set_irq_pic(PIIX3State *piix3, int pic_irq)
|
||||||
static void piix3_set_irq(void *opaque, int irq_num, int level)
|
|
||||||
{
|
{
|
||||||
int i, pic_irq, pic_level;
|
qemu_set_irq(piix3->pic[pic_irq],
|
||||||
PIIX3State *piix3 = opaque;
|
!!(piix3->pic_levels &
|
||||||
|
(((1UL << PIIX_NUM_PIRQS) - 1) <<
|
||||||
|
(pic_irq * PIIX_NUM_PIRQS))));
|
||||||
|
}
|
||||||
|
|
||||||
piix3->pci_irq_levels[irq_num] = level;
|
static void piix3_set_irq_level(PIIX3State *piix3, int pirq, int level)
|
||||||
|
{
|
||||||
|
int pic_irq;
|
||||||
|
uint64_t mask;
|
||||||
|
|
||||||
/* now we change the pic irq level according to the piix irq mappings */
|
pic_irq = piix3->dev.config[PIIX_PIRQC + pirq];
|
||||||
/* XXX: optimize */
|
if (pic_irq >= PIIX_NUM_PIC_IRQS) {
|
||||||
pic_irq = piix3->dev.config[0x60 + irq_num];
|
return;
|
||||||
if (pic_irq < 16) {
|
}
|
||||||
/* The pic level is the logical OR of all the PCI irqs mapped
|
|
||||||
to it */
|
mask = 1ULL << ((pic_irq * PIIX_NUM_PIRQS) + pirq);
|
||||||
pic_level = 0;
|
piix3->pic_levels &= ~mask;
|
||||||
for (i = 0; i < 4; i++) {
|
piix3->pic_levels |= mask * !!level;
|
||||||
if (pic_irq == piix3->dev.config[0x60 + i])
|
|
||||||
pic_level |= piix3->pci_irq_levels[i];
|
piix3_set_irq_pic(piix3, pic_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void piix3_set_irq(void *opaque, int pirq, int 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->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[0xac] = 0x00;
|
||||||
pci_conf[0xae] = 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 = {
|
static const VMStateDescription vmstate_piix3 = {
|
||||||
@ -318,9 +393,12 @@ static const VMStateDescription vmstate_piix3 = {
|
|||||||
.version_id = 3,
|
.version_id = 3,
|
||||||
.minimum_version_id = 2,
|
.minimum_version_id = 2,
|
||||||
.minimum_version_id_old = 2,
|
.minimum_version_id_old = 2,
|
||||||
|
.post_load = piix3_post_load,
|
||||||
|
.pre_save = piix3_pre_save,
|
||||||
.fields = (VMStateField []) {
|
.fields = (VMStateField []) {
|
||||||
VMSTATE_PCI_DEVICE(dev, PIIX3State),
|
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()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -359,6 +437,7 @@ static PCIDeviceInfo i440fx_info[] = {
|
|||||||
.qdev.no_user = 1,
|
.qdev.no_user = 1,
|
||||||
.no_hotplug = 1,
|
.no_hotplug = 1,
|
||||||
.init = piix3_initfn,
|
.init = piix3_initfn,
|
||||||
|
.config_write = piix3_write_config,
|
||||||
},{
|
},{
|
||||||
/* end of list */
|
/* end of list */
|
||||||
}
|
}
|
||||||
|
11
hw/rtl8139.c
11
hw/rtl8139.c
@ -3375,14 +3375,6 @@ static const VMStateDescription vmstate_rtl8139 = {
|
|||||||
/***********************************************************/
|
/***********************************************************/
|
||||||
/* PCI RTL8139 definitions */
|
/* 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,
|
static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num,
|
||||||
pcibus_t addr, pcibus_t size, int type)
|
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_register_bar(&s->dev, 0, 0x100,
|
||||||
PCI_BASE_ADDRESS_SPACE_IO, rtl8139_ioport_map);
|
PCI_BASE_ADDRESS_SPACE_IO, rtl8139_ioport_map);
|
||||||
|
|
||||||
pci_register_bar(&s->dev, 1, 0x100,
|
pci_register_bar_simple(&s->dev, 1, 0x100, 0, s->rtl8139_mmio_io_addr);
|
||||||
PCI_BASE_ADDRESS_SPACE_MEMORY, rtl8139_mmio_map);
|
|
||||||
|
|
||||||
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
qemu_macaddr_default_if_unset(&s->conf.macaddr);
|
||||||
|
|
||||||
|
@ -1708,13 +1708,6 @@ typedef struct {
|
|||||||
OHCIState state;
|
OHCIState state;
|
||||||
} OHCIPCIState;
|
} 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)
|
static int usb_ohci_initfn_pci(struct PCIDevice *dev)
|
||||||
{
|
{
|
||||||
OHCIPCIState *ohci = DO_UPCAST(OHCIPCIState, pci_dev, 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];
|
ohci->state.irq = ohci->pci_dev.irq[0];
|
||||||
|
|
||||||
/* TODO: avoid cast below by using dev */
|
/* TODO: avoid cast below by using dev */
|
||||||
pci_register_bar(&ohci->pci_dev, 0, 256,
|
pci_register_bar_simple(&ohci->pci_dev, 0, 256, 0, ohci->state.mem);
|
||||||
PCI_BASE_ADDRESS_SPACE_MEMORY, ohci_mapfunc);
|
|
||||||
return 0;
|
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;
|
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,
|
static void vhost_client_set_memory(CPUPhysMemoryClient *client,
|
||||||
target_phys_addr_t start_addr,
|
target_phys_addr_t start_addr,
|
||||||
ram_addr_t size,
|
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);
|
struct vhost_dev *dev = container_of(client, struct vhost_dev, client);
|
||||||
ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
|
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];
|
(dev->mem->nregions + 1) * sizeof dev->mem->regions[0];
|
||||||
uint64_t log_size;
|
uint64_t log_size;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
dev->mem = qemu_realloc(dev->mem, s);
|
dev->mem = qemu_realloc(dev->mem, s);
|
||||||
|
|
||||||
|
if (log_dirty) {
|
||||||
|
flags = IO_MEM_UNASSIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
assert(size);
|
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);
|
vhost_dev_unassign_memory(dev, start_addr, size);
|
||||||
if (flags == IO_MEM_RAM) {
|
if (flags == IO_MEM_RAM) {
|
||||||
/* Add given mapping, merging adjacent regions if any */
|
/* 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 = {
|
static const VMStateDescription vmstate_i6300esb = {
|
||||||
.name = "i6300esb_wdt",
|
.name = "i6300esb_wdt",
|
||||||
.version_id = sizeof(I6300State),
|
.version_id = sizeof(I6300State),
|
||||||
@ -407,6 +382,17 @@ static int i6300esb_init(PCIDevice *dev)
|
|||||||
{
|
{
|
||||||
I6300State *d = DO_UPCAST(I6300State, dev, dev);
|
I6300State *d = DO_UPCAST(I6300State, dev, dev);
|
||||||
uint8_t *pci_conf;
|
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);
|
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_device_id(pci_conf, PCI_DEVICE_ID_INTEL_ESB_9);
|
||||||
pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER);
|
pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER);
|
||||||
|
|
||||||
pci_register_bar(&d->dev, 0, 0x10,
|
io_mem = cpu_register_io_memory(mem_read, mem_write, d,
|
||||||
PCI_BASE_ADDRESS_SPACE_MEMORY, i6300esb_map);
|
DEVICE_NATIVE_ENDIAN);
|
||||||
|
pci_register_bar_simple(&d->dev, 0, 0x10, 0, io_mem);
|
||||||
|
/* qemu_register_coalesced_mmio (addr, 0x10); ? */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
60
kvm-all.c
60
kvm-all.c
@ -245,29 +245,28 @@ err:
|
|||||||
/*
|
/*
|
||||||
* dirty pages logging control
|
* 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;
|
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;
|
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;
|
old_flags = mem->flags;
|
||||||
|
|
||||||
flags = (mem->flags & ~mask) | flags;
|
flags = (mem->flags & ~mask) | kvm_mem_flags(s, log_dirty);
|
||||||
mem->flags = flags;
|
mem->flags = flags;
|
||||||
|
|
||||||
/* If nothing changed effectively, no need to issue ioctl */
|
/* If nothing changed effectively, no need to issue ioctl */
|
||||||
if (s->migration_log) {
|
if (s->migration_log) {
|
||||||
flags |= KVM_MEM_LOG_DIRTY_PAGES;
|
flags |= KVM_MEM_LOG_DIRTY_PAGES;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags == old_flags) {
|
if (flags == old_flags) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -275,18 +274,31 @@ static int kvm_dirty_pages_log_change(target_phys_addr_t phys_addr,
|
|||||||
return kvm_set_user_memory_region(s, mem);
|
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,
|
static int kvm_log_start(CPUPhysMemoryClient *client,
|
||||||
target_phys_addr_t phys_addr, ram_addr_t size)
|
target_phys_addr_t phys_addr, ram_addr_t size)
|
||||||
{
|
{
|
||||||
return kvm_dirty_pages_log_change(phys_addr, size, KVM_MEM_LOG_DIRTY_PAGES,
|
return kvm_dirty_pages_log_change(phys_addr, size, true);
|
||||||
KVM_MEM_LOG_DIRTY_PAGES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvm_log_stop(CPUPhysMemoryClient *client,
|
static int kvm_log_stop(CPUPhysMemoryClient *client,
|
||||||
target_phys_addr_t phys_addr, ram_addr_t size)
|
target_phys_addr_t phys_addr, ram_addr_t size)
|
||||||
{
|
{
|
||||||
return kvm_dirty_pages_log_change(phys_addr, size, 0,
|
return kvm_dirty_pages_log_change(phys_addr, size, false);
|
||||||
KVM_MEM_LOG_DIRTY_PAGES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int kvm_set_migration_log(int enable)
|
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,
|
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;
|
KVMState *s = kvm_state;
|
||||||
ram_addr_t flags = phys_offset & ~TARGET_PAGE_MASK;
|
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) &&
|
(start_addr + size <= mem->start_addr + mem->memory_size) &&
|
||||||
(phys_offset - start_addr == mem->phys_offset - mem->start_addr)) {
|
(phys_offset - start_addr == mem->phys_offset - mem->start_addr)) {
|
||||||
/* The new slot fits into the existing one and comes with
|
/* 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;
|
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->memory_size = old.memory_size;
|
||||||
mem->start_addr = old.start_addr;
|
mem->start_addr = old.start_addr;
|
||||||
mem->phys_offset = old.phys_offset;
|
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);
|
err = kvm_set_user_memory_region(s, mem);
|
||||||
if (err) {
|
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->memory_size = start_addr - old.start_addr;
|
||||||
mem->start_addr = old.start_addr;
|
mem->start_addr = old.start_addr;
|
||||||
mem->phys_offset = old.phys_offset;
|
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);
|
err = kvm_set_user_memory_region(s, mem);
|
||||||
if (err) {
|
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;
|
size_delta = mem->start_addr - old.start_addr;
|
||||||
mem->memory_size = old.memory_size - size_delta;
|
mem->memory_size = old.memory_size - size_delta;
|
||||||
mem->phys_offset = old.phys_offset + 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);
|
err = kvm_set_user_memory_region(s, mem);
|
||||||
if (err) {
|
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->memory_size = size;
|
||||||
mem->start_addr = start_addr;
|
mem->start_addr = start_addr;
|
||||||
mem->phys_offset = phys_offset;
|
mem->phys_offset = phys_offset;
|
||||||
mem->flags = 0;
|
mem->flags = kvm_mem_flags(s, log_dirty);
|
||||||
|
|
||||||
err = kvm_set_user_memory_region(s, mem);
|
err = kvm_set_user_memory_region(s, mem);
|
||||||
if (err) {
|
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,
|
static void kvm_client_set_memory(struct CPUPhysMemoryClient *client,
|
||||||
target_phys_addr_t start_addr,
|
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,
|
static int kvm_client_sync_dirty_bitmap(struct CPUPhysMemoryClient *client,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user