[Qemu-devel] [PATCH for-4.1] hw/usb/hcd-ohci: Move PCI-related code into a separate file

Thomas Huth posted 1 patch 4 years, 11 months ago
Test checkpatch passed
Test asan passed
Test docker-clang@ubuntu passed
Test docker-mingw@fedora passed
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20190418111019.4080-1-thuth@redhat.com
Maintainers: Gerd Hoffmann <kraxel@redhat.com>
hw/usb/Kconfig        |   6 +-
hw/usb/Makefile.objs  |   1 +
hw/usb/hcd-ohci-pci.c | 166 ++++++++++++++++++++++++++++
hw/usb/hcd-ohci.c     | 244 +++---------------------------------------
hw/usb/hcd-ohci.h     | 132 +++++++++++++++++++++++
5 files changed, 321 insertions(+), 228 deletions(-)
create mode 100644 hw/usb/hcd-ohci-pci.c
create mode 100644 hw/usb/hcd-ohci.h
[Qemu-devel] [PATCH for-4.1] hw/usb/hcd-ohci: Move PCI-related code into a separate file
Posted by Thomas Huth 4 years, 11 months ago
Some machines (like the pxa2xx-based ARM machines) only have a sysbus
OHCI controller, but no PCI. With the new Kconfig-style build system,
it will soon be possible to create QEMU binaries that only contain
such PCI-less machines. However, the two OHCI controllers, for sysbus
and for PCI, are currently both located in one file, so the PCI code
is still required for linking here. Move the OHCI-PCI device code
into a separate file, so that it is possible to use the sysbus OHCI
device also without the PCI dependency.

Apart from moving code to a new file (and a new header), this patch
might also fix one subtle bug: The ohci_die() function always assumed
to be running with a OHCI-PCI controller and called some PCI-specific
functions - but if I got the code right, ohci_die() might also get
called for the sysbus-OHCI device, so it likely failed in that case.
I've changed this part of the code now, so that there are two ohci_die()
implementations now, one for sysbus and one for PCI.

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 hw/usb/Kconfig        |   6 +-
 hw/usb/Makefile.objs  |   1 +
 hw/usb/hcd-ohci-pci.c | 166 ++++++++++++++++++++++++++++
 hw/usb/hcd-ohci.c     | 244 +++---------------------------------------
 hw/usb/hcd-ohci.h     | 132 +++++++++++++++++++++++
 5 files changed, 321 insertions(+), 228 deletions(-)
 create mode 100644 hw/usb/hcd-ohci-pci.c
 create mode 100644 hw/usb/hcd-ohci.h

diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig
index a1b7acb12a..564305e283 100644
--- a/hw/usb/Kconfig
+++ b/hw/usb/Kconfig
@@ -8,10 +8,14 @@ config USB_UHCI
     select USB
 
 config USB_OHCI
+    bool
+    select USB
+
+config USB_OHCI_PCI
     bool
     default y if PCI_DEVICES
     depends on PCI
-    select USB
+    select USB_OHCI
 
 config USB_EHCI
     bool
diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
index 2b929649ac..81688f6e70 100644
--- a/hw/usb/Makefile.objs
+++ b/hw/usb/Makefile.objs
@@ -5,6 +5,7 @@ common-obj-$(CONFIG_USB) += desc.o desc-msos.o
 # usb host adapters
 common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
 common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
+common-obj-$(CONFIG_USB_OHCI_PCI) += hcd-ohci-pci.o
 common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o
 common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci.o hcd-ehci-sysbus.o
 common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
diff --git a/hw/usb/hcd-ohci-pci.c b/hw/usb/hcd-ohci-pci.c
new file mode 100644
index 0000000000..e972df35c9
--- /dev/null
+++ b/hw/usb/hcd-ohci-pci.c
@@ -0,0 +1,166 @@
+/*
+ * QEMU USB OHCI Emulation
+ * Copyright (c) 2004 Gianni Tedesco
+ * Copyright (c) 2006 CodeSourcery
+ * Copyright (c) 2006 Openedhand Ltd.
+ *
+ * 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.1 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 Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/hw.h"
+#include "qapi/error.h"
+#include "qemu/timer.h"
+#include "hw/usb.h"
+#include "hw/pci/pci.h"
+#include "hw/sysbus.h"
+#include "hw/qdev-dma.h"
+#include "trace.h"
+#include "hcd-ohci.h"
+
+#define TYPE_PCI_OHCI "pci-ohci"
+#define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI)
+
+typedef struct {
+    /*< private >*/
+    PCIDevice parent_obj;
+    /*< public >*/
+
+    OHCIState state;
+    char *masterbus;
+    uint32_t num_ports;
+    uint32_t firstport;
+} OHCIPCIState;
+
+/**
+ * A typical O/EHCI will stop operating, set itself into error state
+ * (which can be queried by MMIO) and will set PERR in its config
+ * space to signal that it got an error
+ */
+static void ohci_pci_die(OHCIState *ohci)
+{
+    OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state);
+
+    trace_usb_ohci_die();
+
+    ohci_set_interrupt(ohci, OHCI_INTR_UE);
+    ohci_bus_stop(ohci);
+    pci_set_word(dev->parent_obj.config + PCI_STATUS,
+                 PCI_STATUS_DETECTED_PARITY);
+}
+
+static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp)
+{
+    Error *err = NULL;
+    OHCIPCIState *ohci = PCI_OHCI(dev);
+
+    dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */
+    dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
+
+    usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0,
+                  ohci->masterbus, ohci->firstport,
+                  pci_get_address_space(dev), ohci_pci_die, &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+
+    ohci->state.irq = pci_allocate_irq(dev);
+    pci_register_bar(dev, 0, 0, &ohci->state.mem);
+}
+
+static void usb_ohci_exit(PCIDevice *dev)
+{
+    OHCIPCIState *ohci = PCI_OHCI(dev);
+    OHCIState *s = &ohci->state;
+
+    trace_usb_ohci_exit(s->name);
+    ohci_bus_stop(s);
+
+    if (s->async_td) {
+        usb_cancel_packet(&s->usb_packet);
+        s->async_td = 0;
+    }
+    ohci_stop_endpoints(s);
+
+    if (!ohci->masterbus) {
+        usb_bus_release(&s->bus);
+    }
+
+    timer_del(s->eof_timer);
+    timer_free(s->eof_timer);
+}
+
+static void usb_ohci_reset_pci(DeviceState *d)
+{
+    PCIDevice *dev = PCI_DEVICE(d);
+    OHCIPCIState *ohci = PCI_OHCI(dev);
+    OHCIState *s = &ohci->state;
+
+    ohci_hard_reset(s);
+}
+
+static Property ohci_pci_properties[] = {
+    DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
+    DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
+    DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription vmstate_ohci = {
+    .name = "ohci",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState),
+        VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void ohci_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+    k->realize = usb_ohci_realize_pci;
+    k->exit = usb_ohci_exit;
+    k->vendor_id = PCI_VENDOR_ID_APPLE;
+    k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
+    k->class_id = PCI_CLASS_SERIAL_USB;
+    set_bit(DEVICE_CATEGORY_USB, dc->categories);
+    dc->desc = "Apple USB Controller";
+    dc->props = ohci_pci_properties;
+    dc->hotpluggable = false;
+    dc->vmsd = &vmstate_ohci;
+    dc->reset = usb_ohci_reset_pci;
+}
+
+static const TypeInfo ohci_pci_info = {
+    .name          = TYPE_PCI_OHCI,
+    .parent        = TYPE_PCI_DEVICE,
+    .instance_size = sizeof(OHCIPCIState),
+    .class_init    = ohci_pci_class_init,
+    .interfaces = (InterfaceInfo[]) {
+        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
+        { },
+    },
+};
+
+static void ohci_pci_register_types(void)
+{
+    type_register_static(&ohci_pci_info);
+}
+
+type_init(ohci_pci_register_types)
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index 81cf5ab7a5..343816d561 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -30,86 +30,19 @@
 #include "qapi/error.h"
 #include "qemu/timer.h"
 #include "hw/usb.h"
