xhci: add qemu-xhci device, some followup cleanups.
ccid: better sanity checking. ehci: fix memory leak ohci: bugfixes. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJYq+jbAAoJEEy22O7T6HE4gukP/jqP9SxKcZyEIFalmnOzR+Wq 5N20ZRuAJXAFEWG+FLOz+TC9tYCJ3IEpDwkEEtlFXdZgc8SF+YlOhWLRvTHSQYfy LZbYgoQnRsE+kpYVaADJ+lGYGRM/RjPPLkt54FF6SDX9jtNbv7nSyIvTXHkNrjZd cnGxCy4yu4S1kXhCURhkHiK8SjloexrwwtkfLfOVApFIpXcfb2enWIN79pbb6a1I 8GdYaTedQtr+//FasDagFWpHgpCiknA0A4C+C0E7tGtBkGa1IIoq0RB/82ZApoNB r8aM7SwhjsrRLGniIQNxXK93I5TX2SjHYeeIt37yvI89h5NAk6nzW6Dk9UbAWITq YOm9xOD27d8PtsBuEa9cVB2NJv5rflGyl+dsP0VbwKmhzMS/NU44cCLkcpDXsaIp R09vIuCCBoAyae9IgrFty6wJrpv2HmuLUCJelU3lOBSCGihSBCjTlLLnzSEkXV6o 9b+sfPTC5/d1U2sivCW7T0LxqIgyFew76NGdSO5Y86CqB+sYEQv3kwR6zcV/3WlE DonQLAPMtDdFwAoR/Aww7dhsNSMERYDz76xg6P7+FgbwG59iGzcqNkpsMyAAOvSS wVl1RkAm2Ln3Vo4re9fQJtWF/MLeDnZe7I1SQJdXF5NcRWCEPLd8tK+WFeg9HcPD 99jIUosbJ2prKtcKkNhI =5lEp -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/pull-usb-20170221-1' into staging xhci: add qemu-xhci device, some followup cleanups. ccid: better sanity checking. ehci: fix memory leak ohci: bugfixes. # gpg: Signature made Tue 21 Feb 2017 07:14:35 GMT # gpg: using RSA key 0x4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/pull-usb-20170221-1: usb-ccid: add check message size checks usb-ccid: move header size check usb-ccid: better bulk_out error handling xhci: drop via vendor command handling xhci: fix nec vendor quirk handling xhci: add qemu xhci controller xhci: drop ER_FULL_HACK workaround xhci: apply limits to loops usb: ohci: limit the number of link eds usb: ohci: fix error return code in servicing iso td usb: ehci: fix memory leak in ehci Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
		
						commit
						b856256179
					
				@ -61,6 +61,7 @@ PCI devices (other than virtio):
 | 
				
			|||||||
1b36:0009  PCI Expander Bridge (-device pxb)
 | 
					1b36:0009  PCI Expander Bridge (-device pxb)
 | 
				
			||||||
1b36:000a  PCI-PCI bridge (multiseat)
 | 
					1b36:000a  PCI-PCI bridge (multiseat)
 | 
				
			||||||
1b36:000b  PCIe Expander Bridge (-device pxb-pcie)
 | 
					1b36:000b  PCIe Expander Bridge (-device pxb-pcie)
 | 
				
			||||||
 | 
					1b36:000d  PCI xhci usb host adapter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
