Blame 0158-ehci-switch-to-new-style-memory-ops.patch

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