-#include "hw/pci/pci.h"
 #include "hw/sysbus.h"
 #include "hw/qdev-dma.h"
 #include "trace.h"
+#include "hcd-ohci.h"
 
 /* This causes frames to occur 1000x slower */
 //#define OHCI_TIME_WARP 1
 
-/* Number of Downstream Ports on the root hub.  */
-
-#define OHCI_MAX_PORTS 15
-
 #define ED_LINK_LIMIT 32
 
 static int64_t usb_frame_time;
 static int64_t usb_bit_time;
 
-typedef struct OHCIPort {
-    USBPort port;
-    uint32_t ctrl;
-} OHCIPort;
-
-typedef struct {
-    USBBus bus;
-    qemu_irq irq;
-    MemoryRegion mem;
-    AddressSpace *as;
-    uint32_t num_ports;
-    const char *name;
-
-    QEMUTimer *eof_timer;
-    int64_t sof_time;
-
-    /* OHCI state */
-    /* Control partition */
-    uint32_t ctl, status;
-    uint32_t intr_status;
-    uint32_t intr;
-
-    /* memory pointer partition */
-    uint32_t hcca;
-    uint32_t ctrl_head, ctrl_cur;
-    uint32_t bulk_head, bulk_cur;
-    uint32_t per_cur;
-    uint32_t done;
-    int32_t done_count;
-
-    /* Frame counter partition */
-    uint16_t fsmps;
-    uint8_t fit;
-    uint16_t fi;
-    uint8_t frt;
-    uint16_t frame_number;
-    uint16_t padding;
-    uint32_t pstart;
-    uint32_t lst;
-
-    /* Root Hub partition */
-    uint32_t rhdesc_a, rhdesc_b;
-    uint32_t rhstatus;
-    OHCIPort rhport[OHCI_MAX_PORTS];
-
-    /* PXA27x Non-OHCI events */
-    uint32_t hstatus;
-    uint32_t hmask;
-    uint32_t hreset;
-    uint32_t htest;
-
-    /* SM501 local memory offset */
-    dma_addr_t localmem_base;
-
-    /* Active packets.  */
-    uint32_t old_ctl;
-    USBPacket usb_packet;
-    uint8_t usb_buf[8192];
-    uint32_t async_td;
-    bool async_complete;
-
-} OHCIState;
-
 /* Host Controller Communications Area */
 struct ohci_hcca {
     uint32_t intr[32];
@@ -122,7 +55,6 @@ struct ohci_hcca {
 #define ED_WBACK_OFFSET offsetof(struct ohci_ed, head)
 #define ED_WBACK_SIZE   4
 
-static void ohci_bus_stop(OHCIState *ohci);
 static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
 
 /* Bitfields for the first word of an Endpoint Desciptor.  */
@@ -229,16 +161,6 @@ struct ohci_iso_td {
 #define OHCI_STATUS_OCR       (1<<3)
 #define OHCI_STATUS_SOC       ((1<<6)|(1<<7))
 
-#define OHCI_INTR_SO          (1U<<0) /* Scheduling overrun */
-#define OHCI_INTR_WD          (1U<<1) /* HcDoneHead writeback */
-#define OHCI_INTR_SF          (1U<<2) /* Start of frame */
-#define OHCI_INTR_RD          (1U<<3) /* Resume detect */
-#define OHCI_INTR_UE          (1U<<4) /* Unrecoverable error */
-#define OHCI_INTR_FNO         (1U<<5) /* Frame number overflow */
-#define OHCI_INTR_RHSC        (1U<<6) /* Root hub status change */
-#define OHCI_INTR_OC          (1U<<30) /* Ownership change */
-#define OHCI_INTR_MIE         (1U<<31) /* Master Interrupt Enable */
-
 #define OHCI_HCCA_SIZE        0x100
 #define OHCI_HCCA_MASK        0xffffff00
 
@@ -302,25 +224,9 @@ struct ohci_iso_td {
 
 #define OHCI_HRESET_FSBIR       (1 << 0)
 
-static void ohci_die(OHCIState *ohci);
-
-/* Update IRQ levels */
-static inline void ohci_intr_update(OHCIState *ohci)
+static inline void ohci_die(OHCIState *ohci)
 {
-    int level = 0;
-
-    if ((ohci->intr & OHCI_INTR_MIE) &&
-        (ohci->intr_status & ohci->intr))
-        level = 1;
-
-    qemu_set_irq(ohci->irq, level);
-}
-
-/* Set an interrupt */
-static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
-{
-    ohci->intr_status |= intr;
-    ohci_intr_update(ohci);
+    ohci->ohci_die(ohci);
 }
 
 /* Attach or detach a device on a root hub port.  */
@@ -426,7 +332,7 @@ static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
     return NULL;
 }
 
-static void ohci_stop_endpoints(OHCIState *ohci)
+void ohci_stop_endpoints(OHCIState *ohci)
 {
     USBDevice *dev;
     int i, j;
@@ -498,7 +404,7 @@ static void ohci_soft_reset(OHCIState *ohci)
     ohci->lst = OHCI_LS_THRESH;
 }
 
-static void ohci_hard_reset(OHCIState *ohci)
+void ohci_hard_reset(OHCIState *ohci)
 {
     ohci_soft_reset(ohci);
     ohci->ctl = 0;
@@ -1372,7 +1278,7 @@ static int ohci_bus_start(OHCIState *ohci)
 }
 
 /* Stop sending SOF tokens on the bus */
-static void ohci_bus_stop(OHCIState *ohci)
+void ohci_bus_stop(OHCIState *ohci)
 {
     trace_usb_ohci_stop(ohci->name);
     timer_del(ohci->eof_timer);
@@ -1852,15 +1758,16 @@ static USBPortOps ohci_port_ops = {
 static USBBusOps ohci_bus_ops = {
 };
 
-static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
-                          uint32_t num_ports, dma_addr_t localmem_base,
-                          char *masterbus, uint32_t firstport,
-                          AddressSpace *as, Error **errp)
+void usb_ohci_init(OHCIState *ohci, DeviceState *dev, uint32_t num_ports,
+                   dma_addr_t localmem_base, char *masterbus,
+                   uint32_t firstport, AddressSpace *as,
+                   void (*ohci_die_func)(OHCIState *ohci), Error **errp)
 {
     Error *err = NULL;
     int i;
 
     ohci->as = as;
+    ohci->ohci_die = ohci_die_func;
 
     if (num_ports > OHCI_MAX_PORTS) {
         error_setg(errp, "OHCI num-ports=%u is too big (limit is %u ports)",
@@ -1919,85 +1826,16 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
                                    ohci_frame_boundary, ohci);
 }
 
-#define TYPE_PCI_OHCI "pci-ohci"
-#define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI)
-
-typedef struct {
-    /*< private >*/
-    PCIDevice parent_obj;
-    /*< public >*/
-
-    OHCIState state;
-    char *masterbus;
-    uint32_t num_ports;
-    uint32_t firstport;
-} OHCIPCIState;
-
-/** A typical O/EHCI will stop operating, set itself into error state
- * (which can be queried by MMIO) and will set PERR in its config
- * space to signal that it got an error
+/**
+ * A typical O/EHCI will stop operating, set itself into error state
+ * (which can be queried by MMIO) to signal that it got an error
  */
-static void ohci_die(OHCIState *ohci)
+static void ohci_sysbus_die(OHCIState *ohci)
 {
-    OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state);
-
     trace_usb_ohci_die();
 
     ohci_set_interrupt(ohci, OHCI_INTR_UE);
     ohci_bus_stop(ohci);
-    pci_set_word(dev->parent_obj.config + PCI_STATUS,
-                 PCI_STATUS_DETECTED_PARITY);
-}
-
-static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp)
-{
-    Error *err = NULL;
-    OHCIPCIState *ohci = PCI_OHCI(dev);
-
-    dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */
-    dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
-
-    usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0,
-                  ohci->masterbus, ohci->firstport,
-                  pci_get_address_space(dev), &err);
-    if (err) {
-        error_propagate(errp, err);
-        return;
-    }
-
-    ohci->state.irq = pci_allocate_irq(dev);
-    pci_register_bar(dev, 0, 0, &ohci->state.mem);
-}
-
-static void usb_ohci_exit(PCIDevice *dev)
-{
-    OHCIPCIState *ohci = PCI_OHCI(dev);
-    OHCIState *s = &ohci->state;
-
-    trace_usb_ohci_exit(s->name);
-    ohci_bus_stop(s);
-
-    if (s->async_td) {
-        usb_cancel_packet(&s->usb_packet);
-        s->async_td = 0;
-    }
-    ohci_stop_endpoints(s);
-
-    if (!ohci->masterbus) {
-        usb_bus_release(&s->bus);
-    }
-
-    timer_del(s->eof_timer);
-    timer_free(s->eof_timer);
-}
-
-static void usb_ohci_reset_pci(DeviceState *d)
-{
-    PCIDevice *dev = PCI_DEVICE(d);
-    OHCIPCIState *ohci = PCI_OHCI(dev);
-    OHCIState *s = &ohci->state;
-
-    ohci_hard_reset(s);
 }
 
 #define TYPE_SYSBUS_OHCI "sysbus-ohci"
@@ -2023,7 +1861,7 @@ static void ohci_realize_pxa(DeviceState *dev, Error **errp)
 
     usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset,
                   s->masterbus, s->firstport,
-                  &address_space_memory, &err);
+                  &address_space_memory, ohci_sysbus_die, &err);
     if (err) {
         error_propagate(errp, err);
         return;
@@ -2040,13 +1878,6 @@ static void usb_ohci_reset_sysbus(DeviceState *dev)
     ohci_hard_reset(ohci);
 }
 
