Skip to content

Commit

Permalink
ehci: switch to new-style memory ops
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
kraxel committed Sep 12, 2012
1 parent 63587e3 commit 3e4f910
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 92 deletions.
173 changes: 84 additions & 89 deletions hw/usb/hcd-ehci.c
Expand Up @@ -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 */
Expand All @@ -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;
Expand All @@ -411,9 +414,9 @@ struct EHCIState {
uint32_t asynclistaddr;
uint32_t notused[9];
uint32_t configflag;
uint32_t portsc[NB_PORTS];
};
};
uint32_t portsc[NB_PORTS];

/*
* Internal states, shadow registers, etc
Expand Down Expand Up @@ -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",
};

Expand All @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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;
uint32_t val;

val = s->mmio[addr];

return val;
return s->caps[addr];
}

static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t 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] | (s->mmio[addr+1] << 8);

val = s->opreg[addr >> 2];
trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val);
return val;
}

static uint32_t ehci_mem_readl(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) |
(s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24);

trace_usb_ehci_mmio_readl(addr, addr2str(addr), val);
val = s->portsc[addr >> 2];
trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, 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;
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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);

/* 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;
}

trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val);

/* Do any register specific pre-write processing here. */
switch(addr) {
switch (addr + OPREGBASE) {
case USBCMD:
if (val & USBCMD_HCRESET) {
ehci_reset(s);
Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
}


Expand Down Expand Up @@ -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,
};

Expand Down Expand Up @@ -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];

Expand All @@ -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;
Expand Down
9 changes: 6 additions & 3 deletions trace-events
Expand Up @@ -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"
Expand Down

0 comments on commit 3e4f910

Please sign in to comment.