All these devices are documented in docs/specs.
 | 
					All these devices are documented in docs/specs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1001,23 +1001,30 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
 | 
				
			|||||||
    CCID_Header *ccid_header;
 | 
					    CCID_Header *ccid_header;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
 | 
					    if (p->iov.size + s->bulk_out_pos > BULK_OUT_DATA_SIZE) {
 | 
				
			||||||
        p->status = USB_RET_STALL;
 | 
					        goto err;
 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    ccid_header = (CCID_Header *)s->bulk_out_data;
 | 
					 | 
				
			||||||
    usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
 | 
					    usb_packet_copy(p, s->bulk_out_data + s->bulk_out_pos, p->iov.size);
 | 
				
			||||||
    s->bulk_out_pos += p->iov.size;
 | 
					    s->bulk_out_pos += p->iov.size;
 | 
				
			||||||
    if (p->iov.size == CCID_MAX_PACKET_SIZE) {
 | 
					    if (s->bulk_out_pos < 10) {
 | 
				
			||||||
 | 
					        DPRINTF(s, 1, "%s: header incomplete\n", __func__);
 | 
				
			||||||
 | 
					        goto err;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ccid_header = (CCID_Header *)s->bulk_out_data;
 | 
				
			||||||
 | 
					    if ((s->bulk_out_pos - 10 < ccid_header->dwLength) &&
 | 
				
			||||||
 | 
					        (p->iov.size == CCID_MAX_PACKET_SIZE)) {
 | 
				
			||||||
        DPRINTF(s, D_VERBOSE,
 | 
					        DPRINTF(s, D_VERBOSE,
 | 
				
			||||||
            "usb-ccid: bulk_in: expecting more packets (%zd/%d)\n",
 | 
					                "usb-ccid: bulk_in: expecting more packets (%d/%d)\n",
 | 
				
			||||||
            p->iov.size, ccid_header->dwLength);
 | 
					                s->bulk_out_pos - 10, ccid_header->dwLength);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (s->bulk_out_pos < 10) {
 | 
					    if (s->bulk_out_pos - 10 != ccid_header->dwLength) {
 | 
				
			||||||
        DPRINTF(s, 1,
 | 
					        DPRINTF(s, 1,
 | 
				
			||||||
                "%s: bad USB_TOKEN_OUT length, should be at least 10 bytes\n",
 | 
					                "usb-ccid: bulk_in: message size mismatch (got %d, expected %d)\n",
 | 
				
			||||||
                __func__);
 | 
					                s->bulk_out_pos - 10, ccid_header->dwLength);
 | 
				
			||||||
    } else {
 | 
					        goto err;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DPRINTF(s, D_MORE_INFO, "%s %x %s\n", __func__,
 | 
					    DPRINTF(s, D_MORE_INFO, "%s %x %s\n", __func__,
 | 
				
			||||||
            ccid_header->bMessageType,
 | 
					            ccid_header->bMessageType,
 | 
				
			||||||
            ccid_message_type_to_str(ccid_header->bMessageType));
 | 
					            ccid_message_type_to_str(ccid_header->bMessageType));
 | 
				
			||||||
@ -1073,8 +1080,13 @@ static void ccid_handle_bulk_out(USBCCIDState *s, USBPacket *p)
 | 
				
			|||||||
        ccid_write_slot_status(s, ccid_header);
 | 
					        ccid_write_slot_status(s, ccid_header);
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    s->bulk_out_pos = 0;
 | 
					    s->bulk_out_pos = 0;
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err:
 | 
				
			||||||
 | 
					    p->status = USB_RET_STALL;
 | 
				
			||||||
 | 
					    s->bulk_out_pos = 0;
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
 | 
					static void ccid_bulk_in_copy_to_guest(USBCCIDState *s, USBPacket *p)
 | 
				
			||||||
 | 
				
			|||||||
@ -89,6 +89,14 @@ static void usb_ehci_pci_init(Object *obj)
 | 
				
			|||||||
    usb_ehci_init(s, DEVICE(obj));
 | 
					    usb_ehci_init(s, DEVICE(obj));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void usb_ehci_pci_finalize(Object *obj)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    EHCIPCIState *i = PCI_EHCI(obj);
 | 
				
			||||||
 | 
					    EHCIState *s = &i->ehci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    usb_ehci_finalize(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void usb_ehci_pci_exit(PCIDevice *dev)
 | 
					static void usb_ehci_pci_exit(PCIDevice *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    EHCIPCIState *i = PCI_EHCI(dev);
 | 
					    EHCIPCIState *i = PCI_EHCI(dev);
 | 
				
			||||||
@ -159,6 +167,7 @@ static const TypeInfo ehci_pci_type_info = {
 | 
				
			|||||||
    .parent = TYPE_PCI_DEVICE,
 | 
					    .parent = TYPE_PCI_DEVICE,
 | 
				
			||||||
    .instance_size = sizeof(EHCIPCIState),
 | 
					    .instance_size = sizeof(EHCIPCIState),
 | 
				
			||||||
    .instance_init = usb_ehci_pci_init,
 | 
					    .instance_init = usb_ehci_pci_init,
 | 
				
			||||||
 | 
					    .instance_finalize = usb_ehci_pci_finalize,
 | 
				
			||||||
    .abstract = true,
 | 
					    .abstract = true,
 | 
				
			||||||
    .class_init = ehci_class_init,
 | 
					    .class_init = ehci_class_init,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -2545,6 +2545,11 @@ void usb_ehci_init(EHCIState *s, DeviceState *dev)
 | 
				
			|||||||
                                &s->mem_ports);
 | 
					                                &s->mem_ports);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void usb_ehci_finalize(EHCIState *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    usb_packet_cleanup(&s->ipacket);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * vim: expandtab ts=4
 | 
					 * vim: expandtab ts=4
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
				
			|||||||
@ -323,6 +323,7 @@ struct EHCIState {
 | 
				
			|||||||
extern const VMStateDescription vmstate_ehci;
 | 
					extern const VMStateDescription vmstate_ehci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void usb_ehci_init(EHCIState *s, DeviceState *dev);
 | 
					void usb_ehci_init(EHCIState *s, DeviceState *dev);
 | 
				
			||||||
 | 
					void usb_ehci_finalize(EHCIState *s);
 | 
				
			||||||
void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp);
 | 
					void usb_ehci_realize(EHCIState *s, DeviceState *dev, Error **errp);
 | 
				
			||||||
void usb_ehci_unrealize(EHCIState *s, DeviceState *dev, Error **errp);
 | 
					void usb_ehci_unrealize(EHCIState *s, DeviceState *dev, Error **errp);
 | 
				
			||||||
void ehci_reset(void *opaque);
 | 
					void ehci_reset(void *opaque);
 | 
				
			||||||
 | 
				
			|||||||
@ -42,6 +42,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define OHCI_MAX_PORTS 15
 | 
					#define OHCI_MAX_PORTS 15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ED_LINK_LIMIT 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int64_t usb_frame_time;
 | 
					static int64_t usb_frame_time;
 | 
				
			||||||
static int64_t usb_bit_time;
 | 
					static int64_t usb_bit_time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -725,7 +727,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
 | 
				
			|||||||
    if (ohci_read_iso_td(ohci, addr, &iso_td)) {
 | 
					    if (ohci_read_iso_td(ohci, addr, &iso_td)) {
 | 
				
			||||||
        trace_usb_ohci_iso_td_read_failed(addr);
 | 
					        trace_usb_ohci_iso_td_read_failed(addr);
 | 
				
			||||||
        ohci_die(ohci);
 | 
					        ohci_die(ohci);
 | 
				
			||||||
        return 0;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    starting_frame = OHCI_BM(iso_td.flags, TD_SF);
 | 
					    starting_frame = OHCI_BM(iso_td.flags, TD_SF);
 | 
				
			||||||
@ -1184,7 +1186,7 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
 | 
				
			|||||||
    uint32_t next_ed;
 | 
					    uint32_t next_ed;
 | 
				
			||||||
    uint32_t cur;
 | 
					    uint32_t cur;
 | 
				
			||||||
    int active;
 | 
					    int active;
 | 
				
			||||||
 | 
					    uint32_t link_cnt = 0;
 | 
				
			||||||
    active = 0;
 | 
					    active = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (head == 0)
 | 
					    if (head == 0)
 | 
				
			||||||
@ -1199,6 +1201,11 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        next_ed = ed.next & OHCI_DPTR_MASK;
 | 
					        next_ed = ed.next & OHCI_DPTR_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (++link_cnt > ED_LINK_LIMIT) {
 | 
				
			||||||
 | 
					            ohci_die(ohci);
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) {
 | 
					        if ((ed.head & OHCI_ED_H) || (ed.flags & OHCI_ED_K)) {
 | 
				
			||||||
            uint32_t addr;
 | 
					            uint32_t addr;
 | 
				
			||||||
            /* Cancel pending packets for ED that have been paused.  */
 | 
					            /* Cancel pending packets for ED that have been paused.  */
 | 
				
			||||||
 | 
				
			|||||||
@ -49,11 +49,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Very pessimistic, let's hope it's enough for all cases */
 | 
					/* Very pessimistic, let's hope it's enough for all cases */
 | 
				
			||||||
#define EV_QUEUE (((3 * 24) + 16) * MAXSLOTS)
 | 
					#define EV_QUEUE (((3 * 24) + 16) * MAXSLOTS)
 | 
				
			||||||
/* Do not deliver ER Full events. NEC's driver does some things not bound
 | 
					 | 
				
			||||||
 * to the specs when it gets them */
 | 
					 | 
				
			||||||
#define ER_FULL_HACK
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TRB_LINK_LIMIT  4
 | 
					#define TRB_LINK_LIMIT  4
 | 
				
			||||||
 | 
					#define COMMAND_LIMIT   256
 | 
				
			||||||
 | 
					#define TRANSFER_LIMIT  256
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LEN_CAP         0x40
 | 
					#define LEN_CAP         0x40
 | 
				
			||||||
#define LEN_OPER        (0x400 + 0x10 * MAXPORTS)
 | 
					#define LEN_OPER        (0x400 + 0x10 * MAXPORTS)
 | 
				
			||||||
@ -199,7 +198,6 @@ typedef enum TRBType {
 | 
				
			|||||||
    ER_DEVICE_NOTIFICATION,
 | 
					    ER_DEVICE_NOTIFICATION,
 | 
				
			||||||
    ER_MFINDEX_WRAP,
 | 
					    ER_MFINDEX_WRAP,
 | 
				
			||||||
    /* vendor specific bits */
 | 
					    /* vendor specific bits */
 | 
				
			||||||
    CR_VENDOR_VIA_CHALLENGE_RESPONSE = 48,
 | 
					 | 
				
			||||||
    CR_VENDOR_NEC_FIRMWARE_REVISION  = 49,
 | 
					    CR_VENDOR_NEC_FIRMWARE_REVISION  = 49,
 | 
				
			||||||
    CR_VENDOR_NEC_CHALLENGE_RESPONSE = 50,
 | 
					    CR_VENDOR_NEC_CHALLENGE_RESPONSE = 50,
 | 
				
			||||||
} TRBType;
 | 
					} TRBType;
 | 
				
			||||||
@ -431,12 +429,14 @@ typedef struct XHCIInterrupter {
 | 
				
			|||||||
    uint32_t erdp_low;
 | 
					    uint32_t erdp_low;
 | 
				
			||||||
    uint32_t erdp_high;
 | 
					    uint32_t erdp_high;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool msix_used, er_pcs, er_full;
 | 
					    bool msix_used, er_pcs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dma_addr_t er_start;
 | 
					    dma_addr_t er_start;
 | 
				
			||||||
    uint32_t er_size;
 | 
					    uint32_t er_size;
 | 
				
			||||||
    unsigned int er_ep_idx;
 | 
					    unsigned int er_ep_idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* kept for live migration compat only */
 | 
				
			||||||
 | 
					    bool er_full_unused;
 | 
				
			||||||
    XHCIEvent ev_buffer[EV_QUEUE];
 | 
					    XHCIEvent ev_buffer[EV_QUEUE];
 | 
				
			||||||
    unsigned int ev_buffer_put;
 | 
					    unsigned int ev_buffer_put;
 | 
				
			||||||
    unsigned int ev_buffer_get;
 | 
					    unsigned int ev_buffer_get;
 | 
				
			||||||
@ -486,9 +486,13 @@ struct XHCIState {
 | 
				
			|||||||
    XHCIInterrupter intr[MAXINTRS];
 | 
					    XHCIInterrupter intr[MAXINTRS];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    XHCIRing cmd_ring;
 | 
					    XHCIRing cmd_ring;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool nec_quirks;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TYPE_XHCI "nec-usb-xhci"
 | 
					#define TYPE_XHCI "base-xhci"
 | 
				
			||||||
 | 
					#define TYPE_NEC_XHCI "nec-usb-xhci"
 | 
				
			||||||
 | 
					#define TYPE_QEMU_XHCI "qemu-xhci"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define XHCI(obj) \
 | 
					#define XHCI(obj) \
 | 
				
			||||||
    OBJECT_CHECK(XHCIState, (obj), TYPE_XHCI)
 | 
					    OBJECT_CHECK(XHCIState, (obj), TYPE_XHCI)
 | 
				
			||||||
@ -549,7 +553,6 @@ static const char *TRBType_names[] = {
 | 
				
			|||||||
    [ER_HOST_CONTROLLER]               = "ER_HOST_CONTROLLER",
 | 
					    [ER_HOST_CONTROLLER]               = "ER_HOST_CONTROLLER",
 | 
				
			||||||
    [ER_DEVICE_NOTIFICATION]           = "ER_DEVICE_NOTIFICATION",
 | 
					    [ER_DEVICE_NOTIFICATION]           = "ER_DEVICE_NOTIFICATION",
 | 
				
			||||||
    [ER_MFINDEX_WRAP]                  = "ER_MFINDEX_WRAP",
 | 
					    [ER_MFINDEX_WRAP]                  = "ER_MFINDEX_WRAP",
 | 
				
			||||||
    [CR_VENDOR_VIA_CHALLENGE_RESPONSE] = "CR_VENDOR_VIA_CHALLENGE_RESPONSE",
 | 
					 | 
				
			||||||
    [CR_VENDOR_NEC_FIRMWARE_REVISION]  = "CR_VENDOR_NEC_FIRMWARE_REVISION",
 | 
					    [CR_VENDOR_NEC_FIRMWARE_REVISION]  = "CR_VENDOR_NEC_FIRMWARE_REVISION",
 | 
				
			||||||
    [CR_VENDOR_NEC_CHALLENGE_RESPONSE] = "CR_VENDOR_NEC_CHALLENGE_RESPONSE",
 | 
					    [CR_VENDOR_NEC_CHALLENGE_RESPONSE] = "CR_VENDOR_NEC_CHALLENGE_RESPONSE",
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -826,7 +829,7 @@ static void xhci_intr_raise(XHCIState *xhci, int v)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static inline int xhci_running(XHCIState *xhci)
 | 
					static inline int xhci_running(XHCIState *xhci)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    return !(xhci->usbsts & USBSTS_HCH) && !xhci->intr[0].er_full;
 | 
					    return !(xhci->usbsts & USBSTS_HCH);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void xhci_die(XHCIState *xhci)
 | 
					static void xhci_die(XHCIState *xhci)
 | 
				
			||||||
@ -865,74 +868,6 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void xhci_events_update(XHCIState *xhci, int v)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    XHCIInterrupter *intr = &xhci->intr[v];
 | 
					 | 
				
			||||||
    dma_addr_t erdp;
 | 
					 | 
				
			||||||
    unsigned int dp_idx;
 | 
					 | 
				
			||||||
    bool do_irq = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (xhci->usbsts & USBSTS_HCH) {
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    erdp = xhci_addr64(intr->erdp_low, intr->erdp_high);
 | 
					 | 
				
			||||||
    if (erdp < intr->er_start ||
 | 
					 | 
				
			||||||
        erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) {
 | 
					 | 
				
			||||||
        DPRINTF("xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp);
 | 
					 | 
				
			||||||
        DPRINTF("xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n",
 | 
					 | 
				
			||||||
                v, intr->er_start, intr->er_size);
 | 
					 | 
				
			||||||
        xhci_die(xhci);
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    dp_idx = (erdp - intr->er_start) / TRB_SIZE;
 | 
					 | 
				
			||||||
    assert(dp_idx < intr->er_size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus
 | 
					 | 
				
			||||||
     * deadlocks when the ER is full. Hack it by holding off events until
 | 
					 | 
				
			||||||
     * the driver decides to free at least half of the ring */
 | 
					 | 
				
			||||||
    if (intr->er_full) {
 | 
					 | 
				
			||||||
        int er_free = dp_idx - intr->er_ep_idx;
 | 
					 | 
				
			||||||
        if (er_free <= 0) {
 | 
					 | 
				
			||||||
            er_free += intr->er_size;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (er_free < (intr->er_size/2)) {
 | 
					 | 
				
			||||||
            DPRINTF("xhci_events_update(): event ring still "
 | 
					 | 
				
			||||||
                    "more than half full (hack)\n");
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while (intr->ev_buffer_put != intr->ev_buffer_get) {
 | 
					 | 
				
			||||||
        assert(intr->er_full);
 | 
					 | 
				
			||||||
        if (((intr->er_ep_idx+1) % intr->er_size) == dp_idx) {
 | 
					 | 
				
			||||||
            DPRINTF("xhci_events_update(): event ring full again\n");
 | 
					 | 
				
			||||||
#ifndef ER_FULL_HACK
 | 
					 | 
				
			||||||
            XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
 | 
					 | 
				
			||||||
            xhci_write_event(xhci, &full, v);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
            do_irq = 1;
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        XHCIEvent *event = &intr->ev_buffer[intr->ev_buffer_get];
 | 
					 | 
				
			||||||
        xhci_write_event(xhci, event, v);
 | 
					 | 
				
			||||||
        intr->ev_buffer_get++;
 | 
					 | 
				
			||||||
        do_irq = 1;
 | 
					 | 
				
			||||||
        if (intr->ev_buffer_get == EV_QUEUE) {
 | 
					 | 
				
			||||||
            intr->ev_buffer_get = 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (do_irq) {
 | 
					 | 
				
			||||||
        xhci_intr_raise(xhci, v);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (intr->er_full && intr->ev_buffer_put == intr->ev_buffer_get) {
 | 
					 | 
				
			||||||
        DPRINTF("xhci_events_update(): event ring no longer full\n");
 | 
					 | 
				
			||||||
        intr->er_full = 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v)
 | 
					static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    XHCIInterrupter *intr;
 | 
					    XHCIInterrupter *intr;
 | 
				
			||||||
@ -945,19 +880,6 @@ static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v)
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    intr = &xhci->intr[v];
 | 
					    intr = &xhci->intr[v];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (intr->er_full) {
 | 
					 | 
				
			||||||
        DPRINTF("xhci_event(): ER full, queueing\n");
 | 
					 | 
				
			||||||
        if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) {
 | 
					 | 
				
			||||||
            DPRINTF("xhci: event queue full, dropping event!\n");
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        intr->ev_buffer[intr->ev_buffer_put++] = *event;
 | 
					 | 
				
			||||||
        if (intr->ev_buffer_put == EV_QUEUE) {
 | 
					 | 
				
			||||||
            intr->ev_buffer_put = 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    erdp = xhci_addr64(intr->erdp_low, intr->erdp_high);
 | 
					    erdp = xhci_addr64(intr->erdp_low, intr->erdp_high);
 | 
				
			||||||
    if (erdp < intr->er_start ||
 | 
					    if (erdp < intr->er_start ||
 | 
				
			||||||
        erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) {
 | 
					        erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) {
 | 
				
			||||||
@ -971,21 +893,12 @@ static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v)
 | 
				
			|||||||
    dp_idx = (erdp - intr->er_start) / TRB_SIZE;
 | 
					    dp_idx = (erdp - intr->er_start) / TRB_SIZE;
 | 
				
			||||||
    assert(dp_idx < intr->er_size);
 | 
					    assert(dp_idx < intr->er_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((intr->er_ep_idx+1) % intr->er_size == dp_idx) {
 | 
					    if ((intr->er_ep_idx + 2) % intr->er_size == dp_idx) {
 | 
				
			||||||
        DPRINTF("xhci_event(): ER full, queueing\n");
 | 
					        DPRINTF("xhci: ER %d full, send ring full error\n", v);
 | 
				
			||||||
#ifndef ER_FULL_HACK
 | 
					 | 
				
			||||||
        XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
 | 
					        XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR};
 | 
				
			||||||
        xhci_write_event(xhci, &full);
 | 
					        xhci_write_event(xhci, &full, v);
 | 
				
			||||||
#endif
 | 
					    } else if ((intr->er_ep_idx + 1) % intr->er_size == dp_idx) {
 | 
				
			||||||
        intr->er_full = 1;
 | 
					        DPRINTF("xhci: ER %d full, drop event\n", v);
 | 
				
			||||||
        if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) {
 | 
					 | 
				
			||||||
            DPRINTF("xhci: event queue full, dropping event!\n");
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        intr->ev_buffer[intr->ev_buffer_put++] = *event;
 | 
					 | 
				
			||||||
        if (intr->ev_buffer_put == EV_QUEUE) {
 | 
					 | 
				
			||||||
            intr->ev_buffer_put = 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        xhci_write_event(xhci, event, v);
 | 
					        xhci_write_event(xhci, event, v);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -1032,6 +945,7 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
 | 
				
			|||||||
            return type;
 | 
					            return type;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            if (++link_cnt > TRB_LINK_LIMIT) {
 | 
					            if (++link_cnt > TRB_LINK_LIMIT) {
 | 
				
			||||||
 | 
					                trace_usb_xhci_enforced_limit("trb-link");
 | 
				
			||||||
                return 0;
 | 
					                return 0;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ring->dequeue = xhci_mask64(trb->parameter);
 | 
					            ring->dequeue = xhci_mask64(trb->parameter);
 | 
				
			||||||
@ -1124,7 +1038,6 @@ static void xhci_er_reset(XHCIState *xhci, int v)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    intr->er_ep_idx = 0;
 | 
					    intr->er_ep_idx = 0;
 | 
				
			||||||
    intr->er_pcs = 1;
 | 
					    intr->er_pcs = 1;
 | 
				
			||||||
    intr->er_full = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DPRINTF("xhci: event ring[%d]:" DMA_ADDR_FMT " [%d]\n",
 | 
					    DPRINTF("xhci: event ring[%d]:" DMA_ADDR_FMT " [%d]\n",
 | 
				
			||||||
            v, intr->er_start, intr->er_size);
 | 
					            v, intr->er_start, intr->er_size);
 | 
				
			||||||
@ -2150,6 +2063,7 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
 | 
				
			|||||||
    XHCIRing *ring;
 | 
					    XHCIRing *ring;
 | 
				
			||||||
    USBEndpoint *ep = NULL;
 | 
					    USBEndpoint *ep = NULL;
 | 
				
			||||||
    uint64_t mfindex;
 | 
					    uint64_t mfindex;
 | 
				
			||||||
 | 
					    unsigned int count = 0;
 | 
				
			||||||
    int length;
 | 
					    int length;
 | 
				
			||||||
    int i;
 | 
					    int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2262,6 +2176,10 @@ static void xhci_kick_epctx(XHCIEPContext *epctx, unsigned int streamid)
 | 
				
			|||||||
            epctx->retry = xfer;
 | 
					            epctx->retry = xfer;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if (count++ > TRANSFER_LIMIT) {
 | 
				
			||||||
 | 
					            trace_usb_xhci_enforced_limit("transfers");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    epctx->kick_active--;
 | 
					    epctx->kick_active--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2702,39 +2620,13 @@ static uint32_t xhci_nec_challenge(uint32_t hi, uint32_t lo)
 | 
				
			|||||||
    return ~val;
 | 
					    return ~val;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void xhci_via_challenge(XHCIState *xhci, uint64_t addr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    PCIDevice *pci_dev = PCI_DEVICE(xhci);
 | 
					 | 
				
			||||||
    uint32_t buf[8];
 | 
					 | 
				
			||||||
    uint32_t obuf[8];
 | 
					 | 
				
			||||||
    dma_addr_t paddr = xhci_mask64(addr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pci_dma_read(pci_dev, paddr, &buf, 32);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    memcpy(obuf, buf, sizeof(obuf));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((buf[0] & 0xff) == 2) {
 | 
					 | 
				
			||||||
        obuf[0] = 0x49932000 + 0x54dc200 * buf[2] + 0x7429b578 * buf[3];
 | 
					 | 
				
			||||||
        obuf[0] |=  (buf[2] * buf[3]) & 0xff;
 | 
					 | 
				
			||||||
        obuf[1] = 0x0132bb37 + 0xe89 * buf[2] + 0xf09 * buf[3];
 | 
					 | 
				
			||||||
        obuf[2] = 0x0066c2e9 + 0x2091 * buf[2] + 0x19bd * buf[3];
 | 
					 | 
				
			||||||
        obuf[3] = 0xd5281342 + 0x2cc9691 * buf[2] + 0x2367662 * buf[3];
 | 
					 | 
				
			||||||
        obuf[4] = 0x0123c75c + 0x1595 * buf[2] + 0x19ec * buf[3];
 | 
					 | 
				
			||||||
        obuf[5] = 0x00f695de + 0x26fd * buf[2] + 0x3e9 * buf[3];
 | 
					 | 
				
			||||||
        obuf[6] = obuf[2] ^ obuf[3] ^ 0x29472956;
 | 
					 | 
				
			||||||
        obuf[7] = obuf[2] ^ obuf[3] ^ 0x65866593;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pci_dma_write(pci_dev, paddr, &obuf, 32);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void xhci_process_commands(XHCIState *xhci)
 | 
					static void xhci_process_commands(XHCIState *xhci)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    XHCITRB trb;
 | 
					    XHCITRB trb;
 | 
				
			||||||
    TRBType type;
 | 
					    TRBType type;
 | 
				
			||||||
    XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS};
 | 
					    XHCIEvent event = {ER_COMMAND_COMPLETE, CC_SUCCESS};
 | 
				
			||||||
    dma_addr_t addr;
 | 
					    dma_addr_t addr;
 | 
				
			||||||
    unsigned int i, slotid = 0;
 | 
					    unsigned int i, slotid = 0, count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DPRINTF("xhci_process_commands()\n");
 | 
					    DPRINTF("xhci_process_commands()\n");
 | 
				
			||||||
    if (!xhci_running(xhci)) {
 | 
					    if (!xhci_running(xhci)) {
 | 
				
			||||||
@ -2823,15 +2715,16 @@ static void xhci_process_commands(XHCIState *xhci)
 | 
				
			|||||||
        case CR_GET_PORT_BANDWIDTH:
 | 
					        case CR_GET_PORT_BANDWIDTH:
 | 
				
			||||||
            event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter);
 | 
					            event.ccode = xhci_get_port_bandwidth(xhci, trb.parameter);
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case CR_VENDOR_VIA_CHALLENGE_RESPONSE:
 | 
					 | 
				
			||||||
            xhci_via_challenge(xhci, trb.parameter);
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        case CR_VENDOR_NEC_FIRMWARE_REVISION:
 | 
					        case CR_VENDOR_NEC_FIRMWARE_REVISION:
 | 
				
			||||||
 | 
					            if (xhci->nec_quirks) {
 | 
				
			||||||
                event.type = 48; /* NEC reply */
 | 
					                event.type = 48; /* NEC reply */
 | 
				
			||||||
                event.length = 0x3025;
 | 
					                event.length = 0x3025;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                event.ccode = CC_TRB_ERROR;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        case CR_VENDOR_NEC_CHALLENGE_RESPONSE:
 | 
					        case CR_VENDOR_NEC_CHALLENGE_RESPONSE:
 | 
				
			||||||
        {
 | 
					            if (xhci->nec_quirks) {
 | 
				
			||||||
                uint32_t chi = trb.parameter >> 32;
 | 
					                uint32_t chi = trb.parameter >> 32;
 | 
				
			||||||
                uint32_t clo = trb.parameter;
 | 
					                uint32_t clo = trb.parameter;
 | 
				
			||||||
                uint32_t val = xhci_nec_challenge(chi, clo);
 | 
					                uint32_t val = xhci_nec_challenge(chi, clo);
 | 
				
			||||||
@ -2839,6 +2732,8 @@ static void xhci_process_commands(XHCIState *xhci)
 | 
				
			|||||||
                event.epid = val >> 16;
 | 
					                event.epid = val >> 16;
 | 
				
			||||||
                slotid = val >> 24;
 | 
					                slotid = val >> 24;
 | 
				
			||||||
                event.type = 48; /* NEC reply */
 | 
					                event.type = 48; /* NEC reply */
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                event.ccode = CC_TRB_ERROR;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        default:
 | 
					        default:
 | 
				
			||||||
@ -2848,6 +2743,11 @@ static void xhci_process_commands(XHCIState *xhci)
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        event.slotid = slotid;
 | 
					        event.slotid = slotid;
 | 
				
			||||||
        xhci_event(xhci, &event, 0);
 | 
					        xhci_event(xhci, &event, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (count++ > COMMAND_LIMIT) {
 | 
				
			||||||
 | 
					            trace_usb_xhci_enforced_limit("commands");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2978,7 +2878,6 @@ static void xhci_reset(DeviceState *dev)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        xhci->intr[i].er_ep_idx = 0;
 | 
					        xhci->intr[i].er_ep_idx = 0;
 | 
				
			||||||
        xhci->intr[i].er_pcs = 1;
 | 
					        xhci->intr[i].er_pcs = 1;
 | 
				
			||||||
        xhci->intr[i].er_full = 0;
 | 
					 | 
				
			||||||
        xhci->intr[i].ev_buffer_put = 0;
 | 
					        xhci->intr[i].ev_buffer_put = 0;
 | 
				
			||||||
        xhci->intr[i].ev_buffer_get = 0;
 | 
					        xhci->intr[i].ev_buffer_get = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -3343,9 +3242,12 @@ static void xhci_runtime_write(void *ptr, hwaddr reg,
 | 
				
			|||||||
        intr->erstsz = val & 0xffff;
 | 
					        intr->erstsz = val & 0xffff;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case 0x10: /* ERSTBA low */
 | 
					    case 0x10: /* ERSTBA low */
 | 
				
			||||||
        /* XXX NEC driver bug: it doesn't align this to 64 bytes
 | 
					        if (xhci->nec_quirks) {
 | 
				
			||||||
        intr->erstba_low = val & 0xffffffc0; */
 | 
					            /* NEC driver bug: it doesn't align this to 64 bytes */
 | 
				
			||||||
            intr->erstba_low = val & 0xfffffff0;
 | 
					            intr->erstba_low = val & 0xfffffff0;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            intr->erstba_low = val & 0xffffffc0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case 0x14: /* ERSTBA high */
 | 
					    case 0x14: /* ERSTBA high */
 | 
				
			||||||
        intr->erstba_high = val;
 | 
					        intr->erstba_high = val;
 | 
				
			||||||
@ -3368,7 +3270,6 @@ static void xhci_runtime_write(void *ptr, hwaddr reg,
 | 
				
			|||||||
        break;
 | 
					        break;
 | 
				
			||||||
    case 0x1c: /* ERDP high */
 | 
					    case 0x1c: /* ERDP high */
 | 
				
			||||||
        intr->erdp_high = val;
 | 
					        intr->erdp_high = val;
 | 
				
			||||||
        xhci_events_update(xhci, v);
 | 
					 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        trace_usb_xhci_unimplemented("oper write", reg);
 | 
					        trace_usb_xhci_unimplemented("oper write", reg);
 | 
				
			||||||
@ -3641,6 +3542,9 @@ static void usb_xhci_realize(struct PCIDevice *dev, Error **errp)
 | 
				
			|||||||
    dev->config[PCI_CACHE_LINE_SIZE] = 0x10;
 | 
					    dev->config[PCI_CACHE_LINE_SIZE] = 0x10;
 | 
				
			||||||
    dev->config[0x60] = 0x30; /* release number */
 | 
					    dev->config[0x60] = 0x30; /* release number */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (strcmp(object_get_typename(OBJECT(dev)), TYPE_NEC_XHCI) == 0) {
 | 
				
			||||||
 | 
					        xhci->nec_quirks = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (xhci->numintrs > MAXINTRS) {
 | 
					    if (xhci->numintrs > MAXINTRS) {
 | 
				
			||||||
        xhci->numintrs = MAXINTRS;
 | 
					        xhci->numintrs = MAXINTRS;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -3866,8 +3770,7 @@ static const VMStateDescription vmstate_xhci_event = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static bool xhci_er_full(void *opaque, int version_id)
 | 
					static bool xhci_er_full(void *opaque, int version_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct XHCIInterrupter *intr = opaque;
 | 
					    return false;
 | 
				
			||||||
    return intr->er_full;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const VMStateDescription vmstate_xhci_intr = {
 | 
					static const VMStateDescription vmstate_xhci_intr = {
 | 
				
			||||||
@ -3891,7 +3794,7 @@ static const VMStateDescription vmstate_xhci_intr = {
 | 
				
			|||||||
        VMSTATE_UINT32(er_ep_idx,     XHCIInterrupter),
 | 
					        VMSTATE_UINT32(er_ep_idx,     XHCIInterrupter),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* event queue (used if ring is full) */
 | 
					        /* event queue (used if ring is full) */
 | 
				
			||||||
        VMSTATE_BOOL(er_full,         XHCIInterrupter),
 | 
					        VMSTATE_BOOL(er_full_unused,  XHCIInterrupter),
 | 
				
			||||||
        VMSTATE_UINT32_TEST(ev_buffer_put, XHCIInterrupter, xhci_er_full),
 | 
					        VMSTATE_UINT32_TEST(ev_buffer_put, XHCIInterrupter, xhci_er_full),
 | 
				
			||||||
        VMSTATE_UINT32_TEST(ev_buffer_get, XHCIInterrupter, xhci_er_full),
 | 
					        VMSTATE_UINT32_TEST(ev_buffer_get, XHCIInterrupter, xhci_er_full),
 | 
				
			||||||
        VMSTATE_STRUCT_ARRAY_TEST(ev_buffer, XHCIInterrupter, EV_QUEUE,
 | 
					        VMSTATE_STRUCT_ARRAY_TEST(ev_buffer, XHCIInterrupter, EV_QUEUE,
 | 
				
			||||||
@ -3963,10 +3866,7 @@ static void xhci_class_init(ObjectClass *klass, void *data)
 | 
				
			|||||||
    set_bit(DEVICE_CATEGORY_USB, dc->categories);
 | 
					    set_bit(DEVICE_CATEGORY_USB, dc->categories);
 | 
				
			||||||
    k->realize      = usb_xhci_realize;
 | 
					    k->realize      = usb_xhci_realize;
 | 
				
			||||||
    k->exit         = usb_xhci_exit;
 | 
					    k->exit         = usb_xhci_exit;
 | 
				
			||||||
    k->vendor_id    = PCI_VENDOR_ID_NEC;
 | 
					 | 
				
			||||||
    k->device_id    = PCI_DEVICE_ID_NEC_UPD720200;
 | 
					 | 
				
			||||||
    k->class_id     = PCI_CLASS_SERIAL_USB;
 | 
					    k->class_id     = PCI_CLASS_SERIAL_USB;
 | 
				
			||||||
    k->revision     = 0x03;
 | 
					 | 
				
			||||||
    k->is_express   = 1;
 | 
					    k->is_express   = 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3975,11 +3875,44 @@ static const TypeInfo xhci_info = {
 | 
				
			|||||||
    .parent        = TYPE_PCI_DEVICE,
 | 
					    .parent        = TYPE_PCI_DEVICE,
 | 
				
			||||||
    .instance_size = sizeof(XHCIState),
 | 
					    .instance_size = sizeof(XHCIState),
 | 
				
			||||||
    .class_init    = xhci_class_init,
 | 
					    .class_init    = xhci_class_init,
 | 
				
			||||||
 | 
					    .abstract      = true,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void nec_xhci_class_init(ObjectClass *klass, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    k->vendor_id    = PCI_VENDOR_ID_NEC;
 | 
				
			||||||
 | 
					    k->device_id    = PCI_DEVICE_ID_NEC_UPD720200;
 | 
				
			||||||
 | 
					    k->revision     = 0x03;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const TypeInfo nec_xhci_info = {
 | 
				
			||||||
 | 
					    .name          = TYPE_NEC_XHCI,
 | 
				
			||||||
 | 
					    .parent        = TYPE_XHCI,
 | 
				
			||||||
 | 
					    .class_init    = nec_xhci_class_init,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void qemu_xhci_class_init(ObjectClass *klass, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    k->vendor_id    = PCI_VENDOR_ID_REDHAT;
 | 
				
			||||||
 | 
					    k->device_id    = PCI_DEVICE_ID_REDHAT_XHCI;
 | 
				
			||||||
 | 
					    k->revision     = 0x01;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const TypeInfo qemu_xhci_info = {
 | 
				
			||||||
 | 
					    .name          = TYPE_QEMU_XHCI,
 | 
				
			||||||
 | 
					    .parent        = TYPE_XHCI,
 | 
				
			||||||
 | 
					    .class_init    = qemu_xhci_class_init,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void xhci_register_types(void)
 | 
					static void xhci_register_types(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    type_register_static(&xhci_info);
 | 
					    type_register_static(&xhci_info);
 | 
				
			||||||
 | 
					    type_register_static(&nec_xhci_info);
 | 
				
			||||||
 | 
					    type_register_static(&qemu_xhci_info);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type_init(xhci_register_types)
 | 
					type_init(xhci_register_types)
 | 
				
			||||||
 | 
				
			|||||||
@ -174,6 +174,7 @@ usb_xhci_xfer_retry(void *xfer) "%p"
 | 
				
			|||||||
usb_xhci_xfer_success(void *xfer, uint32_t bytes) "%p: len %d"
 | 
					usb_xhci_xfer_success(void *xfer, uint32_t bytes) "%p: len %d"
 | 
				
			||||||
usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d"
 | 
					usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d"
 | 
				
			||||||
usb_xhci_unimplemented(const char *item, int nr) "%s (0x%x)"
 | 
					usb_xhci_unimplemented(const char *item, int nr) "%s (0x%x)"
 | 
				
			||||||
 | 
					usb_xhci_enforced_limit(const char *item) "%s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# hw/usb/desc.c
 | 
					# hw/usb/desc.c
 | 
				
			||||||
usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
 | 
					usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d"
 | 
				
			||||||
 | 
				
			|||||||
@ -97,6 +97,7 @@
 | 
				
			|||||||
#define PCI_DEVICE_ID_REDHAT_BRIDGE_SEAT 0x000a
 | 
					#define PCI_DEVICE_ID_REDHAT_BRIDGE_SEAT 0x000a
 | 
				
			||||||
#define PCI_DEVICE_ID_REDHAT_PXB_PCIE    0x000b
 | 
					#define PCI_DEVICE_ID_REDHAT_PXB_PCIE    0x000b
 | 
				
			||||||
#define PCI_DEVICE_ID_REDHAT_PCIE_RP     0x000c
 | 
					#define PCI_DEVICE_ID_REDHAT_PCIE_RP     0x000c
 | 
				
			||||||
 | 
					#define PCI_DEVICE_ID_REDHAT_XHCI        0x000d
 | 
				
			||||||
#define PCI_DEVICE_ID_REDHAT_QXL         0x0100
 | 
					#define PCI_DEVICE_ID_REDHAT_QXL         0x0100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define FMT_PCIBUS                      PRIx64
 | 
					#define FMT_PCIBUS                      PRIx64
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user