-static Property ohci_pci_properties[] = {
-    DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
-    DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
-    DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
-    DEFINE_PROP_END_OF_LIST(),
-};
-
 static const VMStateDescription vmstate_ohci_state_port = {
     .name = "ohci-core/port",
     .version_id = 1,
@@ -2075,7 +1906,7 @@ static const VMStateDescription vmstate_ohci_eof_timer = {
     },
 };
 
-static const VMStateDescription vmstate_ohci_state = {
+const VMStateDescription vmstate_ohci_state = {
     .name = "ohci-core",
     .version_id = 1,
     .minimum_version_id = 1,
@@ -2122,46 +1953,6 @@ static const VMStateDescription vmstate_ohci_state = {
     }
 };
 
-static const VMStateDescription vmstate_ohci = {
-    .name = "ohci",
-    .version_id = 1,
-    .minimum_version_id = 1,
-    .fields = (VMStateField[]) {
-        VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState),
-        VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState),
-        VMSTATE_END_OF_LIST()
-    }
-};
-
-static void ohci_pci_class_init(ObjectClass *klass, void *data)
-{
-    DeviceClass *dc = DEVICE_CLASS(klass);
-    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
-
-    k->realize = usb_ohci_realize_pci;
-    k->exit = usb_ohci_exit;
-    k->vendor_id = PCI_VENDOR_ID_APPLE;
-    k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
-    k->class_id = PCI_CLASS_SERIAL_USB;
-    set_bit(DEVICE_CATEGORY_USB, dc->categories);
-    dc->desc = "Apple USB Controller";
-    dc->props = ohci_pci_properties;
-    dc->hotpluggable = false;
-    dc->vmsd = &vmstate_ohci;
-    dc->reset = usb_ohci_reset_pci;
-}
-
-static const TypeInfo ohci_pci_info = {
-    .name          = TYPE_PCI_OHCI,
-    .parent        = TYPE_PCI_DEVICE,
-    .instance_size = sizeof(OHCIPCIState),
-    .class_init    = ohci_pci_class_init,
-    .interfaces = (InterfaceInfo[]) {
-        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
-        { },
-    },
-};
-
 static Property ohci_sysbus_properties[] = {
     DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus),
     DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
