diff options
Diffstat (limited to 'hw/usb')
-rw-r--r-- | hw/usb/hcd-ehci.c | 173 |
1 files changed, 84 insertions, 89 deletions
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 2f3e9c03a1..f5ba8e1469 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -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]; }; }; + 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; - 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; @@ -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); - - /* 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); @@ -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; |