mirror of
https://github.com/qemu/qemu.git
synced 2024-11-25 11:53:39 +08:00
ehci: switch to new-style memory ops
Also register different memory regions for capabilities, operational registers and port status registers. Create separate tracepoints for operational regs and port status regs. Ditch a bunch of sanity checks because the memory core will do this for us now. Offloading the byte, word and dword access handling to the memory core also has the side effect of fixing ehci register access on bigendian hosts. Cc: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
63587e3135
commit
3e4f910c8d
@ -389,6 +389,9 @@ struct EHCIState {
|
||||
USBBus bus;
|
||||
qemu_irq irq;
|
||||
MemoryRegion mem;
|
||||
MemoryRegion mem_caps;
|
||||
MemoryRegion mem_opreg;
|
||||
MemoryRegion mem_ports;
|
||||
int companion_count;
|
||||
|
||||
/* properties */
|
||||
@ -398,10 +401,10 @@ struct EHCIState {
|
||||
* EHCI spec version 1.0 Section 2.3
|
||||
* Host Controller Operational Registers
|
||||
*/
|
||||
uint8_t caps[OPREGBASE];
|
||||
union {
|
||||
uint8_t mmio[MMIO_SIZE];
|
||||
uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)];
|
||||
struct {
|
||||
uint8_t cap[OPREGBASE];
|
||||
uint32_t usbcmd;
|
||||
uint32_t usbsts;
|
||||
uint32_t usbintr;
|
||||
@ -411,9 +414,9 @@ struct EHCIState {
|
||||
uint32_t asynclistaddr;
|
||||
uint32_t notused[9];
|
||||
uint32_t configflag;
|
||||
};
|
||||
};
|
||||
uint32_t portsc[NB_PORTS];
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* Internal states, shadow registers, etc
|
||||
@ -471,22 +474,12 @@ static const char *ehci_state_names[] = {
|
||||
};
|
||||
|
||||
static const char *ehci_mmio_names[] = {
|
||||
[CAPLENGTH] = "CAPLENGTH",
|
||||
[HCIVERSION] = "HCIVERSION",
|
||||
[HCSPARAMS] = "HCSPARAMS",
|
||||
[HCCPARAMS] = "HCCPARAMS",
|
||||
[USBCMD] = "USBCMD",
|
||||
[USBSTS] = "USBSTS",
|
||||
[USBINTR] = "USBINTR",
|
||||
[FRINDEX] = "FRINDEX",
|
||||
[PERIODICLISTBASE] = "P-LIST BASE",
|
||||
[ASYNCLISTADDR] = "A-LIST ADDR",
|
||||
[PORTSC_BEGIN] = "PORTSC #0",
|
||||
[PORTSC_BEGIN + 4] = "PORTSC #1",
|
||||
[PORTSC_BEGIN + 8] = "PORTSC #2",
|
||||
[PORTSC_BEGIN + 12] = "PORTSC #3",
|
||||
[PORTSC_BEGIN + 16] = "PORTSC #4",
|
||||
[PORTSC_BEGIN + 20] = "PORTSC #5",
|
||||
[CONFIGFLAG] = "CONFIGFLAG",
|
||||
};
|
||||
|
||||
@ -509,7 +502,8 @@ static const char *state2str(uint32_t state)
|
||||
|
||||
static const char *addr2str(target_phys_addr_t addr)
|
||||
{
|
||||
return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
|
||||
return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names),
|
||||
addr + OPREGBASE);
|
||||
}
|
||||
|
||||
static void ehci_trace_usbsts(uint32_t mask, int state)
|
||||
@ -1018,7 +1012,7 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[],
|
||||
}
|
||||
|
||||
s->companion_count++;
|
||||
s->mmio[0x05] = (s->companion_count << 4) | portcount;
|
||||
s->caps[0x05] = (s->companion_count << 4) | portcount;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1063,7 +1057,8 @@ static void ehci_reset(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE);
|
||||
memset(&s->opreg, 0x00, sizeof(s->opreg));
|
||||
memset(&s->portsc, 0x00, sizeof(s->portsc));
|
||||
|
||||
s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH;
|
||||
s->usbsts = USBSTS_HALT;
|
||||
@ -1090,50 +1085,35 @@ static void ehci_reset(void *opaque)
|
||||
qemu_bh_cancel(s->async_bh);
|
||||
}
|
||||
|
||||
static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr)
|
||||
static uint64_t ehci_caps_read(void *ptr, target_phys_addr_t addr,
|
||||
unsigned size)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
return s->caps[addr];
|
||||
}
|
||||
|
||||
static uint64_t ehci_opreg_read(void *ptr, target_phys_addr_t addr,
|
||||
unsigned size)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
uint32_t val;
|
||||
|
||||
val = s->mmio[addr];
|
||||
|
||||
val = s->opreg[addr >> 2];
|
||||
trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr)
|
||||
static uint64_t ehci_port_read(void *ptr, target_phys_addr_t addr,
|
||||
unsigned size)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
uint32_t val;
|
||||
|
||||
val = s->mmio[addr] | (s->mmio[addr+1] << 8);
|
||||
|
||||
val = s->portsc[addr >> 2];
|
||||
trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
uint32_t val;
|
||||
|
||||
val = s->mmio[addr] | (s->mmio[addr+1] << 8) |
|
||||
(s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24);
|
||||
|
||||
trace_usb_ehci_mmio_readl(addr, addr2str(addr), val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
|
||||
{
|
||||
USBDevice *dev = s->ports[port].dev;
|
||||
@ -1162,11 +1142,17 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner)
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
|
||||
static void ehci_port_write(void *ptr, target_phys_addr_t addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
int port = addr >> 2;
|
||||
uint32_t *portsc = &s->portsc[port];
|
||||
uint32_t old = *portsc;
|
||||
USBDevice *dev = s->ports[port].dev;
|
||||
|
||||
trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val);
|
||||
|
||||
/* Clear rwc bits */
|
||||
*portsc &= ~(val & PORTSC_RWC_MASK);
|
||||
/* The guest may clear, but not set the PED bit */
|
||||
@ -1198,39 +1184,20 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val)
|
||||
|
||||
*portsc &= ~PORTSC_RO_MASK;
|
||||
*portsc |= val;
|
||||
trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old);
|
||||
}
|
||||
|
||||
static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
static void ehci_opreg_write(void *ptr, target_phys_addr_t addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
EHCIState *s = ptr;
|
||||
uint32_t *mmio = (uint32_t *)(&s->mmio[addr]);
|
||||
uint32_t *mmio = s->opreg + (addr >> 2);
|
||||
uint32_t old = *mmio;
|
||||
int i;
|
||||
|
||||
trace_usb_ehci_mmio_writel(addr, addr2str(addr), val);
|
||||
trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val);
|
||||
|
||||
/* Only aligned reads are allowed on OHCI */
|
||||
if (addr & 3) {
|
||||
fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x"
|
||||
TARGET_FMT_plx "\n", addr);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) {
|
||||
handle_port_status_write(s, (addr-PORTSC)/4, val);
|
||||
trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
|
||||
return;
|
||||
}
|
||||
|
||||
if (addr < OPREGBASE) {
|
||||
fprintf(stderr, "usb-ehci: write attempt to read-only register"
|
||||
TARGET_FMT_plx "\n", addr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Do any register specific pre-write processing here. */
|
||||
switch(addr) {
|
||||
switch (addr + OPREGBASE) {
|
||||
case USBCMD:
|
||||
if (val & USBCMD_HCRESET) {
|
||||
ehci_reset(s);
|
||||
@ -1241,7 +1208,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
/* not supporting dynamic frame list size at the moment */
|
||||
if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) {
|
||||
fprintf(stderr, "attempt to set frame list size -- value %d\n",
|
||||
val & USBCMD_FLS);
|
||||
(int)val & USBCMD_FLS);
|
||||
val &= ~USBCMD_FLS;
|
||||
}
|
||||
|
||||
@ -1308,7 +1275,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
}
|
||||
|
||||
*mmio = val;
|
||||
trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old);
|
||||
trace_usb_ehci_opreg_change(addr + OPREGBASE, addr2str(addr), *mmio, old);
|
||||
}
|
||||
|
||||
|
||||
@ -2520,11 +2487,28 @@ static void ehci_async_bh(void *opaque)
|
||||
ehci_advance_async_state(ehci);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps ehci_mem_ops = {
|
||||
.old_mmio = {
|
||||
.read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl },
|
||||
.write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel },
|
||||
},
|
||||
static const MemoryRegionOps ehci_mmio_caps_ops = {
|
||||
.read = ehci_caps_read,
|
||||
.valid.min_access_size = 1,
|
||||
.valid.max_access_size = 4,
|
||||
.impl.min_access_size = 1,
|
||||
.impl.max_access_size = 1,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static const MemoryRegionOps ehci_mmio_opreg_ops = {
|
||||
.read = ehci_opreg_read,
|
||||
.write = ehci_opreg_write,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
static const MemoryRegionOps ehci_mmio_port_ops = {
|
||||
.read = ehci_port_read,
|
||||
.write = ehci_port_write,
|
||||
.valid.min_access_size = 4,
|
||||
.valid.max_access_size = 4,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
};
|
||||
|
||||
@ -2681,19 +2665,19 @@ static int usb_ehci_initfn(PCIDevice *dev)
|
||||
pci_conf[0x6e] = 0x00;
|
||||
pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS
|
||||
|
||||
// 2.2 host controller interface version
|
||||
s->mmio[0x00] = (uint8_t) OPREGBASE;
|
||||
s->mmio[0x01] = 0x00;
|
||||
s->mmio[0x02] = 0x00;
|
||||
s->mmio[0x03] = 0x01; // HC version
|
||||
s->mmio[0x04] = NB_PORTS; // Number of downstream ports
|
||||
s->mmio[0x05] = 0x00; // No companion ports at present
|
||||
s->mmio[0x06] = 0x00;
|
||||
s->mmio[0x07] = 0x00;
|
||||
s->mmio[0x08] = 0x80; // We can cache whole frame, not 64-bit capable
|
||||
s->mmio[0x09] = 0x68; // EECP
|
||||
s->mmio[0x0a] = 0x00;
|
||||
s->mmio[0x0b] = 0x00;
|
||||
/* 2.2 host controller interface version */
|
||||
s->caps[0x00] = (uint8_t) OPREGBASE;
|
||||
s->caps[0x01] = 0x00;
|
||||
s->caps[0x02] = 0x00;
|
||||
s->caps[0x03] = 0x01; /* HC version */
|
||||
s->caps[0x04] = NB_PORTS; /* Number of downstream ports */
|
||||
s->caps[0x05] = 0x00; /* No companion ports at present */
|
||||
s->caps[0x06] = 0x00;
|
||||
s->caps[0x07] = 0x00;
|
||||
s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */
|
||||
s->caps[0x09] = 0x68; /* EECP */
|
||||
s->caps[0x0a] = 0x00;
|
||||
s->caps[0x0b] = 0x00;
|
||||
|
||||
s->irq = s->dev.irq[3];
|
||||
|
||||
@ -2712,7 +2696,18 @@ static int usb_ehci_initfn(PCIDevice *dev)
|
||||
|
||||
qemu_register_reset(ehci_reset, s);
|
||||
|
||||
memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE);
|
||||
memory_region_init(&s->mem, "ehci", MMIO_SIZE);
|
||||
memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s,
|
||||
"capabilities", OPREGBASE);
|
||||
memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s,
|
||||
"operational", PORTSC_BEGIN - OPREGBASE);
|
||||
memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s,
|
||||
"ports", PORTSC_END - PORTSC_BEGIN);
|
||||
|
||||
memory_region_add_subregion(&s->mem, 0, &s->mem_caps);
|
||||
memory_region_add_subregion(&s->mem, OPREGBASE, &s->mem_opreg);
|
||||
memory_region_add_subregion(&s->mem, PORTSC_BEGIN, &s->mem_ports);
|
||||
|
||||
pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
|
||||
|
||||
return 0;
|
||||
|
@ -243,9 +243,12 @@ usb_port_release(int bus, const char *port) "bus %d, port %s"
|
||||
|
||||
# hw/usb/hcd-ehci.c
|
||||
usb_ehci_reset(void) "=== RESET ==="
|
||||
usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
|
||||
usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x"
|
||||
usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)"
|
||||
usb_ehci_opreg_read(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x"
|
||||
usb_ehci_opreg_write(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x"
|
||||
usb_ehci_opreg_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)"
|
||||
usb_ehci_portsc_read(uint32_t addr, uint32_t port, uint32_t val) "rd mmio %04x [port %d] = %x"
|
||||
usb_ehci_portsc_write(uint32_t addr, uint32_t port, uint32_t val) "wr mmio %04x [port %d] = %x"
|
||||
usb_ehci_portsc_change(uint32_t addr, uint32_t port, uint32_t new, uint32_t old) "ch mmio %04x [port %d] = %x (old: %x)"
|
||||
usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d"
|
||||
usb_ehci_state(const char *schedule, const char *state) "%s schedule %s"
|
||||
usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x"
|
||||
|
Loading…
Reference in New Issue
Block a user