@@ -2190,7 +1981,6 @@ static const TypeInfo ohci_sysbus_info = {
 
 static void ohci_register_types(void)
 {
-    type_register_static(&ohci_pci_info);
     type_register_static(&ohci_sysbus_info);
 }
 
diff --git a/hw/usb/hcd-ohci.h b/hw/usb/hcd-ohci.h
new file mode 100644
index 0000000000..481ceba7ff
--- /dev/null
+++ b/hw/usb/hcd-ohci.h
@@ -0,0 +1,132 @@
+/*
+ * QEMU USB OHCI Emulation
+ * Copyright (c) 2004 Gianni Tedesco
+ * Copyright (c) 2006 CodeSourcery
+ * Copyright (c) 2006 Openedhand Ltd.
+ *
+ * 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.1 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 Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HCD_OHCI_H
+#define HCD_OHCI_H
+
+#include "sysemu/dma.h"
+
+/* Number of Downstream Ports on the root hub: */
+#define OHCI_MAX_PORTS 15
+
+typedef struct OHCIPort {
+    USBPort port;
+    uint32_t ctrl;
+} OHCIPort;
+
+typedef struct OHCIState {
+    USBBus bus;
+    qemu_irq irq;
+    MemoryRegion mem;
+    AddressSpace *as;
+    uint32_t num_ports;
+    const char *name;
+
+    QEMUTimer *eof_timer;
+    int64_t sof_time;
+
+    /* OHCI state */
+    /* Control partition */
+    uint32_t ctl, status;
+    uint32_t intr_status;
+    uint32_t intr;
+
+    /* memory pointer partition */
+    uint32_t hcca;
+    uint32_t ctrl_head, ctrl_cur;
+    uint32_t bulk_head, bulk_cur;
+    uint32_t per_cur;
+    uint32_t done;
+    int32_t done_count;
+
+    /* Frame counter partition */
+    uint16_t fsmps;
+    uint8_t fit;
+    uint16_t fi;
+    uint8_t frt;
+    uint16_t frame_number;
+    uint16_t padding;
+    uint32_t pstart;
+    uint32_t lst;
+
+    /* Root Hub partition */
+    uint32_t rhdesc_a, rhdesc_b;
+    uint32_t rhstatus;
+    OHCIPort rhport[OHCI_MAX_PORTS];
+
+    /* PXA27x Non-OHCI events */
+    uint32_t hstatus;
+    uint32_t hmask;
+    uint32_t hreset;
+    uint32_t htest;
+
+    /* SM501 local memory offset */
+    dma_addr_t localmem_base;
+
+    /* Active packets.  */
+    uint32_t old_ctl;
+    USBPacket usb_packet;
+    uint8_t usb_buf[8192];
+    uint32_t async_td;
+    bool async_complete;
+
+    void (*ohci_die)(struct OHCIState *ohci);
+} OHCIState;
+
+extern const VMStateDescription vmstate_ohci_state;
+
+#define OHCI_INTR_SO          (1U << 0)   /* Scheduling overrun */
+#define OHCI_INTR_WD          (1U << 1)   /* HcDoneHead writeback */
+#define OHCI_INTR_SF          (1U << 2)   /* Start of frame */
+#define OHCI_INTR_RD          (1U << 3)   /* Resume detect */
+#define OHCI_INTR_UE          (1U << 4)   /* Unrecoverable error */
+#define OHCI_INTR_FNO         (1U << 5)   /* Frame number overflow */
+#define OHCI_INTR_RHSC        (1U << 6)   /* Root hub status change */
+#define OHCI_INTR_OC          (1U << 30)  /* Ownership change */
+#define OHCI_INTR_MIE         (1U << 31)  /* Master Interrupt Enable */
+
+/* Update IRQ levels */
+static inline void ohci_intr_update(OHCIState *ohci)
+{
+    int level = 0;
+
+    if ((ohci->intr & OHCI_INTR_MIE) &&
+        (ohci->intr_status & ohci->intr))
+        level = 1;
+
+    qemu_set_irq(ohci->irq, level);
+}
+
+/* Set an interrupt */
+static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
+{
+    ohci->intr_status |= intr;
+    ohci_intr_update(ohci);
+}
+
+void usb_ohci_init(OHCIState *ohci, DeviceState *dev, uint32_t num_ports,
+                   dma_addr_t localmem_base, char *masterbus,
+                   uint32_t firstport, AddressSpace *as,
+                   void (*ohci_die_func)(OHCIState *ohci), Error **errp);
+void ohci_hard_reset(OHCIState *ohci);
+void ohci_bus_stop(OHCIState *ohci);
+void ohci_stop_endpoints(OHCIState *ohci);
+
+#endif
-- 
2.21.0


Re: [Qemu-devel] [PATCH for-4.1] hw/usb/hcd-ohci: Move PCI-related code into a separate file
Posted by Philippe Mathieu-Daudé 4 years, 11 months ago
Hi Thomas,

On 4/18/19 1:10 PM, Thomas Huth wrote:
> Some machines (like the pxa2xx-based ARM machines) only have a sysbus
> OHCI controller, but no PCI. With the new Kconfig-style build system,
> it will soon be possible to create QEMU binaries that only contain
> such PCI-less machines. However, the two OHCI controllers, for sysbus
> and for PCI, are currently both located in one file, so the PCI code
> is still required for linking here. Move the OHCI-PCI device code
> into a separate file, so that it is possible to use the sysbus OHCI
> device also without the PCI dependency.
> 
> Apart from moving code to a new file (and a new header), this patch
> might also fix one subtle bug: The ohci_die() function always assumed
> to be running with a OHCI-PCI controller and called some PCI-specific
> functions - but if I got the code right, ohci_die() might also get
> called for the sysbus-OHCI device, so it likely failed in that case.
> I've changed this part of the code now, so that there are two ohci_die()
> implementations now, one for sysbus and one for PCI.

Can this be done in 2 patches?

> Signed-off-by: Thomas Huth <thuth@redhat.com>
> ---
>  hw/usb/Kconfig        |   6 +-
>  hw/usb/Makefile.objs  |   1 +
>  hw/usb/hcd-ohci-pci.c | 166 ++++++++++++++++++++++++++++
>  hw/usb/hcd-ohci.c     | 244 +++---------------------------------------
>  hw/usb/hcd-ohci.h     | 132 +++++++++++++++++++++++
>  5 files changed, 321 insertions(+), 228 deletions(-)
>  create mode 100644 hw/usb/hcd-ohci-pci.c
>  create mode 100644 hw/usb/hcd-ohci.h
> 
> diff --git a/hw/usb/Kconfig b/hw/usb/Kconfig
> index a1b7acb12a..564305e283 100644
> --- a/hw/usb/Kconfig
> +++ b/hw/usb/Kconfig
> @@ -8,10 +8,14 @@ config USB_UHCI
>      select USB
>  
>  config USB_OHCI
> +    bool
> +    select USB
> +
> +config USB_OHCI_PCI
>      bool
>      default y if PCI_DEVICES
>      depends on PCI
> -    select USB
> +    select USB_OHCI
>  
>  config USB_EHCI
>      bool
> diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs
> index 2b929649ac..81688f6e70 100644
> --- a/hw/usb/Makefile.objs
> +++ b/hw/usb/Makefile.objs
> @@ -5,6 +5,7 @@ common-obj-$(CONFIG_USB) += desc.o desc-msos.o
>  # usb host adapters
>  common-obj-$(CONFIG_USB_UHCI) += hcd-uhci.o
>  common-obj-$(CONFIG_USB_OHCI) += hcd-ohci.o
> +common-obj-$(CONFIG_USB_OHCI_PCI) += hcd-ohci-pci.o
>  common-obj-$(CONFIG_USB_EHCI) += hcd-ehci.o hcd-ehci-pci.o
>  common-obj-$(CONFIG_USB_EHCI_SYSBUS) += hcd-ehci.o hcd-ehci-sysbus.o
>  common-obj-$(CONFIG_USB_XHCI) += hcd-xhci.o
> diff --git a/hw/usb/hcd-ohci-pci.c b/hw/usb/hcd-ohci-pci.c
> new file mode 100644
> index 0000000000..e972df35c9
> --- /dev/null
> +++ b/hw/usb/hcd-ohci-pci.c
> @@ -0,0 +1,166 @@
> +/*
> + * QEMU USB OHCI Emulation
> + * Copyright (c) 2004 Gianni Tedesco
> + * Copyright (c) 2006 CodeSourcery
> + * Copyright (c) 2006 Openedhand Ltd.
> + *
> + * 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.1 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 Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/hw.h"
> +#include "qapi/error.h"
> +#include "qemu/timer.h"
> +#include "hw/usb.h"
> +#include "hw/pci/pci.h"
> +#include "hw/sysbus.h"
> +#include "hw/qdev-dma.h"
> +#include "trace.h"
> +#include "hcd-ohci.h"
> +
> +#define TYPE_PCI_OHCI "pci-ohci"
> +#define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI)
> +
> +typedef struct {
> +    /*< private >*/
> +    PCIDevice parent_obj;
> +    /*< public >*/
> +
> +    OHCIState state;
> +    char *masterbus;
> +    uint32_t num_ports;
> +    uint32_t firstport;
> +} OHCIPCIState;
> +
> +/**
> + * A typical O/EHCI will stop operating, set itself into error state
> + * (which can be queried by MMIO) and will set PERR in its config
> + * space to signal that it got an error
> + */
> +static void ohci_pci_die(OHCIState *ohci)
> +{
> +    OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state);
> +
> +    trace_usb_ohci_die();
> +
> +    ohci_set_interrupt(ohci, OHCI_INTR_UE);
> +    ohci_bus_stop(ohci);
> +    pci_set_word(dev->parent_obj.config + PCI_STATUS,
> +                 PCI_STATUS_DETECTED_PARITY);
> +}
> +
> +static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp)
> +{
> +    Error *err = NULL;
> +    OHCIPCIState *ohci = PCI_OHCI(dev);
> +
> +    dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */
> +    dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
> +
> +    usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0,
> +                  ohci->masterbus, ohci->firstport,
> +                  pci_get_address_space(dev), ohci_pci_die, &err);
> +    if (err) {
> +        error_propagate(errp, err);
> +        return;
> +    }
> +
> +    ohci->state.irq = pci_allocate_irq(dev);
> +    pci_register_bar(dev, 0, 0, &ohci->state.mem);
> +}
> +
> +static void usb_ohci_exit(PCIDevice *dev)
> +{
> +    OHCIPCIState *ohci = PCI_OHCI(dev);
> +    OHCIState *s = &ohci->state;
> +
> +    trace_usb_ohci_exit(s->name);
> +    ohci_bus_stop(s);
> +
> +    if (s->async_td) {
> +        usb_cancel_packet(&s->usb_packet);
> +        s->async_td = 0;
> +    }
> +    ohci_stop_endpoints(s);
> +
> +    if (!ohci->masterbus) {
> +        usb_bus_release(&s->bus);
> +    }
> +
> +    timer_del(s->eof_timer);
> +    timer_free(s->eof_timer);
> +}
> +
> +static void usb_ohci_reset_pci(DeviceState *d)
> +{
> +    PCIDevice *dev = PCI_DEVICE(d);
> +    OHCIPCIState *ohci = PCI_OHCI(dev);
> +    OHCIState *s = &ohci->state;
> +
> +    ohci_hard_reset(s);
> +}
> +
> +static Property ohci_pci_properties[] = {
> +    DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
> +    DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
> +    DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static const VMStateDescription vmstate_ohci = {
> +    .name = "ohci",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState),
> +        VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void ohci_pci_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> +
> +    k->realize = usb_ohci_realize_pci;
> +    k->exit = usb_ohci_exit;
> +    k->vendor_id = PCI_VENDOR_ID_APPLE;
> +    k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
> +    k->class_id = PCI_CLASS_SERIAL_USB;
> +    set_bit(DEVICE_CATEGORY_USB, dc->categories);
> +    dc->desc = "Apple USB Controller";
> +    dc->props = ohci_pci_properties;
> +    dc->hotpluggable = false;
> +    dc->vmsd = &vmstate_ohci;
> +    dc->reset = usb_ohci_reset_pci;
> +}
> +
> +static const TypeInfo ohci_pci_info = {
> +    .name          = TYPE_PCI_OHCI,
> +    .parent        = TYPE_PCI_DEVICE,
> +    .instance_size = sizeof(OHCIPCIState),
> +    .class_init    = ohci_pci_class_init,
> +    .interfaces = (InterfaceInfo[]) {
> +        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> +        { },
> +    },
> +};
> +
> +static void ohci_pci_register_types(void)
> +{
> +    type_register_static(&ohci_pci_info);
> +}
> +
> +type_init(ohci_pci_register_types)
> diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
> index 81cf5ab7a5..343816d561 100644
> --- a/hw/usb/hcd-ohci.c
> +++ b/hw/usb/hcd-ohci.c
> @@ -30,86 +30,19 @@
>  #include "qapi/error.h"
>  #include "qemu/timer.h"
>  #include "hw/usb.h"
> -#include "hw/pci/pci.h"
>  #include "hw/sysbus.h"
>  #include "hw/qdev-dma.h"
>  #include "trace.h"
> +#include "hcd-ohci.h"
>  
>  /* This causes frames to occur 1000x slower */
>  //#define OHCI_TIME_WARP 1
>  
> -/* Number of Downstream Ports on the root hub.  */
> -
> -#define OHCI_MAX_PORTS 15
> -
>  #define ED_LINK_LIMIT 32
>  
>  static int64_t usb_frame_time;
>  static int64_t usb_bit_time;
>  
> -typedef struct OHCIPort {
> -    USBPort port;
> -    uint32_t ctrl;
> -} OHCIPort;
> -
> -typedef struct {
> -    USBBus bus;
> -    qemu_irq irq;
> -    MemoryRegion mem;
> -    AddressSpace *as;
> -    uint32_t num_ports;
> -    const char *name;
> -
> -    QEMUTimer *eof_timer;
> -    int64_t sof_time;
> -
> -    /* OHCI state */
> -    /* Control partition */
> -    uint32_t ctl, status;
> -    uint32_t intr_status;
> -    uint32_t intr;
> -
> -    /* memory pointer partition */
> -    uint32_t hcca;
> -    uint32_t ctrl_head, ctrl_cur;
> -    uint32_t bulk_head, bulk_cur;
> -    uint32_t per_cur;
> -    uint32_t done;
> -    int32_t done_count;
> -
> -    /* Frame counter partition */
> -    uint16_t fsmps;
> -    uint8_t fit;
> -    uint16_t fi;
> -    uint8_t frt;
> -    uint16_t frame_number;
> -    uint16_t padding;
> -    uint32_t pstart;
> -    uint32_t lst;
> -
> -    /* Root Hub partition */
> -    uint32_t rhdesc_a, rhdesc_b;
> -    uint32_t rhstatus;
> -    OHCIPort rhport[OHCI_MAX_PORTS];
> -
> -    /* PXA27x Non-OHCI events */
> -    uint32_t hstatus;
> -    uint32_t hmask;
> -    uint32_t hreset;
> -    uint32_t htest;
> -
> -    /* SM501 local memory offset */
> -    dma_addr_t localmem_base;
> -
> -    /* Active packets.  */
> -    uint32_t old_ctl;
> -    USBPacket usb_packet;
> -    uint8_t usb_buf[8192];
> -    uint32_t async_td;
> -    bool async_complete;
> -
> -} OHCIState;
> -
>  /* Host Controller Communications Area */
>  struct ohci_hcca {
>      uint32_t intr[32];
> @@ -122,7 +55,6 @@ struct ohci_hcca {
>  #define ED_WBACK_OFFSET offsetof(struct ohci_ed, head)
>  #define ED_WBACK_SIZE   4
>  
> -static void ohci_bus_stop(OHCIState *ohci);
>  static void ohci_async_cancel_device(OHCIState *ohci, USBDevice *dev);
>  
>  /* Bitfields for the first word of an Endpoint Desciptor.  */
> @@ -229,16 +161,6 @@ struct ohci_iso_td {
>  #define OHCI_STATUS_OCR       (1<<3)
>  #define OHCI_STATUS_SOC       ((1<<6)|(1<<7))
>  
> -#define OHCI_INTR_SO          (1U<<0) /* Scheduling overrun */
> -#define OHCI_INTR_WD          (1U<<1) /* HcDoneHead writeback */
> -#define OHCI_INTR_SF          (1U<<2) /* Start of frame */
> -#define OHCI_INTR_RD          (1U<<3) /* Resume detect */
> -#define OHCI_INTR_UE          (1U<<4) /* Unrecoverable error */
> -#define OHCI_INTR_FNO         (1U<<5) /* Frame number overflow */
> -#define OHCI_INTR_RHSC        (1U<<6) /* Root hub status change */
> -#define OHCI_INTR_OC          (1U<<30) /* Ownership change */
> -#define OHCI_INTR_MIE         (1U<<31) /* Master Interrupt Enable */
> -
>  #define OHCI_HCCA_SIZE        0x100
>  #define OHCI_HCCA_MASK        0xffffff00
>  
> @@ -302,25 +224,9 @@ struct ohci_iso_td {
>  
>  #define OHCI_HRESET_FSBIR       (1 << 0)
>  
> -static void ohci_die(OHCIState *ohci);
> -
> -/* Update IRQ levels */
> -static inline void ohci_intr_update(OHCIState *ohci)
> +static inline void ohci_die(OHCIState *ohci)
>  {
> -    int level = 0;
> -
> -    if ((ohci->intr & OHCI_INTR_MIE) &&
> -        (ohci->intr_status & ohci->intr))
> -        level = 1;
> -
> -    qemu_set_irq(ohci->irq, level);
> -}
> -
> -/* Set an interrupt */
> -static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
> -{
> -    ohci->intr_status |= intr;
> -    ohci_intr_update(ohci);
> +    ohci->ohci_die(ohci);
>  }
>  
>  /* Attach or detach a device on a root hub port.  */
> @@ -426,7 +332,7 @@ static USBDevice *ohci_find_device(OHCIState *ohci, uint8_t addr)
>      return NULL;
>  }
>  
> -static void ohci_stop_endpoints(OHCIState *ohci)
> +void ohci_stop_endpoints(OHCIState *ohci)
>  {
>      USBDevice *dev;
>      int i, j;
> @@ -498,7 +404,7 @@ static void ohci_soft_reset(OHCIState *ohci)
>      ohci->lst = OHCI_LS_THRESH;
>  }
>  
> -static void ohci_hard_reset(OHCIState *ohci)
> +void ohci_hard_reset(OHCIState *ohci)
>  {
>      ohci_soft_reset(ohci);
>      ohci->ctl = 0;
> @@ -1372,7 +1278,7 @@ static int ohci_bus_start(OHCIState *ohci)
>  }
>  
>  /* Stop sending SOF tokens on the bus */
> -static void ohci_bus_stop(OHCIState *ohci)
> +void ohci_bus_stop(OHCIState *ohci)
>  {
>      trace_usb_ohci_stop(ohci->name);
>      timer_del(ohci->eof_timer);
> @@ -1852,15 +1758,16 @@ static USBPortOps ohci_port_ops = {
>  static USBBusOps ohci_bus_ops = {
>  };
>  
> -static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
> -                          uint32_t num_ports, dma_addr_t localmem_base,
> -                          char *masterbus, uint32_t firstport,
> -                          AddressSpace *as, Error **errp)
> +void usb_ohci_init(OHCIState *ohci, DeviceState *dev, uint32_t num_ports,
> +                   dma_addr_t localmem_base, char *masterbus,
> +                   uint32_t firstport, AddressSpace *as,
> +                   void (*ohci_die_func)(OHCIState *ohci), Error **errp)
>  {
>      Error *err = NULL;
>      int i;
>  
>      ohci->as = as;
> +    ohci->ohci_die = ohci_die_func;
>  
>      if (num_ports > OHCI_MAX_PORTS) {
>          error_setg(errp, "OHCI num-ports=%u is too big (limit is %u ports)",
> @@ -1919,85 +1826,16 @@ static void usb_ohci_init(OHCIState *ohci, DeviceState *dev,
>                                     ohci_frame_boundary, ohci);
>  }
>  
> -#define TYPE_PCI_OHCI "pci-ohci"
> -#define PCI_OHCI(obj) OBJECT_CHECK(OHCIPCIState, (obj), TYPE_PCI_OHCI)
> -
> -typedef struct {
> -    /*< private >*/
> -    PCIDevice parent_obj;
> -    /*< public >*/
> -
> -    OHCIState state;
> -    char *masterbus;
> -    uint32_t num_ports;
> -    uint32_t firstport;
> -} OHCIPCIState;
> -
> -/** A typical O/EHCI will stop operating, set itself into error state
> - * (which can be queried by MMIO) and will set PERR in its config
> - * space to signal that it got an error
> +/**
> + * A typical O/EHCI will stop operating, set itself into error state
> + * (which can be queried by MMIO) to signal that it got an error
>   */
> -static void ohci_die(OHCIState *ohci)
> +static void ohci_sysbus_die(OHCIState *ohci)
>  {
> -    OHCIPCIState *dev = container_of(ohci, OHCIPCIState, state);
> -
>      trace_usb_ohci_die();
>  
>      ohci_set_interrupt(ohci, OHCI_INTR_UE);
>      ohci_bus_stop(ohci);
> -    pci_set_word(dev->parent_obj.config + PCI_STATUS,
> -                 PCI_STATUS_DETECTED_PARITY);
> -}
> -
> -static void usb_ohci_realize_pci(PCIDevice *dev, Error **errp)
> -{
> -    Error *err = NULL;
> -    OHCIPCIState *ohci = PCI_OHCI(dev);
> -
> -    dev->config[PCI_CLASS_PROG] = 0x10; /* OHCI */
> -    dev->config[PCI_INTERRUPT_PIN] = 0x01; /* interrupt pin A */
> -
> -    usb_ohci_init(&ohci->state, DEVICE(dev), ohci->num_ports, 0,
> -                  ohci->masterbus, ohci->firstport,
> -                  pci_get_address_space(dev), &err);
> -    if (err) {
> -        error_propagate(errp, err);
> -        return;
> -    }
> -
> -    ohci->state.irq = pci_allocate_irq(dev);
> -    pci_register_bar(dev, 0, 0, &ohci->state.mem);
> -}
> -
> -static void usb_ohci_exit(PCIDevice *dev)
> -{
> -    OHCIPCIState *ohci = PCI_OHCI(dev);
> -    OHCIState *s = &ohci->state;
> -
> -    trace_usb_ohci_exit(s->name);
> -    ohci_bus_stop(s);
> -
> -    if (s->async_td) {
> -        usb_cancel_packet(&s->usb_packet);
> -        s->async_td = 0;
> -    }
> -    ohci_stop_endpoints(s);
> -
> -    if (!ohci->masterbus) {
> -        usb_bus_release(&s->bus);
> -    }
> -
> -    timer_del(s->eof_timer);
> -    timer_free(s->eof_timer);
> -}
> -
> -static void usb_ohci_reset_pci(DeviceState *d)
> -{
> -    PCIDevice *dev = PCI_DEVICE(d);
> -    OHCIPCIState *ohci = PCI_OHCI(dev);
> -    OHCIState *s = &ohci->state;
> -
> -    ohci_hard_reset(s);
>  }
>  
>  #define TYPE_SYSBUS_OHCI "sysbus-ohci"
> @@ -2023,7 +1861,7 @@ static void ohci_realize_pxa(DeviceState *dev, Error **errp)
>  
>      usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset,
>                    s->masterbus, s->firstport,
> -                  &address_space_memory, &err);
> +                  &address_space_memory, ohci_sysbus_die, &err);
>      if (err) {
>          error_propagate(errp, err);
>          return;
> @@ -2040,13 +1878,6 @@ static void usb_ohci_reset_sysbus(DeviceState *dev)
>      ohci_hard_reset(ohci);
>  }
>  
> -static Property ohci_pci_properties[] = {
> -    DEFINE_PROP_STRING("masterbus", OHCIPCIState, masterbus),
> -    DEFINE_PROP_UINT32("num-ports", OHCIPCIState, num_ports, 3),
> -    DEFINE_PROP_UINT32("firstport", OHCIPCIState, firstport, 0),
> -    DEFINE_PROP_END_OF_LIST(),
> -};
> -
>  static const VMStateDescription vmstate_ohci_state_port = {
>      .name = "ohci-core/port",
>      .version_id = 1,
> @@ -2075,7 +1906,7 @@ static const VMStateDescription vmstate_ohci_eof_timer = {
>      },
>  };
>  
> -static const VMStateDescription vmstate_ohci_state = {
> +const VMStateDescription vmstate_ohci_state = {
>      .name = "ohci-core",
>      .version_id = 1,
>      .minimum_version_id = 1,
> @@ -2122,46 +1953,6 @@ static const VMStateDescription vmstate_ohci_state = {
>      }
>  };
>  
> -static const VMStateDescription vmstate_ohci = {
> -    .name = "ohci",
> -    .version_id = 1,
> -    .minimum_version_id = 1,
> -    .fields = (VMStateField[]) {
> -        VMSTATE_PCI_DEVICE(parent_obj, OHCIPCIState),
> -        VMSTATE_STRUCT(state, OHCIPCIState, 1, vmstate_ohci_state, OHCIState),
> -        VMSTATE_END_OF_LIST()
> -    }
> -};
> -
> -static void ohci_pci_class_init(ObjectClass *klass, void *data)
> -{
> -    DeviceClass *dc = DEVICE_CLASS(klass);
> -    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
> -
> -    k->realize = usb_ohci_realize_pci;
> -    k->exit = usb_ohci_exit;
> -    k->vendor_id = PCI_VENDOR_ID_APPLE;
> -    k->device_id = PCI_DEVICE_ID_APPLE_IPID_USB;
> -    k->class_id = PCI_CLASS_SERIAL_USB;
> -    set_bit(DEVICE_CATEGORY_USB, dc->categories);
> -    dc->desc = "Apple USB Controller";
> -    dc->props = ohci_pci_properties;
> -    dc->hotpluggable = false;
> -    dc->vmsd = &vmstate_ohci;
> -    dc->reset = usb_ohci_reset_pci;
> -}
> -
> -static const TypeInfo ohci_pci_info = {
> -    .name          = TYPE_PCI_OHCI,
> -    .parent        = TYPE_PCI_DEVICE,
> -    .instance_size = sizeof(OHCIPCIState),
> -    .class_init    = ohci_pci_class_init,
> -    .interfaces = (InterfaceInfo[]) {
> -        { INTERFACE_CONVENTIONAL_PCI_DEVICE },
> -        { },
> -    },
> -};
> -
>  static Property ohci_sysbus_properties[] = {
>      DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus),
>      DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3),
> @@ -2190,7 +1981,6 @@ static const TypeInfo ohci_sysbus_info = {
>  
>  static void ohci_register_types(void)
>  {
> -    type_register_static(&ohci_pci_info);
>      type_register_static(&ohci_sysbus_info);
>  }
>  
> diff --git a/hw/usb/hcd-ohci.h b/hw/usb/hcd-ohci.h
> new file mode 100644
> index 0000000000..481ceba7ff
> --- /dev/null
> +++ b/hw/usb/hcd-ohci.h
> @@ -0,0 +1,132 @@
> +/*
> + * QEMU USB OHCI Emulation
> + * Copyright (c) 2004 Gianni Tedesco
> + * Copyright (c) 2006 CodeSourcery
> + * Copyright (c) 2006 Openedhand Ltd.
> + *
> + * 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.1 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 Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef HCD_OHCI_H
> +#define HCD_OHCI_H
> +
> +#include "sysemu/dma.h"
> +
> +/* Number of Downstream Ports on the root hub: */
> +#define OHCI_MAX_PORTS 15
> +
> +typedef struct OHCIPort {
> +    USBPort port;
> +    uint32_t ctrl;
> +} OHCIPort;
> +
> +typedef struct OHCIState {
> +    USBBus bus;
> +    qemu_irq irq;
> +    MemoryRegion mem;
> +    AddressSpace *as;
> +    uint32_t num_ports;
> +    const char *name;
> +
> +    QEMUTimer *eof_timer;
> +    int64_t sof_time;
> +
> +    /* OHCI state */
> +    /* Control partition */
> +    uint32_t ctl, status;
> +    uint32_t intr_status;
> +    uint32_t intr;
> +
> +    /* memory pointer partition */
> +    uint32_t hcca;
> +    uint32_t ctrl_head, ctrl_cur;
> +    uint32_t bulk_head, bulk_cur;
> +    uint32_t per_cur;
> +    uint32_t done;
> +    int32_t done_count;
> +
> +    /* Frame counter partition */
> +    uint16_t fsmps;
> +    uint8_t fit;
> +    uint16_t fi;
> +    uint8_t frt;
> +    uint16_t frame_number;
> +    uint16_t padding;
> +    uint32_t pstart;
> +    uint32_t lst;
> +
> +    /* Root Hub partition */
> +    uint32_t rhdesc_a, rhdesc_b;
> +    uint32_t rhstatus;
> +    OHCIPort rhport[OHCI_MAX_PORTS];
> +
> +    /* PXA27x Non-OHCI events */
> +    uint32_t hstatus;
> +    uint32_t hmask;
> +    uint32_t hreset;
> +    uint32_t htest;
> +
> +    /* SM501 local memory offset */
> +    dma_addr_t localmem_base;
> +
> +    /* Active packets.  */
> +    uint32_t old_ctl;
> +    USBPacket usb_packet;
> +    uint8_t usb_buf[8192];
> +    uint32_t async_td;
> +    bool async_complete;
> +
> +    void (*ohci_die)(struct OHCIState *ohci);
> +} OHCIState;
> +
> +extern const VMStateDescription vmstate_ohci_state;
> +
> +#define OHCI_INTR_SO          (1U << 0)   /* Scheduling overrun */
> +#define OHCI_INTR_WD          (1U << 1)   /* HcDoneHead writeback */
> +#define OHCI_INTR_SF          (1U << 2)   /* Start of frame */
> +#define OHCI_INTR_RD          (1U << 3)   /* Resume detect */
> +#define OHCI_INTR_UE          (1U << 4)   /* Unrecoverable error */
> +#define OHCI_INTR_FNO         (1U << 5)   /* Frame number overflow */
> +#define OHCI_INTR_RHSC        (1U << 6)   /* Root hub status change */
> +#define OHCI_INTR_OC          (1U << 30)  /* Ownership change */
> +#define OHCI_INTR_MIE         (1U << 31)  /* Master Interrupt Enable */
> +
> +/* Update IRQ levels */
> +static inline void ohci_intr_update(OHCIState *ohci)
> +{
> +    int level = 0;
> +
> +    if ((ohci->intr & OHCI_INTR_MIE) &&
> +        (ohci->intr_status & ohci->intr))
> +        level = 1;
> +
> +    qemu_set_irq(ohci->irq, level);
> +}
> +
> +/* Set an interrupt */
> +static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr)
> +{
> +    ohci->intr_status |= intr;
> +    ohci_intr_update(ohci);
> +}
> +
> +void usb_ohci_init(OHCIState *ohci, DeviceState *dev, uint32_t num_ports,
> +                   dma_addr_t localmem_base, char *masterbus,
> +                   uint32_t firstport, AddressSpace *as,
> +                   void (*ohci_die_func)(OHCIState *ohci), Error **errp);
> +void ohci_hard_reset(OHCIState *ohci);
> +void ohci_bus_stop(OHCIState *ohci);
> +void ohci_stop_endpoints(OHCIState *ohci);
> +
> +#endif
> 

Re: [Qemu-devel] [PATCH for-4.1] hw/usb/hcd-ohci: Move PCI-related code into a separate file
Posted by Thomas Huth 4 years, 11 months ago
On 18/04/2019 14.35, Philippe Mathieu-Daudé wrote:
> Hi Thomas,
> 
> On 4/18/19 1:10 PM, Thomas Huth wrote:
>> Some machines (like the pxa2xx-based ARM machines) only have a sysbus
>> OHCI controller, but no PCI. With the new Kconfig-style build system,
>> it will soon be possible to create QEMU binaries that only contain
>> such PCI-less machines. However, the two OHCI controllers, for sysbus
>> and for PCI, are currently both located in one file, so the PCI code
>> is still required for linking here. Move the OHCI-PCI device code
>> into a separate file, so that it is possible to use the sysbus OHCI
>> device also without the PCI dependency.
>>
>> Apart from moving code to a new file (and a new header), this patch
>> might also fix one subtle bug: The ohci_die() function always assumed
>> to be running with a OHCI-PCI controller and called some PCI-specific
>> functions - but if I got the code right, ohci_die() might also get
>> called for the sysbus-OHCI device, so it likely failed in that case.
>> I've changed this part of the code now, so that there are two ohci_die()
>> implementations now, one for sysbus and one for PCI.
> 
> Can this be done in 2 patches?

Yeah, maybe that's cleaner... I'll send a v2...

 Thomas