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