* [Qemu-devel] [RfC PATCH 1/5] usb/ehci: parameterise the register region offsets
2012-10-30 11:28 [Qemu-devel] [RfC PATCH 0/5] ehci pci splitup Gerd Hoffmann
@ 2012-10-30 11:28 ` Gerd Hoffmann
2012-10-30 12:41 ` Andreas Färber
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 2/5] usb/ehci: Abstract away PCI DMA API Gerd Hoffmann
` (4 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 11:28 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.crosthwaite, Gerd Hoffmann
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
The capabilities register and operational register offsets can vary from one
EHCI implementation to the next. Parameterise accordingly.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/hcd-ehci.c | 68 ++++++++++++++++++++++++++++-------------------------
1 files changed, 36 insertions(+), 32 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index f14f9d7..7f04322 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -48,20 +48,18 @@
#define USB_RET_PROCERR (-99)
#define MMIO_SIZE 0x1000
+#define CAPA_SIZE 0x10
/* Capability Registers Base Address - section 2.2 */
-#define CAPREGBASE 0x0000
-#define CAPLENGTH CAPREGBASE + 0x0000 // 1-byte, 0x0001 reserved
-#define HCIVERSION CAPREGBASE + 0x0002 // 2-bytes, i/f version #
-#define HCSPARAMS CAPREGBASE + 0x0004 // 4-bytes, structural params
-#define HCCPARAMS CAPREGBASE + 0x0008 // 4-bytes, capability params
+#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
+#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
+#define HCSPARAMS 0x0004 /* 4-bytes, structural params */
+#define HCCPARAMS 0x0008 /* 4-bytes, capability params */
#define EECP HCCPARAMS + 1
-#define HCSPPORTROUTE1 CAPREGBASE + 0x000c
-#define HCSPPORTROUTE2 CAPREGBASE + 0x0010
+#define HCSPPORTROUTE1 0x000c
+#define HCSPPORTROUTE2 0x0010
-#define OPREGBASE 0x0020 // Operational Registers Base Address
-
-#define USBCMD OPREGBASE + 0x0000
+#define USBCMD 0x0000
#define USBCMD_RUNSTOP (1 << 0) // run / Stop
#define USBCMD_HCRESET (1 << 1) // HC Reset
#define USBCMD_FLS (3 << 2) // Frame List Size
@@ -75,7 +73,7 @@
#define USBCMD_ITC (0x7f << 16) // Int Threshold Control
#define USBCMD_ITC_SH 16 // Int Threshold Control Shift
-#define USBSTS OPREGBASE + 0x0004
+#define USBSTS 0x0004
#define USBSTS_RO_MASK 0x0000003f
#define USBSTS_INT (1 << 0) // USB Interrupt
#define USBSTS_ERRINT (1 << 1) // Error Interrupt
@@ -92,18 +90,18 @@
* Interrupt enable bits correspond to the interrupt active bits in USBSTS
* so no need to redefine here.
*/
-#define USBINTR OPREGBASE + 0x0008
+#define USBINTR 0x0008
#define USBINTR_MASK 0x0000003f
-#define FRINDEX OPREGBASE + 0x000c
-#define CTRLDSSEGMENT OPREGBASE + 0x0010
-#define PERIODICLISTBASE OPREGBASE + 0x0014
-#define ASYNCLISTADDR OPREGBASE + 0x0018
+#define FRINDEX 0x000c
+#define CTRLDSSEGMENT 0x0010
+#define PERIODICLISTBASE 0x0014
+#define ASYNCLISTADDR 0x0018
#define ASYNCLISTADDR_MASK 0xffffffe0
-#define CONFIGFLAG OPREGBASE + 0x0040
+#define CONFIGFLAG 0x0040
-#define PORTSC (OPREGBASE + 0x0044)
+#define PORTSC 0x0044
#define PORTSC_BEGIN PORTSC
#define PORTSC_END (PORTSC + 4 * NB_PORTS)
/*
@@ -395,6 +393,8 @@ struct EHCIState {
MemoryRegion mem_opreg;
MemoryRegion mem_ports;
int companion_count;
+ uint16_t capsbase;
+ uint16_t opregbase;
/* properties */
uint32_t maxframes;
@@ -403,9 +403,9 @@ struct EHCIState {
* EHCI spec version 1.0 Section 2.3
* Host Controller Operational Registers
*/
- uint8_t caps[OPREGBASE];
+ uint8_t caps[CAPA_SIZE];
union {
- uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)];
+ uint32_t opreg[PORTSC_BEGIN/sizeof(uint32_t)];
struct {
uint32_t usbcmd;
uint32_t usbsts;
@@ -506,8 +506,7 @@ static const char *state2str(uint32_t state)
static const char *addr2str(hwaddr addr)
{
- return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names),
- addr + OPREGBASE);
+ return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr);
}
static void ehci_trace_usbsts(uint32_t mask, int state)
@@ -1115,7 +1114,7 @@ static uint64_t ehci_opreg_read(void *ptr, hwaddr addr,
uint32_t val;
val = s->opreg[addr >> 2];
- trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val);
+ trace_usb_ehci_opreg_read(addr + s->opregbase, addr2str(addr), val);
return val;
}
@@ -1211,9 +1210,9 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
uint32_t old = *mmio;
int i;
- trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val);
+ trace_usb_ehci_opreg_write(addr + s->opregbase, addr2str(addr), val);
- switch (addr + OPREGBASE) {
+ switch (addr) {
case USBCMD:
if (val & USBCMD_HCRESET) {
ehci_reset(s);
@@ -1291,7 +1290,8 @@ static void ehci_opreg_write(void *ptr, hwaddr addr,
}
*mmio = val;
- trace_usb_ehci_opreg_change(addr + OPREGBASE, addr2str(addr), *mmio, old);
+ trace_usb_ehci_opreg_change(addr + s->opregbase, addr2str(addr),
+ *mmio, old);
}
@@ -2731,8 +2731,11 @@ static int usb_ehci_initfn(PCIDevice *dev)
pci_conf[0x6e] = 0x00;
pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS
+ s->capsbase = 0x00;
+ s->opregbase = 0x20;
+
/* 2.2 host controller interface version */
- s->caps[0x00] = (uint8_t) OPREGBASE;
+ s->caps[0x00] = (uint8_t)(s->opregbase - s->capsbase);
s->caps[0x01] = 0x00;
s->caps[0x02] = 0x00;
s->caps[0x03] = 0x01; /* HC version */
@@ -2765,15 +2768,16 @@ static int usb_ehci_initfn(PCIDevice *dev)
memory_region_init(&s->mem, "ehci", MMIO_SIZE);
memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s,
- "capabilities", OPREGBASE);
+ "capabilities", CAPA_SIZE);
memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s,
- "operational", PORTSC_BEGIN - OPREGBASE);
+ "operational", PORTSC_BEGIN);
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);
+ memory_region_add_subregion(&s->mem, s->capsbase, &s->mem_caps);
+ memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg);
+ memory_region_add_subregion(&s->mem, s->opregbase + PORTSC_BEGIN,
+ &s->mem_ports);
pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RfC PATCH 1/5] usb/ehci: parameterise the register region offsets
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 1/5] usb/ehci: parameterise the register region offsets Gerd Hoffmann
@ 2012-10-30 12:41 ` Andreas Färber
0 siblings, 0 replies; 12+ messages in thread
From: Andreas Färber @ 2012-10-30 12:41 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: peter.crosthwaite, qemu-devel
Am 30.10.2012 12:28, schrieb Gerd Hoffmann:
> From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
>
> The capabilities register and operational register offsets can vary from one
> EHCI implementation to the next. Parameterise accordingly.
>
> Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Andreas Färber <afaerber@suse.de>
Andreas
--
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [RfC PATCH 2/5] usb/ehci: Abstract away PCI DMA API
2012-10-30 11:28 [Qemu-devel] [RfC PATCH 0/5] ehci pci splitup Gerd Hoffmann
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 1/5] usb/ehci: parameterise the register region offsets Gerd Hoffmann
@ 2012-10-30 11:28 ` Gerd Hoffmann
2012-10-30 12:42 ` Andreas Färber
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 3/5] usb/ehci: seperate out PCIisms Gerd Hoffmann
` (3 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 11:28 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.crosthwaite, Gerd Hoffmann
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Pull the DMAContext for the PCI DMA out at device init time and put it into
the device state. Use dma_memory_read/write() instead of pci specific versions.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/hcd-ehci.c | 13 ++++++++-----
1 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 7f04322..28890b5 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -389,6 +389,7 @@ struct EHCIState {
USBBus bus;
qemu_irq irq;
MemoryRegion mem;
+ DMAContext *dma;
MemoryRegion mem_caps;
MemoryRegion mem_opreg;
MemoryRegion mem_ports;
@@ -1304,7 +1305,7 @@ static inline int get_dwords(EHCIState *ehci, uint32_t addr,
int i;
for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- pci_dma_read(&ehci->dev, addr, buf, sizeof(*buf));
+ dma_memory_read(ehci->dma, addr, buf, sizeof(*buf));
*buf = le32_to_cpu(*buf);
}
@@ -1319,7 +1320,7 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr,
for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint32_t tmp = cpu_to_le32(*buf);
- pci_dma_write(&ehci->dev, addr, &tmp, sizeof(tmp));
+ dma_memory_write(ehci->dma, addr, &tmp, sizeof(tmp));
}
return 1;
@@ -1402,7 +1403,7 @@ static int ehci_init_transfer(EHCIPacket *p)
cpage = get_field(p->qtd.token, QTD_TOKEN_CPAGE);
bytes = get_field(p->qtd.token, QTD_TOKEN_TBYTES);
offset = p->qtd.bufptr[0] & ~QTD_BUFPTR_MASK;
- pci_dma_sglist_init(&p->sgl, &p->queue->ehci->dev, 5);
+ qemu_sglist_init(&p->sgl, 5, p->queue->ehci->dma);
while (bytes > 0) {
if (cpage > 4) {
@@ -1647,7 +1648,7 @@ static int ehci_process_itd(EHCIState *ehci,
return USB_RET_PROCERR;
}
- pci_dma_sglist_init(&ehci->isgl, &ehci->dev, 2);
+ qemu_sglist_init(&ehci->isgl, 2, ehci->dma);
if (off + len > 4096) {
/* transfer crosses page border */
uint32_t len2 = off + len - 4096;
@@ -2402,7 +2403,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
}
list |= ((ehci->frindex & 0x1ff8) >> 1);
- pci_dma_read(&ehci->dev, list, &entry, sizeof entry);
+ dma_memory_read(ehci->dma, list, &entry, sizeof entry);
entry = le32_to_cpu(entry);
DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
@@ -2750,6 +2751,8 @@ static int usb_ehci_initfn(PCIDevice *dev)
s->irq = s->dev.irq[3];
+ s->dma = pci_dma_context(dev);
+
usb_bus_new(&s->bus, &ehci_bus_ops, &s->dev.qdev);
for(i = 0; i < NB_PORTS; i++) {
usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RfC PATCH 2/5] usb/ehci: Abstract away PCI DMA API
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 2/5] usb/ehci: Abstract away PCI DMA API Gerd Hoffmann
@ 2012-10-30 12:42 ` Andreas Färber
0 siblings, 0 replies; 12+ messages in thread
From: Andreas Färber @ 2012-10-30 12:42 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: peter.crosthwaite, qemu-devel
Am 30.10.2012 12:28, schrieb Gerd Hoffmann:
> From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
>
> Pull the DMAContext for the PCI DMA out at device init time and put it into
> the device state. Use dma_memory_read/write() instead of pci specific versions.
>
> Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Reviewed-by: Andreas Färber <afaerber@suse.de>
Andreas
--
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [RfC PATCH 3/5] usb/ehci: seperate out PCIisms
2012-10-30 11:28 [Qemu-devel] [RfC PATCH 0/5] ehci pci splitup Gerd Hoffmann
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 1/5] usb/ehci: parameterise the register region offsets Gerd Hoffmann
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 2/5] usb/ehci: Abstract away PCI DMA API Gerd Hoffmann
@ 2012-10-30 11:28 ` Gerd Hoffmann
2012-10-31 16:05 ` Andreas Färber
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 4/5] usb/ehci: Guard definition of EHCI_DEBUG Gerd Hoffmann
` (2 subsequent siblings)
5 siblings, 1 reply; 12+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 11:28 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.crosthwaite, Gerd Hoffmann
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Seperate the PCI stuff from the EHCI components. Extracted the PCIDevice
out into a new wrapper struct to make EHCIState non-PCI-specific. Seperated
tho non PCI init component out into a seperate "common" init function.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/hcd-ehci.c | 124 +++++++++++++++++++++++++++++++----------------------
1 files changed, 72 insertions(+), 52 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 28890b5..59580fc 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -385,7 +385,6 @@ struct EHCIQueue {
typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
struct EHCIState {
- PCIDevice dev;
USBBus bus;
qemu_irq irq;
MemoryRegion mem;
@@ -447,6 +446,11 @@ struct EHCIState {
bool int_req_by_async;
};
+typedef struct EHCIPCIState {
+ PCIDevice pcidev;
+ EHCIState ehci;
+} EHCIPCIState;
+
#define SET_LAST_RUN_CLOCK(s) \
(s)->last_run_ns = qemu_get_clock_ns(vm_clock);
@@ -2553,7 +2557,7 @@ static const MemoryRegionOps ehci_mmio_port_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static int usb_ehci_initfn(PCIDevice *dev);
+static int usb_ehci_pci_initfn(PCIDevice *dev);
static USBPortOps ehci_port_ops = {
.attach = ehci_attach,
@@ -2614,12 +2618,11 @@ static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
}
static const VMStateDescription vmstate_ehci = {
- .name = "ehci",
+ .name = "ehci-core",
.version_id = 2,
.minimum_version_id = 1,
.post_load = usb_ehci_post_load,
.fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(dev, EHCIState),
/* mmio registers */
VMSTATE_UINT32(usbcmd, EHCIState),
VMSTATE_UINT32(usbsts, EHCIState),
@@ -2650,8 +2653,19 @@ static const VMStateDescription vmstate_ehci = {
}
};
-static Property ehci_properties[] = {
- DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128),
+static const VMStateDescription vmstate_ehci_pci = {
+ .name = "ehci",
+ .version_id = 2,
+ .minimum_version_id = 1,
+ .post_load = usb_ehci_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
+ VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
+ }
+};
+
+static Property ehci_pci_properties[] = {
+ DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
DEFINE_PROP_END_OF_LIST(),
};
@@ -2660,13 +2674,13 @@ static void ehci_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->init = usb_ehci_initfn;
+ k->init = usb_ehci_pci_initfn;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
k->revision = 0x10;
k->class_id = PCI_CLASS_SERIAL_USB;
dc->vmsd = &vmstate_ehci;
- dc->props = ehci_properties;
+ dc->props = ehci_pci_properties;
}
static TypeInfo ehci_info = {
@@ -2681,13 +2695,13 @@ static void ich9_ehci_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->init = usb_ehci_initfn;
+ k->init = usb_ehci_pci_initfn;
k->vendor_id = PCI_VENDOR_ID_INTEL;
k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
k->revision = 0x03;
k->class_id = PCI_CLASS_SERIAL_USB;
dc->vmsd = &vmstate_ehci;
- dc->props = ehci_properties;
+ dc->props = ehci_pci_properties;
}
static TypeInfo ich9_ehci_info = {
@@ -2697,44 +2711,10 @@ static TypeInfo ich9_ehci_info = {
.class_init = ich9_ehci_class_init,
};
-static int usb_ehci_initfn(PCIDevice *dev)
+static void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
{
- EHCIState *s = DO_UPCAST(EHCIState, dev, dev);
- uint8_t *pci_conf = s->dev.config;
int i;
- pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
-
- /* capabilities pointer */
- pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
- //pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50);
-
- pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
- pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
- pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
-
- // pci_conf[0x50] = 0x01; // power management caps
-
- pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); // release number (2.1.4)
- pci_set_byte(&pci_conf[0x61], 0x20); // frame length adjustment (2.1.5)
- pci_set_word(&pci_conf[0x62], 0x00); // port wake up capability (2.1.6)
-
- pci_conf[0x64] = 0x00;
- pci_conf[0x65] = 0x00;
- pci_conf[0x66] = 0x00;
- pci_conf[0x67] = 0x00;
- pci_conf[0x68] = 0x01;
- pci_conf[0x69] = 0x00;
- pci_conf[0x6a] = 0x00;
- pci_conf[0x6b] = 0x00; // USBLEGSUP
- pci_conf[0x6c] = 0x00;
- pci_conf[0x6d] = 0x00;
- pci_conf[0x6e] = 0x00;
- pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS
-
- s->capsbase = 0x00;
- s->opregbase = 0x20;
-
/* 2.2 host controller interface version */
s->caps[0x00] = (uint8_t)(s->opregbase - s->capsbase);
s->caps[0x01] = 0x00;
@@ -2745,15 +2725,10 @@ static int usb_ehci_initfn(PCIDevice *dev)
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];
-
- s->dma = pci_dma_context(dev);
-
- usb_bus_new(&s->bus, &ehci_bus_ops, &s->dev.qdev);
+ usb_bus_new(&s->bus, &ehci_bus_ops, dev);
for(i = 0; i < NB_PORTS; i++) {
usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
USB_SPEED_MASK_HIGH);
@@ -2781,8 +2756,53 @@ static int usb_ehci_initfn(PCIDevice *dev)
memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg);
memory_region_add_subregion(&s->mem, s->opregbase + PORTSC_BEGIN,
&s->mem_ports);
+}
+
+static int usb_ehci_pci_initfn(PCIDevice *dev)
+{
+ EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
+ EHCIState *s = &i->ehci;
+ uint8_t *pci_conf = dev->config;
+
+ pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
+
+ /* capabilities pointer */
+ pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
+ /* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */
+
+ pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
+ pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
+ pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
+
+ /* pci_conf[0x50] = 0x01; *//* power management caps */
+
+ pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */
+ pci_set_byte(&pci_conf[0x61], 0x20); /* frame length adjustment (2.1.5) */
+ pci_set_word(&pci_conf[0x62], 0x00); /* port wake up capability (2.1.6) */
+
+ pci_conf[0x64] = 0x00;
+ pci_conf[0x65] = 0x00;
+ pci_conf[0x66] = 0x00;
+ pci_conf[0x67] = 0x00;
+ pci_conf[0x68] = 0x01;
+ pci_conf[0x69] = 0x00;
+ pci_conf[0x6a] = 0x00;
+ pci_conf[0x6b] = 0x00; /* USBLEGSUP */
+ pci_conf[0x6c] = 0x00;
+ pci_conf[0x6d] = 0x00;
+ pci_conf[0x6e] = 0x00;
+ pci_conf[0x6f] = 0xc0; /* USBLEFCTLSTS */
+
+ s->caps[0x09] = 0x68; /* EECP */
+
+ s->irq = dev->irq[3];
+ s->dma = pci_dma_context(dev);
+
+ s->capsbase = 0x00;
+ s->opregbase = 0x20;
- pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
+ usb_ehci_initfn(s, DEVICE(dev));
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
return 0;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RfC PATCH 3/5] usb/ehci: seperate out PCIisms
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 3/5] usb/ehci: seperate out PCIisms Gerd Hoffmann
@ 2012-10-31 16:05 ` Andreas Färber
2012-11-01 8:39 ` Gerd Hoffmann
0 siblings, 1 reply; 12+ messages in thread
From: Andreas Färber @ 2012-10-31 16:05 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: peter.crosthwaite, qemu-devel
Am 30.10.2012 12:28, schrieb Gerd Hoffmann:
> From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
>
> Seperate the PCI stuff from the EHCI components. Extracted the PCIDevice
> out into a new wrapper struct to make EHCIState non-PCI-specific. Seperated
> tho non PCI init component out into a seperate "common" init function.
>
> Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> hw/usb/hcd-ehci.c | 124 +++++++++++++++++++++++++++++++----------------------
> 1 files changed, 72 insertions(+), 52 deletions(-)
>
> diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
> index 28890b5..59580fc 100644
> --- a/hw/usb/hcd-ehci.c
> +++ b/hw/usb/hcd-ehci.c
> @@ -385,7 +385,6 @@ struct EHCIQueue {
> typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
>
> struct EHCIState {
> - PCIDevice dev;
> USBBus bus;
> qemu_irq irq;
> MemoryRegion mem;
> @@ -447,6 +446,11 @@ struct EHCIState {
> bool int_req_by_async;
> };
>
> +typedef struct EHCIPCIState {
> + PCIDevice pcidev;
> + EHCIState ehci;
> +} EHCIPCIState;
> +
> #define SET_LAST_RUN_CLOCK(s) \
> (s)->last_run_ns = qemu_get_clock_ns(vm_clock);
>
> @@ -2553,7 +2557,7 @@ static const MemoryRegionOps ehci_mmio_port_ops = {
> .endianness = DEVICE_LITTLE_ENDIAN,
> };
>
> -static int usb_ehci_initfn(PCIDevice *dev);
> +static int usb_ehci_pci_initfn(PCIDevice *dev);
>
> static USBPortOps ehci_port_ops = {
> .attach = ehci_attach,
> @@ -2614,12 +2618,11 @@ static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
> }
>
> static const VMStateDescription vmstate_ehci = {
> - .name = "ehci",
> + .name = "ehci-core",
> .version_id = 2,
> .minimum_version_id = 1,
> .post_load = usb_ehci_post_load,
> .fields = (VMStateField[]) {
> - VMSTATE_PCI_DEVICE(dev, EHCIState),
> /* mmio registers */
> VMSTATE_UINT32(usbcmd, EHCIState),
> VMSTATE_UINT32(usbsts, EHCIState),
> @@ -2650,8 +2653,19 @@ static const VMStateDescription vmstate_ehci = {
> }
> };
>
> -static Property ehci_properties[] = {
> - DEFINE_PROP_UINT32("maxframes", EHCIState, maxframes, 128),
> +static const VMStateDescription vmstate_ehci_pci = {
> + .name = "ehci",
> + .version_id = 2,
> + .minimum_version_id = 1,
> + .post_load = usb_ehci_post_load,
> + .fields = (VMStateField[]) {
> + VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
> + VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
> + }
> +};
> +
> +static Property ehci_pci_properties[] = {
> + DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
> DEFINE_PROP_END_OF_LIST(),
> };
>
> @@ -2660,13 +2674,13 @@ static void ehci_class_init(ObjectClass *klass, void *data)
> DeviceClass *dc = DEVICE_CLASS(klass);
> PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>
> - k->init = usb_ehci_initfn;
> + k->init = usb_ehci_pci_initfn;
> k->vendor_id = PCI_VENDOR_ID_INTEL;
> k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
> k->revision = 0x10;
> k->class_id = PCI_CLASS_SERIAL_USB;
> dc->vmsd = &vmstate_ehci;
> - dc->props = ehci_properties;
> + dc->props = ehci_pci_properties;
> }
>
> static TypeInfo ehci_info = {
> @@ -2681,13 +2695,13 @@ static void ich9_ehci_class_init(ObjectClass *klass, void *data)
> DeviceClass *dc = DEVICE_CLASS(klass);
> PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
>
> - k->init = usb_ehci_initfn;
> + k->init = usb_ehci_pci_initfn;
> k->vendor_id = PCI_VENDOR_ID_INTEL;
> k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
> k->revision = 0x03;
> k->class_id = PCI_CLASS_SERIAL_USB;
> dc->vmsd = &vmstate_ehci;
> - dc->props = ehci_properties;
> + dc->props = ehci_pci_properties;
> }
>
> static TypeInfo ich9_ehci_info = {
> @@ -2697,44 +2711,10 @@ static TypeInfo ich9_ehci_info = {
> .class_init = ich9_ehci_class_init,
> };
>
> -static int usb_ehci_initfn(PCIDevice *dev)
> +static void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
> {
> - EHCIState *s = DO_UPCAST(EHCIState, dev, dev);
> - uint8_t *pci_conf = s->dev.config;
> int i;
>
> - pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
> -
> - /* capabilities pointer */
> - pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
> - //pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50);
> -
> - pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
> - pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
> - pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
> -
> - // pci_conf[0x50] = 0x01; // power management caps
> -
> - pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); // release number (2.1.4)
> - pci_set_byte(&pci_conf[0x61], 0x20); // frame length adjustment (2.1.5)
> - pci_set_word(&pci_conf[0x62], 0x00); // port wake up capability (2.1.6)
> -
> - pci_conf[0x64] = 0x00;
> - pci_conf[0x65] = 0x00;
> - pci_conf[0x66] = 0x00;
> - pci_conf[0x67] = 0x00;
> - pci_conf[0x68] = 0x01;
> - pci_conf[0x69] = 0x00;
> - pci_conf[0x6a] = 0x00;
> - pci_conf[0x6b] = 0x00; // USBLEGSUP
> - pci_conf[0x6c] = 0x00;
> - pci_conf[0x6d] = 0x00;
> - pci_conf[0x6e] = 0x00;
> - pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS
> -
> - s->capsbase = 0x00;
> - s->opregbase = 0x20;
> -
> /* 2.2 host controller interface version */
> s->caps[0x00] = (uint8_t)(s->opregbase - s->capsbase);
> s->caps[0x01] = 0x00;
> @@ -2745,15 +2725,10 @@ static int usb_ehci_initfn(PCIDevice *dev)
> 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];
> -
> - s->dma = pci_dma_context(dev);
> -
> - usb_bus_new(&s->bus, &ehci_bus_ops, &s->dev.qdev);
> + usb_bus_new(&s->bus, &ehci_bus_ops, dev);
> for(i = 0; i < NB_PORTS; i++) {
> usb_register_port(&s->bus, &s->ports[i], s, i, &ehci_port_ops,
> USB_SPEED_MASK_HIGH);
> @@ -2781,8 +2756,53 @@ static int usb_ehci_initfn(PCIDevice *dev)
> memory_region_add_subregion(&s->mem, s->opregbase, &s->mem_opreg);
> memory_region_add_subregion(&s->mem, s->opregbase + PORTSC_BEGIN,
> &s->mem_ports);
> +}
> +
> +static int usb_ehci_pci_initfn(PCIDevice *dev)
> +{
> + EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
Same as discussed for Peter's patchset, this should be using a QOM cast
macro and may need an abstract base type if there is no unique type
matching EHCIPCIState struct.
Should I send you a follow-up to squash if this is the approach we are
going to take?
Andreas
> + EHCIState *s = &i->ehci;
> + uint8_t *pci_conf = dev->config;
> +
> + pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
> +
> + /* capabilities pointer */
> + pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
> + /* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */
> +
> + pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
> + pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
> + pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
> +
> + /* pci_conf[0x50] = 0x01; *//* power management caps */
> +
> + pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */
> + pci_set_byte(&pci_conf[0x61], 0x20); /* frame length adjustment (2.1.5) */
> + pci_set_word(&pci_conf[0x62], 0x00); /* port wake up capability (2.1.6) */
> +
> + pci_conf[0x64] = 0x00;
> + pci_conf[0x65] = 0x00;
> + pci_conf[0x66] = 0x00;
> + pci_conf[0x67] = 0x00;
> + pci_conf[0x68] = 0x01;
> + pci_conf[0x69] = 0x00;
> + pci_conf[0x6a] = 0x00;
> + pci_conf[0x6b] = 0x00; /* USBLEGSUP */
> + pci_conf[0x6c] = 0x00;
> + pci_conf[0x6d] = 0x00;
> + pci_conf[0x6e] = 0x00;
> + pci_conf[0x6f] = 0xc0; /* USBLEFCTLSTS */
> +
> + s->caps[0x09] = 0x68; /* EECP */
> +
> + s->irq = dev->irq[3];
> + s->dma = pci_dma_context(dev);
> +
> + s->capsbase = 0x00;
> + s->opregbase = 0x20;
>
> - pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
> + usb_ehci_initfn(s, DEVICE(dev));
> + pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
>
> return 0;
> }
>
--
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RfC PATCH 3/5] usb/ehci: seperate out PCIisms
2012-10-31 16:05 ` Andreas Färber
@ 2012-11-01 8:39 ` Gerd Hoffmann
0 siblings, 0 replies; 12+ messages in thread
From: Gerd Hoffmann @ 2012-11-01 8:39 UTC (permalink / raw)
To: Andreas Färber; +Cc: peter.crosthwaite, qemu-devel
Hi,
>> -static int usb_ehci_initfn(PCIDevice *dev)
>> +static void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
>> {
>> - EHCIState *s = DO_UPCAST(EHCIState, dev, dev);
>> +static int usb_ehci_pci_initfn(PCIDevice *dev)
>> +{
>> + EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
>
> Same as discussed for Peter's patchset, this should be using a QOM cast
> macro and may need an abstract base type if there is no unique type
> matching EHCIPCIState struct.
--verbose please.
This is exactly like it used to be. PCIDeviceClass->init() gets passed
in a PCIDevice pointer and uses DO_UPCAST to get the container struct
carrying the ehci state (EHCIState before the patch, EHCIPCIState now).
This is common practice all over the tree.
> Should I send you a follow-up to squash if this is the approach we are
> going to take?
If there is a new, more QOM-ish way to do the same feel free to send
patches. I see that as independent cleanup though, not as something
which should be squashed into this patch.
cheers,
Gerd
^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [RfC PATCH 4/5] usb/ehci: Guard definition of EHCI_DEBUG
2012-10-30 11:28 [Qemu-devel] [RfC PATCH 0/5] ehci pci splitup Gerd Hoffmann
` (2 preceding siblings ...)
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 3/5] usb/ehci: seperate out PCIisms Gerd Hoffmann
@ 2012-10-30 11:28 ` Gerd Hoffmann
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 5/5] usb/ehci: split into multiple source files Gerd Hoffmann
2012-10-30 13:13 ` [Qemu-devel] [RfC PATCH 0/5] ehci pci splitup Peter Crosthwaite
5 siblings, 0 replies; 12+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 11:28 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.crosthwaite, Gerd Hoffmann
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Guard against re-definition of EHCI_DEBUG. Allows for turning on of debug info
from configure (using --qemu-extra-cflags="-DEHCI_DEBUG=1") rather than source
code hacking.
Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/hcd-ehci.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index 59580fc..d3168c9 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -36,7 +36,9 @@
#include "dma.h"
#include "sysemu.h"
+#ifndef EHCI_DEBUG
#define EHCI_DEBUG 0
+#endif
#if EHCI_DEBUG
#define DPRINTF printf
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [RfC PATCH 5/5] usb/ehci: split into multiple source files
2012-10-30 11:28 [Qemu-devel] [RfC PATCH 0/5] ehci pci splitup Gerd Hoffmann
` (3 preceding siblings ...)
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 4/5] usb/ehci: Guard definition of EHCI_DEBUG Gerd Hoffmann
@ 2012-10-30 11:28 ` Gerd Hoffmann
2012-10-30 13:13 ` [Qemu-devel] [RfC PATCH 0/5] ehci pci splitup Peter Crosthwaite
5 siblings, 0 replies; 12+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 11:28 UTC (permalink / raw)
To: qemu-devel; +Cc: peter.crosthwaite, Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/Makefile.objs | 2 +-
hw/usb/hcd-ehci-pci.c | 138 ++++++++++++++++
hw/usb/hcd-ehci.c | 426 +------------------------------------------------
hw/usb/hcd-ehci.h | 320 +++++++++++++++++++++++++++++++++++++
4 files changed, 462 insertions(+), 424 deletions(-)
create mode 100644 hw/usb/hcd-ehci-pci.c
create mode 100644 hw/usb/hcd-ehci.h
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index c6a7cb6..26ab298 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -1,6 +1,6 @@
common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
-common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o
+common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
common-obj-y += libhw.o
diff --git a/hw/usb/hcd-ehci-pci.c b/hw/usb/hcd-ehci-pci.c
new file mode 100644
index 0000000..daac41d
--- /dev/null
+++ b/hw/usb/hcd-ehci-pci.c
@@ -0,0 +1,138 @@
+/*
+ * QEMU USB EHCI Emulation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/usb/hcd-ehci.h"
+#include "hw/pci.h"
+
+typedef struct EHCIPCIState {
+ PCIDevice pcidev;
+ EHCIState ehci;
+} EHCIPCIState;
+
+static int usb_ehci_pci_initfn(PCIDevice *dev)
+{
+ EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
+ EHCIState *s = &i->ehci;
+ uint8_t *pci_conf = dev->config;
+
+ pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
+
+ /* capabilities pointer */
+ pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
+ /* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */
+
+ pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
+ pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
+ pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
+
+ /* pci_conf[0x50] = 0x01; *//* power management caps */
+
+ pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */
+ pci_set_byte(&pci_conf[0x61], 0x20); /* frame length adjustment (2.1.5) */
+ pci_set_word(&pci_conf[0x62], 0x00); /* port wake up capability (2.1.6) */
+
+ pci_conf[0x64] = 0x00;
+ pci_conf[0x65] = 0x00;
+ pci_conf[0x66] = 0x00;
+ pci_conf[0x67] = 0x00;
+ pci_conf[0x68] = 0x01;
+ pci_conf[0x69] = 0x00;
+ pci_conf[0x6a] = 0x00;
+ pci_conf[0x6b] = 0x00; /* USBLEGSUP */
+ pci_conf[0x6c] = 0x00;
+ pci_conf[0x6d] = 0x00;
+ pci_conf[0x6e] = 0x00;
+ pci_conf[0x6f] = 0xc0; /* USBLEFCTLSTS */
+
+ s->caps[0x09] = 0x68; /* EECP */
+
+ s->irq = dev->irq[3];
+ s->dma = pci_dma_context(dev);
+
+ s->capsbase = 0x00;
+ s->opregbase = 0x20;
+
+ usb_ehci_initfn(s, DEVICE(dev));
+ pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
+
+ return 0;
+}
+
+static Property ehci_pci_properties[] = {
+ DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_ehci_pci = {
+ .name = "ehci",
+ .version_id = 2,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
+ VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
+ }
+};
+
+static void ehci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_ehci_pci_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
+ k->revision = 0x10;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_ehci;
+ dc->props = ehci_pci_properties;
+}
+
+static TypeInfo ehci_info = {
+ .name = "usb-ehci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(EHCIState),
+ .class_init = ehci_class_init,
+};
+
+static void ich9_ehci_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = usb_ehci_pci_initfn;
+ k->vendor_id = PCI_VENDOR_ID_INTEL;
+ k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
+ k->revision = 0x03;
+ k->class_id = PCI_CLASS_SERIAL_USB;
+ dc->vmsd = &vmstate_ehci;
+ dc->props = ehci_pci_properties;
+}
+
+static TypeInfo ich9_ehci_info = {
+ .name = "ich9-usb-ehci1",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(EHCIState),
+ .class_init = ich9_ehci_class_init,
+};
+
+static void ehci_pci_register_types(void)
+{
+ type_register_static(&ehci_info);
+ type_register_static(&ich9_ehci_info);
+}
+
+type_init(ehci_pci_register_types)
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index d3168c9..d9dc576 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -27,31 +27,11 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "hw/hw.h"
-#include "qemu-timer.h"
-#include "hw/usb.h"
-#include "hw/pci.h"
-#include "monitor.h"
-#include "trace.h"
-#include "dma.h"
-#include "sysemu.h"
-
-#ifndef EHCI_DEBUG
-#define EHCI_DEBUG 0
-#endif
-
-#if EHCI_DEBUG
-#define DPRINTF printf
-#else
-#define DPRINTF(...)
-#endif
+#include "hw/usb/hcd-ehci.h"
/* internal processing - reset HC to try and recover */
#define USB_RET_PROCERR (-99)
-#define MMIO_SIZE 0x1000
-#define CAPA_SIZE 0x10
-
/* Capability Registers Base Address - section 2.2 */
#define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */
#define HCIVERSION 0x0002 /* 2-bytes, i/f version # */
@@ -103,9 +83,6 @@
#define CONFIGFLAG 0x0040
-#define PORTSC 0x0044
-#define PORTSC_BEGIN PORTSC
-#define PORTSC_END (PORTSC + 4 * NB_PORTS)
/*
* Bits that are reserved or are read-only are masked out of values
* written to us by software
@@ -137,7 +114,6 @@
#define FRAME_TIMER_NS (1000000000 / FRAME_TIMER_FREQ)
#define NB_MAXINTRATE 8 // Max rate at which controller issues ints
-#define NB_PORTS 6 // Number of downstream ports
#define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction
#define MAX_QH 100 // Max allowable queue heads in a chain
#define MIN_FR_PER_TICK 3 // Min frames to process when catching up
@@ -174,285 +150,6 @@ typedef enum {
#define NLPTR_TYPE_STITD 2 // split xaction, isoc xfer descriptor
#define NLPTR_TYPE_FSTN 3 // frame span traversal node
-
-/* EHCI spec version 1.0 Section 3.3
- */
-typedef struct EHCIitd {
- uint32_t next;
-
- uint32_t transact[8];
-#define ITD_XACT_ACTIVE (1 << 31)
-#define ITD_XACT_DBERROR (1 << 30)
-#define ITD_XACT_BABBLE (1 << 29)
-#define ITD_XACT_XACTERR (1 << 28)
-#define ITD_XACT_LENGTH_MASK 0x0fff0000
-#define ITD_XACT_LENGTH_SH 16
-#define ITD_XACT_IOC (1 << 15)
-#define ITD_XACT_PGSEL_MASK 0x00007000
-#define ITD_XACT_PGSEL_SH 12
-#define ITD_XACT_OFFSET_MASK 0x00000fff
-
- uint32_t bufptr[7];
-#define ITD_BUFPTR_MASK 0xfffff000
-#define ITD_BUFPTR_SH 12
-#define ITD_BUFPTR_EP_MASK 0x00000f00
-#define ITD_BUFPTR_EP_SH 8
-#define ITD_BUFPTR_DEVADDR_MASK 0x0000007f
-#define ITD_BUFPTR_DEVADDR_SH 0
-#define ITD_BUFPTR_DIRECTION (1 << 11)
-#define ITD_BUFPTR_MAXPKT_MASK 0x000007ff
-#define ITD_BUFPTR_MAXPKT_SH 0
-#define ITD_BUFPTR_MULT_MASK 0x00000003
-#define ITD_BUFPTR_MULT_SH 0
-} EHCIitd;
-
-/* EHCI spec version 1.0 Section 3.4
- */
-typedef struct EHCIsitd {
- uint32_t next; // Standard next link pointer
- uint32_t epchar;
-#define SITD_EPCHAR_IO (1 << 31)
-#define SITD_EPCHAR_PORTNUM_MASK 0x7f000000
-#define SITD_EPCHAR_PORTNUM_SH 24
-#define SITD_EPCHAR_HUBADD_MASK 0x007f0000
-#define SITD_EPCHAR_HUBADDR_SH 16
-#define SITD_EPCHAR_EPNUM_MASK 0x00000f00
-#define SITD_EPCHAR_EPNUM_SH 8
-#define SITD_EPCHAR_DEVADDR_MASK 0x0000007f
-
- uint32_t uframe;
-#define SITD_UFRAME_CMASK_MASK 0x0000ff00
-#define SITD_UFRAME_CMASK_SH 8
-#define SITD_UFRAME_SMASK_MASK 0x000000ff
-
- uint32_t results;
-#define SITD_RESULTS_IOC (1 << 31)
-#define SITD_RESULTS_PGSEL (1 << 30)
-#define SITD_RESULTS_TBYTES_MASK 0x03ff0000
-#define SITD_RESULTS_TYBYTES_SH 16
-#define SITD_RESULTS_CPROGMASK_MASK 0x0000ff00
-#define SITD_RESULTS_CPROGMASK_SH 8
-#define SITD_RESULTS_ACTIVE (1 << 7)
-#define SITD_RESULTS_ERR (1 << 6)
-#define SITD_RESULTS_DBERR (1 << 5)
-#define SITD_RESULTS_BABBLE (1 << 4)
-#define SITD_RESULTS_XACTERR (1 << 3)
-#define SITD_RESULTS_MISSEDUF (1 << 2)
-#define SITD_RESULTS_SPLITXSTATE (1 << 1)
-
- uint32_t bufptr[2];
-#define SITD_BUFPTR_MASK 0xfffff000
-#define SITD_BUFPTR_CURROFF_MASK 0x00000fff
-#define SITD_BUFPTR_TPOS_MASK 0x00000018
-#define SITD_BUFPTR_TPOS_SH 3
-#define SITD_BUFPTR_TCNT_MASK 0x00000007
-
- uint32_t backptr; // Standard next link pointer
-} EHCIsitd;
-
-/* EHCI spec version 1.0 Section 3.5
- */
-typedef struct EHCIqtd {
- uint32_t next; // Standard next link pointer
- uint32_t altnext; // Standard next link pointer
- uint32_t token;
-#define QTD_TOKEN_DTOGGLE (1 << 31)
-#define QTD_TOKEN_TBYTES_MASK 0x7fff0000
-#define QTD_TOKEN_TBYTES_SH 16
-#define QTD_TOKEN_IOC (1 << 15)
-#define QTD_TOKEN_CPAGE_MASK 0x00007000
-#define QTD_TOKEN_CPAGE_SH 12
-#define QTD_TOKEN_CERR_MASK 0x00000c00
-#define QTD_TOKEN_CERR_SH 10
-#define QTD_TOKEN_PID_MASK 0x00000300
-#define QTD_TOKEN_PID_SH 8
-#define QTD_TOKEN_ACTIVE (1 << 7)
-#define QTD_TOKEN_HALT (1 << 6)
-#define QTD_TOKEN_DBERR (1 << 5)
-#define QTD_TOKEN_BABBLE (1 << 4)
-#define QTD_TOKEN_XACTERR (1 << 3)
-#define QTD_TOKEN_MISSEDUF (1 << 2)
-#define QTD_TOKEN_SPLITXSTATE (1 << 1)
-#define QTD_TOKEN_PING (1 << 0)
-
- uint32_t bufptr[5]; // Standard buffer pointer
-#define QTD_BUFPTR_MASK 0xfffff000
-#define QTD_BUFPTR_SH 12
-} EHCIqtd;
-
-/* EHCI spec version 1.0 Section 3.6
- */
-typedef struct EHCIqh {
- uint32_t next; // Standard next link pointer
-
- /* endpoint characteristics */
- uint32_t epchar;
-#define QH_EPCHAR_RL_MASK 0xf0000000
-#define QH_EPCHAR_RL_SH 28
-#define QH_EPCHAR_C (1 << 27)
-#define QH_EPCHAR_MPLEN_MASK 0x07FF0000
-#define QH_EPCHAR_MPLEN_SH 16
-#define QH_EPCHAR_H (1 << 15)
-#define QH_EPCHAR_DTC (1 << 14)
-#define QH_EPCHAR_EPS_MASK 0x00003000
-#define QH_EPCHAR_EPS_SH 12
-#define EHCI_QH_EPS_FULL 0
-#define EHCI_QH_EPS_LOW 1
-#define EHCI_QH_EPS_HIGH 2
-#define EHCI_QH_EPS_RESERVED 3
-
-#define QH_EPCHAR_EP_MASK 0x00000f00
-#define QH_EPCHAR_EP_SH 8
-#define QH_EPCHAR_I (1 << 7)
-#define QH_EPCHAR_DEVADDR_MASK 0x0000007f
-#define QH_EPCHAR_DEVADDR_SH 0
-
- /* endpoint capabilities */
- uint32_t epcap;
-#define QH_EPCAP_MULT_MASK 0xc0000000
-#define QH_EPCAP_MULT_SH 30
-#define QH_EPCAP_PORTNUM_MASK 0x3f800000
-#define QH_EPCAP_PORTNUM_SH 23
-#define QH_EPCAP_HUBADDR_MASK 0x007f0000
-#define QH_EPCAP_HUBADDR_SH 16
-#define QH_EPCAP_CMASK_MASK 0x0000ff00
-#define QH_EPCAP_CMASK_SH 8
-#define QH_EPCAP_SMASK_MASK 0x000000ff
-#define QH_EPCAP_SMASK_SH 0
-
- uint32_t current_qtd; // Standard next link pointer
- uint32_t next_qtd; // Standard next link pointer
- uint32_t altnext_qtd;
-#define QH_ALTNEXT_NAKCNT_MASK 0x0000001e
-#define QH_ALTNEXT_NAKCNT_SH 1
-
- uint32_t token; // Same as QTD token
- uint32_t bufptr[5]; // Standard buffer pointer
-#define BUFPTR_CPROGMASK_MASK 0x000000ff
-#define BUFPTR_FRAMETAG_MASK 0x0000001f
-#define BUFPTR_SBYTES_MASK 0x00000fe0
-#define BUFPTR_SBYTES_SH 5
-} EHCIqh;
-
-/* EHCI spec version 1.0 Section 3.7
- */
-typedef struct EHCIfstn {
- uint32_t next; // Standard next link pointer
- uint32_t backptr; // Standard next link pointer
-} EHCIfstn;
-
-typedef struct EHCIPacket EHCIPacket;
-typedef struct EHCIQueue EHCIQueue;
-typedef struct EHCIState EHCIState;
-
-enum async_state {
- EHCI_ASYNC_NONE = 0,
- EHCI_ASYNC_INITIALIZED,
- EHCI_ASYNC_INFLIGHT,
- EHCI_ASYNC_FINISHED,
-};
-
-struct EHCIPacket {
- EHCIQueue *queue;
- QTAILQ_ENTRY(EHCIPacket) next;
-
- EHCIqtd qtd; /* copy of current QTD (being worked on) */
- uint32_t qtdaddr; /* address QTD read from */
-
- USBPacket packet;
- QEMUSGList sgl;
- int pid;
- enum async_state async;
- int usb_status;
-};
-
-struct EHCIQueue {
- EHCIState *ehci;
- QTAILQ_ENTRY(EHCIQueue) next;
- uint32_t seen;
- uint64_t ts;
- int async;
- int transact_ctr;
-
- /* cached data from guest - needs to be flushed
- * when guest removes an entry (doorbell, handshake sequence)
- */
- EHCIqh qh; /* copy of current QH (being worked on) */
- uint32_t qhaddr; /* address QH read from */
- uint32_t qtdaddr; /* address QTD read from */
- USBDevice *dev;
- QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
-};
-
-typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
-
-struct EHCIState {
- USBBus bus;
- qemu_irq irq;
- MemoryRegion mem;
- DMAContext *dma;
- MemoryRegion mem_caps;
- MemoryRegion mem_opreg;
- MemoryRegion mem_ports;
- int companion_count;
- uint16_t capsbase;
- uint16_t opregbase;
-
- /* properties */
- uint32_t maxframes;
-
- /*
- * EHCI spec version 1.0 Section 2.3
- * Host Controller Operational Registers
- */
- uint8_t caps[CAPA_SIZE];
- union {
- uint32_t opreg[PORTSC_BEGIN/sizeof(uint32_t)];
- struct {
- uint32_t usbcmd;
- uint32_t usbsts;
- uint32_t usbintr;
- uint32_t frindex;
- uint32_t ctrldssegment;
- uint32_t periodiclistbase;
- uint32_t asynclistaddr;
- uint32_t notused[9];
- uint32_t configflag;
- };
- };
- uint32_t portsc[NB_PORTS];
-
- /*
- * Internal states, shadow registers, etc
- */
- QEMUTimer *frame_timer;
- QEMUBH *async_bh;
- uint32_t astate; /* Current state in asynchronous schedule */
- uint32_t pstate; /* Current state in periodic schedule */
- USBPort ports[NB_PORTS];
- USBPort *companion_ports[NB_PORTS];
- uint32_t usbsts_pending;
- uint32_t usbsts_frindex;
- EHCIQueueHead aqueues;
- EHCIQueueHead pqueues;
-
- /* which address to look at next */
- uint32_t a_fetch_addr;
- uint32_t p_fetch_addr;
-
- USBPacket ipacket;
- QEMUSGList isgl;
-
- uint64_t last_run_ns;
- uint32_t async_stepdown;
- bool int_req_by_async;
-};
-
-typedef struct EHCIPCIState {
- PCIDevice pcidev;
- EHCIState ehci;
-} EHCIPCIState;
-
#define SET_LAST_RUN_CLOCK(s) \
(s)->last_run_ns = qemu_get_clock_ns(vm_clock);
@@ -2559,8 +2256,6 @@ static const MemoryRegionOps ehci_mmio_port_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
-static int usb_ehci_pci_initfn(PCIDevice *dev);
-
static USBPortOps ehci_port_ops = {
.attach = ehci_attach,
.detach = ehci_detach,
@@ -2619,7 +2314,7 @@ static void usb_ehci_vm_state_change(void *opaque, int running, RunState state)
}
}
-static const VMStateDescription vmstate_ehci = {
+const VMStateDescription vmstate_ehci = {
.name = "ehci-core",
.version_id = 2,
.minimum_version_id = 1,
@@ -2655,65 +2350,7 @@ static const VMStateDescription vmstate_ehci = {
}
};
-static const VMStateDescription vmstate_ehci_pci = {
- .name = "ehci",
- .version_id = 2,
- .minimum_version_id = 1,
- .post_load = usb_ehci_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_PCI_DEVICE(pcidev, EHCIPCIState),
- VMSTATE_STRUCT(ehci, EHCIPCIState, 2, vmstate_ehci, EHCIState),
- }
-};
-
-static Property ehci_pci_properties[] = {
- DEFINE_PROP_UINT32("maxframes", EHCIPCIState, ehci.maxframes, 128),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void ehci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = usb_ehci_pci_initfn;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82801D; /* ich4 */
- k->revision = 0x10;
- k->class_id = PCI_CLASS_SERIAL_USB;
- dc->vmsd = &vmstate_ehci;
- dc->props = ehci_pci_properties;
-}
-
-static TypeInfo ehci_info = {
- .name = "usb-ehci",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(EHCIState),
- .class_init = ehci_class_init,
-};
-
-static void ich9_ehci_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
- k->init = usb_ehci_pci_initfn;
- k->vendor_id = PCI_VENDOR_ID_INTEL;
- k->device_id = PCI_DEVICE_ID_INTEL_82801I_EHCI1;
- k->revision = 0x03;
- k->class_id = PCI_CLASS_SERIAL_USB;
- dc->vmsd = &vmstate_ehci;
- dc->props = ehci_pci_properties;
-}
-
-static TypeInfo ich9_ehci_info = {
- .name = "ich9-usb-ehci1",
- .parent = TYPE_PCI_DEVICE,
- .instance_size = sizeof(EHCIState),
- .class_init = ich9_ehci_class_init,
-};
-
-static void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
+void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
{
int i;
@@ -2760,63 +2397,6 @@ static void usb_ehci_initfn(EHCIState *s, DeviceState *dev)
&s->mem_ports);
}
-static int usb_ehci_pci_initfn(PCIDevice *dev)
-{
- EHCIPCIState *i = DO_UPCAST(EHCIPCIState, pcidev, dev);
- EHCIState *s = &i->ehci;
- uint8_t *pci_conf = dev->config;
-
- pci_set_byte(&pci_conf[PCI_CLASS_PROG], 0x20);
-
- /* capabilities pointer */
- pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x00);
- /* pci_set_byte(&pci_conf[PCI_CAPABILITY_LIST], 0x50); */
-
- pci_set_byte(&pci_conf[PCI_INTERRUPT_PIN], 4); /* interrupt pin D */
- pci_set_byte(&pci_conf[PCI_MIN_GNT], 0);
- pci_set_byte(&pci_conf[PCI_MAX_LAT], 0);
-
- /* pci_conf[0x50] = 0x01; *//* power management caps */
-
- pci_set_byte(&pci_conf[USB_SBRN], USB_RELEASE_2); /* release # (2.1.4) */
- pci_set_byte(&pci_conf[0x61], 0x20); /* frame length adjustment (2.1.5) */
- pci_set_word(&pci_conf[0x62], 0x00); /* port wake up capability (2.1.6) */
-
- pci_conf[0x64] = 0x00;
- pci_conf[0x65] = 0x00;
- pci_conf[0x66] = 0x00;
- pci_conf[0x67] = 0x00;
- pci_conf[0x68] = 0x01;
- pci_conf[0x69] = 0x00;
- pci_conf[0x6a] = 0x00;
- pci_conf[0x6b] = 0x00; /* USBLEGSUP */
- pci_conf[0x6c] = 0x00;
- pci_conf[0x6d] = 0x00;
- pci_conf[0x6e] = 0x00;
- pci_conf[0x6f] = 0xc0; /* USBLEFCTLSTS */
-
- s->caps[0x09] = 0x68; /* EECP */
-
- s->irq = dev->irq[3];
- s->dma = pci_dma_context(dev);
-
- s->capsbase = 0x00;
- s->opregbase = 0x20;
-
- usb_ehci_initfn(s, DEVICE(dev));
- pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem);
-
- return 0;
-}
-
-static void ehci_register_types(void)
-{
- type_register_static(&ehci_info);
- type_register_static(&ich9_ehci_info);
-}
-
-type_init(ehci_register_types)
-
/*
* vim: expandtab ts=4
*/
diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h
new file mode 100644
index 0000000..0ec675c
--- /dev/null
+++ b/hw/usb/hcd-ehci.h
@@ -0,0 +1,320 @@
+/*
+ * QEMU USB EHCI Emulation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/hw.h"
+#include "qemu-timer.h"
+#include "hw/usb.h"
+#include "monitor.h"
+#include "trace.h"
+#include "dma.h"
+#include "sysemu.h"
+
+#ifndef EHCI_DEBUG
+#define EHCI_DEBUG 0
+#endif
+
+#if EHCI_DEBUG
+#define DPRINTF printf
+#else
+#define DPRINTF(...)
+#endif
+
+#define MMIO_SIZE 0x1000
+#define CAPA_SIZE 0x10
+
+#define PORTSC 0x0044
+#define PORTSC_BEGIN PORTSC
+#define PORTSC_END (PORTSC + 4 * NB_PORTS)
+
+#define NB_PORTS 6 /* Number of downstream ports */
+
+typedef struct EHCIPacket EHCIPacket;
+typedef struct EHCIQueue EHCIQueue;
+typedef struct EHCIState EHCIState;
+
+/* EHCI spec version 1.0 Section 3.3
+ */
+typedef struct EHCIitd {
+ uint32_t next;
+
+ uint32_t transact[8];
+#define ITD_XACT_ACTIVE (1 << 31)
+#define ITD_XACT_DBERROR (1 << 30)
+#define ITD_XACT_BABBLE (1 << 29)
+#define ITD_XACT_XACTERR (1 << 28)
+#define ITD_XACT_LENGTH_MASK 0x0fff0000
+#define ITD_XACT_LENGTH_SH 16
+#define ITD_XACT_IOC (1 << 15)
+#define ITD_XACT_PGSEL_MASK 0x00007000
+#define ITD_XACT_PGSEL_SH 12
+#define ITD_XACT_OFFSET_MASK 0x00000fff
+
+ uint32_t bufptr[7];
+#define ITD_BUFPTR_MASK 0xfffff000
+#define ITD_BUFPTR_SH 12
+#define ITD_BUFPTR_EP_MASK 0x00000f00
+#define ITD_BUFPTR_EP_SH 8
+#define ITD_BUFPTR_DEVADDR_MASK 0x0000007f
+#define ITD_BUFPTR_DEVADDR_SH 0
+#define ITD_BUFPTR_DIRECTION (1 << 11)
+#define ITD_BUFPTR_MAXPKT_MASK 0x000007ff
+#define ITD_BUFPTR_MAXPKT_SH 0
+#define ITD_BUFPTR_MULT_MASK 0x00000003
+#define ITD_BUFPTR_MULT_SH 0
+} EHCIitd;
+
+/* EHCI spec version 1.0 Section 3.4
+ */
+typedef struct EHCIsitd {
+ uint32_t next; /* Standard next link pointer */
+ uint32_t epchar;
+#define SITD_EPCHAR_IO (1 << 31)
+#define SITD_EPCHAR_PORTNUM_MASK 0x7f000000
+#define SITD_EPCHAR_PORTNUM_SH 24
+#define SITD_EPCHAR_HUBADD_MASK 0x007f0000
+#define SITD_EPCHAR_HUBADDR_SH 16
+#define SITD_EPCHAR_EPNUM_MASK 0x00000f00
+#define SITD_EPCHAR_EPNUM_SH 8
+#define SITD_EPCHAR_DEVADDR_MASK 0x0000007f
+
+ uint32_t uframe;
+#define SITD_UFRAME_CMASK_MASK 0x0000ff00
+#define SITD_UFRAME_CMASK_SH 8
+#define SITD_UFRAME_SMASK_MASK 0x000000ff
+
+ uint32_t results;
+#define SITD_RESULTS_IOC (1 << 31)
+#define SITD_RESULTS_PGSEL (1 << 30)
+#define SITD_RESULTS_TBYTES_MASK 0x03ff0000
+#define SITD_RESULTS_TYBYTES_SH 16
+#define SITD_RESULTS_CPROGMASK_MASK 0x0000ff00
+#define SITD_RESULTS_CPROGMASK_SH 8
+#define SITD_RESULTS_ACTIVE (1 << 7)
+#define SITD_RESULTS_ERR (1 << 6)
+#define SITD_RESULTS_DBERR (1 << 5)
+#define SITD_RESULTS_BABBLE (1 << 4)
+#define SITD_RESULTS_XACTERR (1 << 3)
+#define SITD_RESULTS_MISSEDUF (1 << 2)
+#define SITD_RESULTS_SPLITXSTATE (1 << 1)
+
+ uint32_t bufptr[2];
+#define SITD_BUFPTR_MASK 0xfffff000
+#define SITD_BUFPTR_CURROFF_MASK 0x00000fff
+#define SITD_BUFPTR_TPOS_MASK 0x00000018
+#define SITD_BUFPTR_TPOS_SH 3
+#define SITD_BUFPTR_TCNT_MASK 0x00000007
+
+ uint32_t backptr; /* Standard next link pointer */
+} EHCIsitd;
+
+/* EHCI spec version 1.0 Section 3.5
+ */
+typedef struct EHCIqtd {
+ uint32_t next; /* Standard next link pointer */
+ uint32_t altnext; /* Standard next link pointer */
+ uint32_t token;
+#define QTD_TOKEN_DTOGGLE (1 << 31)
+#define QTD_TOKEN_TBYTES_MASK 0x7fff0000
+#define QTD_TOKEN_TBYTES_SH 16
+#define QTD_TOKEN_IOC (1 << 15)
+#define QTD_TOKEN_CPAGE_MASK 0x00007000
+#define QTD_TOKEN_CPAGE_SH 12
+#define QTD_TOKEN_CERR_MASK 0x00000c00
+#define QTD_TOKEN_CERR_SH 10
+#define QTD_TOKEN_PID_MASK 0x00000300
+#define QTD_TOKEN_PID_SH 8
+#define QTD_TOKEN_ACTIVE (1 << 7)
+#define QTD_TOKEN_HALT (1 << 6)
+#define QTD_TOKEN_DBERR (1 << 5)
+#define QTD_TOKEN_BABBLE (1 << 4)
+#define QTD_TOKEN_XACTERR (1 << 3)
+#define QTD_TOKEN_MISSEDUF (1 << 2)
+#define QTD_TOKEN_SPLITXSTATE (1 << 1)
+#define QTD_TOKEN_PING (1 << 0)
+
+ uint32_t bufptr[5]; /* Standard buffer pointer */
+#define QTD_BUFPTR_MASK 0xfffff000
+#define QTD_BUFPTR_SH 12
+} EHCIqtd;
+
+/* EHCI spec version 1.0 Section 3.6
+ */
+typedef struct EHCIqh {
+ uint32_t next; /* Standard next link pointer */
+
+ /* endpoint characteristics */
+ uint32_t epchar;
+#define QH_EPCHAR_RL_MASK 0xf0000000
+#define QH_EPCHAR_RL_SH 28
+#define QH_EPCHAR_C (1 << 27)
+#define QH_EPCHAR_MPLEN_MASK 0x07FF0000
+#define QH_EPCHAR_MPLEN_SH 16
+#define QH_EPCHAR_H (1 << 15)
+#define QH_EPCHAR_DTC (1 << 14)
+#define QH_EPCHAR_EPS_MASK 0x00003000
+#define QH_EPCHAR_EPS_SH 12
+#define EHCI_QH_EPS_FULL 0
+#define EHCI_QH_EPS_LOW 1
+#define EHCI_QH_EPS_HIGH 2
+#define EHCI_QH_EPS_RESERVED 3
+
+#define QH_EPCHAR_EP_MASK 0x00000f00
+#define QH_EPCHAR_EP_SH 8
+#define QH_EPCHAR_I (1 << 7)
+#define QH_EPCHAR_DEVADDR_MASK 0x0000007f
+#define QH_EPCHAR_DEVADDR_SH 0
+
+ /* endpoint capabilities */
+ uint32_t epcap;
+#define QH_EPCAP_MULT_MASK 0xc0000000
+#define QH_EPCAP_MULT_SH 30
+#define QH_EPCAP_PORTNUM_MASK 0x3f800000
+#define QH_EPCAP_PORTNUM_SH 23
+#define QH_EPCAP_HUBADDR_MASK 0x007f0000
+#define QH_EPCAP_HUBADDR_SH 16
+#define QH_EPCAP_CMASK_MASK 0x0000ff00
+#define QH_EPCAP_CMASK_SH 8
+#define QH_EPCAP_SMASK_MASK 0x000000ff
+#define QH_EPCAP_SMASK_SH 0
+
+ uint32_t current_qtd; /* Standard next link pointer */
+ uint32_t next_qtd; /* Standard next link pointer */
+ uint32_t altnext_qtd;
+#define QH_ALTNEXT_NAKCNT_MASK 0x0000001e
+#define QH_ALTNEXT_NAKCNT_SH 1
+
+ uint32_t token; /* Same as QTD token */
+ uint32_t bufptr[5]; /* Standard buffer pointer */
+#define BUFPTR_CPROGMASK_MASK 0x000000ff
+#define BUFPTR_FRAMETAG_MASK 0x0000001f
+#define BUFPTR_SBYTES_MASK 0x00000fe0
+#define BUFPTR_SBYTES_SH 5
+} EHCIqh;
+
+/* EHCI spec version 1.0 Section 3.7
+ */
+typedef struct EHCIfstn {
+ uint32_t next; /* Standard next link pointer */
+ uint32_t backptr; /* Standard next link pointer */
+} EHCIfstn;
+
+enum async_state {
+ EHCI_ASYNC_NONE = 0,
+ EHCI_ASYNC_INITIALIZED,
+ EHCI_ASYNC_INFLIGHT,
+ EHCI_ASYNC_FINISHED,
+};
+
+struct EHCIPacket {
+ EHCIQueue *queue;
+ QTAILQ_ENTRY(EHCIPacket) next;
+
+ EHCIqtd qtd; /* copy of current QTD (being worked on) */
+ uint32_t qtdaddr; /* address QTD read from */
+
+ USBPacket packet;
+ QEMUSGList sgl;
+ int pid;
+ enum async_state async;
+ int usb_status;
+};
+
+struct EHCIQueue {
+ EHCIState *ehci;
+ QTAILQ_ENTRY(EHCIQueue) next;
+ uint32_t seen;
+ uint64_t ts;
+ int async;
+ int transact_ctr;
+
+ /* cached data from guest - needs to be flushed
+ * when guest removes an entry (doorbell, handshake sequence)
+ */
+ EHCIqh qh; /* copy of current QH (being worked on) */
+ uint32_t qhaddr; /* address QH read from */
+ uint32_t qtdaddr; /* address QTD read from */
+ USBDevice *dev;
+ QTAILQ_HEAD(pkts_head, EHCIPacket) packets;
+};
+
+typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead;
+
+struct EHCIState {
+ USBBus bus;
+ qemu_irq irq;
+ MemoryRegion mem;
+ DMAContext *dma;
+ MemoryRegion mem_caps;
+ MemoryRegion mem_opreg;
+ MemoryRegion mem_ports;
+ int companion_count;
+ uint16_t capsbase;
+ uint16_t opregbase;
+
+ /* properties */
+ uint32_t maxframes;
+
+ /*
+ * EHCI spec version 1.0 Section 2.3
+ * Host Controller Operational Registers
+ */
+ uint8_t caps[CAPA_SIZE];
+ union {
+ uint32_t opreg[PORTSC_BEGIN/sizeof(uint32_t)];
+ struct {
+ uint32_t usbcmd;
+ uint32_t usbsts;
+ uint32_t usbintr;
+ uint32_t frindex;
+ uint32_t ctrldssegment;
+ uint32_t periodiclistbase;
+ uint32_t asynclistaddr;
+ uint32_t notused[9];
+ uint32_t configflag;
+ };
+ };
+ uint32_t portsc[NB_PORTS];
+
+ /*
+ * Internal states, shadow registers, etc
+ */
+ QEMUTimer *frame_timer;
+ QEMUBH *async_bh;
+ uint32_t astate; /* Current state in asynchronous schedule */
+ uint32_t pstate; /* Current state in periodic schedule */
+ USBPort ports[NB_PORTS];
+ USBPort *companion_ports[NB_PORTS];
+ uint32_t usbsts_pending;
+ uint32_t usbsts_frindex;
+ EHCIQueueHead aqueues;
+ EHCIQueueHead pqueues;
+
+ /* which address to look at next */
+ uint32_t a_fetch_addr;
+ uint32_t p_fetch_addr;
+
+ USBPacket ipacket;
+ QEMUSGList isgl;
+
+ uint64_t last_run_ns;
+ uint32_t async_stepdown;
+ bool int_req_by_async;
+};
+
+extern const VMStateDescription vmstate_ehci;
+
+void usb_ehci_initfn(EHCIState *s, DeviceState *dev);
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RfC PATCH 0/5] ehci pci splitup
2012-10-30 11:28 [Qemu-devel] [RfC PATCH 0/5] ehci pci splitup Gerd Hoffmann
` (4 preceding siblings ...)
2012-10-30 11:28 ` [Qemu-devel] [RfC PATCH 5/5] usb/ehci: split into multiple source files Gerd Hoffmann
@ 2012-10-30 13:13 ` Peter Crosthwaite
2012-10-30 14:14 ` Gerd Hoffmann
5 siblings, 1 reply; 12+ messages in thread
From: Peter Crosthwaite @ 2012-10-30 13:13 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel
On Tue, Oct 30, 2012 at 9:28 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Hi,
>
> Based on Peters series, not tested much yet, sysfs dropped but adding
> back in should be as easy as adding a hcd-ehci-sysbus.c file simliar
> to the pci variant.
I can look into this tomorrow if there are no objections to this
series, and ill rerun my test suite to confirm functionality for both
PCI and SYSBUS. Ill send as patches ontop of this series.
Thanks for helping out,
Regards,
Peter
No changes in ehci core should be needed.
>
> Comments?
>
> cheers,
> Gerd
>
> Gerd Hoffmann (1):
> usb/ehci: split into multiple source files
>
> Peter Crosthwaite (4):
> usb/ehci: parameterise the register region offsets
> usb/ehci: Abstract away PCI DMA API
> usb/ehci: seperate out PCIisms
> usb/ehci: Guard definition of EHCI_DEBUG
>
> hw/usb/Makefile.objs | 2 +-
> hw/usb/hcd-ehci-pci.c | 138 +++++++++++++++
> hw/usb/hcd-ehci.c | 465 ++++---------------------------------------------
> hw/usb/hcd-ehci.h | 320 ++++++++++++++++++++++++++++++++++
> 4 files changed, 496 insertions(+), 429 deletions(-)
> create mode 100644 hw/usb/hcd-ehci-pci.c
> create mode 100644 hw/usb/hcd-ehci.h
>
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [RfC PATCH 0/5] ehci pci splitup
2012-10-30 13:13 ` [Qemu-devel] [RfC PATCH 0/5] ehci pci splitup Peter Crosthwaite
@ 2012-10-30 14:14 ` Gerd Hoffmann
0 siblings, 0 replies; 12+ messages in thread
From: Gerd Hoffmann @ 2012-10-30 14:14 UTC (permalink / raw)
To: Peter Crosthwaite; +Cc: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 633 bytes --]
On 10/30/12 14:13, Peter Crosthwaite wrote:
> On Tue, Oct 30, 2012 at 9:28 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
>> Hi,
>>
>> Based on Peters series, not tested much yet, sysfs dropped but adding
>> back in should be as easy as adding a hcd-ehci-sysbus.c file simliar
>> to the pci variant.
>
> I can look into this tomorrow if there are no objections to this
> series, and ill rerun my test suite to confirm functionality for both
> PCI and SYSBUS. Ill send as patches ontop of this series.
I gave it a spin, patch attached, will send a full patch series with
current usb patch queue status in a moment.
cheers,
Gerd
[-- Attachment #2: 0001-usb-ehci-add-sysbus-variant.patch --]
[-- Type: text/plain, Size: 3428 bytes --]
>From 4b818b35d5ead6d4cb97c59945a15c7c61a8f479 Mon Sep 17 00:00:00 2001
From: Gerd Hoffmann <kraxel@redhat.com>
Date: Tue, 30 Oct 2012 15:08:37 +0100
Subject: [PATCH] usb/ehci: add sysbus variant
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hw/usb/Makefile.objs | 2 +-
hw/usb/hcd-ehci-sysbus.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 78 insertions(+), 1 deletions(-)
create mode 100644 hw/usb/hcd-ehci-sysbus.c
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index 26ab298..00e271f 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -1,6 +1,6 @@
common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
-common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o
+common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o hcd-ehci-sysbus.o
common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
common-obj-y += libhw.o
diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c
new file mode 100644
index 0000000..1584079
--- /dev/null
+++ b/hw/usb/hcd-ehci-sysbus.c
@@ -0,0 +1,77 @@
+/*
+ * QEMU USB EHCI Emulation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or(at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw/usb/hcd-ehci.h"
+#include "hw/sysbus.h"
+
+typedef struct EHCISysBusState {
+ SysBusDevice busdev;
+ EHCIState ehci;
+} EHCISysBusState;
+
+static const VMStateDescription vmstate_ehci_sysbus = {
+ .name = "ehci-sysbus",
+ .version_id = 2,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT(ehci, EHCISysBusState, 2, vmstate_ehci, EHCIState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property ehci_sysbus_properties[] = {
+ DEFINE_PROP_UINT32("maxframes", EHCISysBusState, ehci.maxframes, 128),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static int usb_ehci_sysbus_initfn(SysBusDevice *dev)
+{
+ EHCISysBusState *i = FROM_SYSBUS(EHCISysBusState, dev);
+ EHCIState *s = &i->ehci;
+
+ s->capsbase = 0x100;
+ s->opregbase = 0x140;
+
+ usb_ehci_initfn(s, DEVICE(dev));
+ sysbus_init_irq(dev, &s->irq);
+ sysbus_init_mmio(dev, &s->mem);
+ return 0;
+}
+
+static void ehci_sysbus_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+
+ k->init = usb_ehci_sysbus_initfn;
+ dc->vmsd = &vmstate_ehci_sysbus;
+ dc->props = ehci_sysbus_properties;
+}
+
+TypeInfo ehci_xlnx_type_info = {
+ .name = "xlnx,ps7-usb",
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(EHCISysBusState),
+ .class_init = ehci_sysbus_class_init,
+};
+
+static void ehci_sysbus_register_types(void)
+{
+ type_register_static(&ehci_xlnx_type_info);
+}
+
+type_init(ehci_sysbus_register_types)
--
1.7.1
^ permalink raw reply related [flat|nested] 12+ messages in thread