Merge remote-tracking branch 'kraxel/usb.52' into staging

* kraxel/usb.52: (37 commits)
  ehci: rework frame skipping
  ehci: adaptive wakeup rate.
  ehci: create ehci_update_frindex
  ehci: remove unused attach_poll_counter
  ehci: fix halt status handling
  ehci: update status bits in ehci_set_state
  ehci: add ehci_*_enabled() helpers
  ehci: fix reset
  ehci: kick async schedule on wakeup
  ehci: schedule async bh on async packet completion
  ehci: move async schedule to bottom half
  ehci: add async field to EHCIQueue
  ehci: tweak queue initialization
  ehci: add queuing support
  ehci: move ehci_flush_qh
  ehci: cache USBDevice in EHCIQueue
  ehci: make ehci_execute work on EHCIPacket instead of EHCIQueue
  ehci: add EHCIPacket
  xhci: trace: slots
  xhci: trace: transfers
  ...
This commit is contained in:
Anthony Liguori 2012-06-11 12:07:00 -05:00
commit 39cde84517
7 changed files with 696 additions and 373 deletions

View File

@ -1507,10 +1507,9 @@ static void put_scsi_requests(QEMUFile *f, void *pv, size_t size)
QTAILQ_FOREACH(req, &s->requests, next) { QTAILQ_FOREACH(req, &s->requests, next) {
assert(!req->io_canceled); assert(!req->io_canceled);
assert(req->status == -1); assert(req->status == -1);
assert(req->retry);
assert(req->enqueued); assert(req->enqueued);
qemu_put_sbyte(f, 1); qemu_put_sbyte(f, req->retry ? 1 : 2);
qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf)); qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf));
qemu_put_be32s(f, &req->tag); qemu_put_be32s(f, &req->tag);
qemu_put_be32s(f, &req->lun); qemu_put_be32s(f, &req->lun);
@ -1528,8 +1527,9 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size)
{ {
SCSIDevice *s = pv; SCSIDevice *s = pv;
SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus); SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus);
int8_t sbyte;
while (qemu_get_sbyte(f)) { while ((sbyte = qemu_get_sbyte(f)) > 0) {
uint8_t buf[SCSI_CMD_BUF_SIZE]; uint8_t buf[SCSI_CMD_BUF_SIZE];
uint32_t tag; uint32_t tag;
uint32_t lun; uint32_t lun;
@ -1539,6 +1539,7 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size)
qemu_get_be32s(f, &tag); qemu_get_be32s(f, &tag);
qemu_get_be32s(f, &lun); qemu_get_be32s(f, &lun);
req = scsi_req_new(s, tag, lun, buf, NULL); req = scsi_req_new(s, tag, lun, buf, NULL);
req->retry = (sbyte == 1);
if (bus->info->load_request) { if (bus->info->load_request) {
req->hba_private = bus->info->load_request(f, req); req->hba_private = bus->info->load_request(f, req);
} }
@ -1547,7 +1548,6 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size)
} }
/* Just restart it later. */ /* Just restart it later. */
req->retry = true;
scsi_req_enqueue_internal(req); scsi_req_enqueue_internal(req);
/* At this point, the request will be kept alive by the reference /* At this point, the request will be kept alive by the reference

View File

@ -132,8 +132,14 @@ static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req)
qemu_put_be64s(f, &r->sector); qemu_put_be64s(f, &r->sector);
qemu_put_be32s(f, &r->sector_count); qemu_put_be32s(f, &r->sector_count);
qemu_put_be32s(f, &r->buflen); qemu_put_be32s(f, &r->buflen);
if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { if (r->buflen) {
qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len); if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len);
} else if (!req->retry) {
uint32_t len = r->iov.iov_len;
qemu_put_be32s(f, &len);
qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len);
}
} }
} }
@ -148,6 +154,12 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req)
scsi_init_iovec(r, r->buflen); scsi_init_iovec(r, r->buflen);
if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len); qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len);
} else if (!r->req.retry) {
uint32_t len;
qemu_get_be32s(f, &len);
r->iov.iov_len = len;
assert(r->iov.iov_len <= r->buflen);
qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len);
} }
} }

View File

@ -48,10 +48,9 @@ struct usb_msd_csw {
typedef struct { typedef struct {
USBDevice dev; USBDevice dev;
enum USBMSDMode mode; enum USBMSDMode mode;
uint32_t scsi_off;
uint32_t scsi_len; uint32_t scsi_len;
uint8_t *scsi_buf;
uint32_t data_len; uint32_t data_len;
uint32_t residue;
struct usb_msd_csw csw; struct usb_msd_csw csw;
SCSIRequest *req; SCSIRequest *req;
SCSIBus bus; SCSIBus bus;
@ -179,9 +178,9 @@ static void usb_msd_copy_data(MSDState *s, USBPacket *p)
len = p->iov.size - p->result; len = p->iov.size - p->result;
if (len > s->scsi_len) if (len > s->scsi_len)
len = s->scsi_len; len = s->scsi_len;
usb_packet_copy(p, s->scsi_buf, len); usb_packet_copy(p, scsi_req_get_buf(s->req) + s->scsi_off, len);
s->scsi_len -= len; s->scsi_len -= len;
s->scsi_buf += len; s->scsi_off += len;
s->data_len -= len; s->data_len -= len;
if (s->scsi_len == 0 || s->data_len == 0) { if (s->scsi_len == 0 || s->data_len == 0) {
scsi_req_continue(s->req); scsi_req_continue(s->req);
@ -201,6 +200,18 @@ static void usb_msd_send_status(MSDState *s, USBPacket *p)
memset(&s->csw, 0, sizeof(s->csw)); memset(&s->csw, 0, sizeof(s->csw));
} }
static void usb_msd_packet_complete(MSDState *s)
{
USBPacket *p = s->packet;
/* Set s->packet to NULL before calling usb_packet_complete
because another request may be issued before
usb_packet_complete returns. */
DPRINTF("Packet complete %p\n", p);
s->packet = NULL;
usb_packet_complete(&s->dev, p);
}
static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
{ {
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
@ -208,17 +219,12 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len)
assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV)); assert((s->mode == USB_MSDM_DATAOUT) == (req->cmd.mode == SCSI_XFER_TO_DEV));
s->scsi_len = len; s->scsi_len = len;
s->scsi_buf = scsi_req_get_buf(req); s->scsi_off = 0;
if (p) { if (p) {
usb_msd_copy_data(s, p); usb_msd_copy_data(s, p);
p = s->packet; p = s->packet;
if (p && p->result == p->iov.size) { if (p && p->result == p->iov.size) {
/* Set s->packet to NULL before calling usb_packet_complete usb_msd_packet_complete(s);
because another request may be issued before
usb_packet_complete returns. */
DPRINTF("Packet complete %p\n", p);
s->packet = NULL;
usb_packet_complete(&s->dev, p);
} }
} }
} }
@ -229,11 +235,10 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r
USBPacket *p = s->packet; USBPacket *p = s->packet;
DPRINTF("Command complete %d tag 0x%x\n", status, req->tag); DPRINTF("Command complete %d tag 0x%x\n", status, req->tag);
s->residue = s->data_len;
s->csw.sig = cpu_to_le32(0x53425355); s->csw.sig = cpu_to_le32(0x53425355);
s->csw.tag = cpu_to_le32(req->tag); s->csw.tag = cpu_to_le32(req->tag);
s->csw.residue = cpu_to_le32(s->residue); s->csw.residue = cpu_to_le32(s->data_len);
s->csw.status = status != 0; s->csw.status = status != 0;
if (s->packet) { if (s->packet) {
@ -252,8 +257,7 @@ static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, size_t r
s->mode = USB_MSDM_CSW; s->mode = USB_MSDM_CSW;
} }
} }
s->packet = NULL; usb_msd_packet_complete(s);
usb_packet_complete(&s->dev, p);
} else if (s->data_len == 0) { } else if (s->data_len == 0) {
s->mode = USB_MSDM_CSW; s->mode = USB_MSDM_CSW;
} }
@ -283,10 +287,8 @@ static void usb_msd_handle_reset(USBDevice *dev)
assert(s->req == NULL); assert(s->req == NULL);
if (s->packet) { if (s->packet) {
USBPacket *p = s->packet; s->packet->result = USB_RET_STALL;
s->packet = NULL; usb_msd_packet_complete(s);
p->result = USB_RET_STALL;
usb_packet_complete(dev, p);
} }
s->mode = USB_MSDM_CBW; s->mode = USB_MSDM_CBW;
@ -378,7 +380,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
} }
DPRINTF("Command tag 0x%x flags %08x len %d data %d\n", DPRINTF("Command tag 0x%x flags %08x len %d data %d\n",
tag, cbw.flags, cbw.cmd_len, s->data_len); tag, cbw.flags, cbw.cmd_len, s->data_len);
s->residue = 0; assert(le32_to_cpu(s->csw.residue) == 0);
s->scsi_len = 0; s->scsi_len = 0;
s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL); s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL);
scsi_req_enqueue(s->req); scsi_req_enqueue(s->req);
@ -397,7 +399,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
if (s->scsi_len) { if (s->scsi_len) {
usb_msd_copy_data(s, p); usb_msd_copy_data(s, p);
} }
if (s->residue) { if (le32_to_cpu(s->csw.residue)) {
int len = p->iov.size - p->result; int len = p->iov.size - p->result;
if (len) { if (len) {
usb_packet_skip(p, len); usb_packet_skip(p, len);
@ -458,7 +460,7 @@ static int usb_msd_handle_data(USBDevice *dev, USBPacket *p)
if (s->scsi_len) { if (s->scsi_len) {
usb_msd_copy_data(s, p); usb_msd_copy_data(s, p);
} }
if (s->residue) { if (le32_to_cpu(s->csw.residue)) {
int len = p->iov.size - p->result; int len = p->iov.size - p->result;
if (len) { if (len) {
usb_packet_skip(p, len); usb_packet_skip(p, len);
@ -504,6 +506,17 @@ static void usb_msd_password_cb(void *opaque, int err)
qdev_unplug(&s->dev.qdev, NULL); qdev_unplug(&s->dev.qdev, NULL);
} }
static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req)
{
MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent);
/* nothing to load, just store req in our state struct */
assert(s->req == NULL);
scsi_req_ref(req);
s->req = req;
return NULL;
}
static const struct SCSIBusInfo usb_msd_scsi_info = { static const struct SCSIBusInfo usb_msd_scsi_info = {
.tcq = false, .tcq = false,
.max_target = 0, .max_target = 0,
@ -511,7 +524,8 @@ static const struct SCSIBusInfo usb_msd_scsi_info = {
.transfer_data = usb_msd_transfer_data, .transfer_data = usb_msd_transfer_data,
.complete = usb_msd_command_complete, .complete = usb_msd_command_complete,
.cancel = usb_msd_request_cancelled .cancel = usb_msd_request_cancelled,
.load_request = usb_msd_load_request,
}; };
static int usb_msd_initfn(USBDevice *dev) static int usb_msd_initfn(USBDevice *dev)
@ -631,11 +645,18 @@ static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
static const VMStateDescription vmstate_usb_msd = { static const VMStateDescription vmstate_usb_msd = {
.name = "usb-storage", .name = "usb-storage",
.unmigratable = 1, /* FIXME: handle transactions which are in flight */
.version_id = 1, .version_id = 1,
.minimum_version_id = 1, .minimum_version_id = 1,
.fields = (VMStateField []) { .fields = (VMStateField []) {
VMSTATE_USB_DEVICE(dev, MSDState), VMSTATE_USB_DEVICE(dev, MSDState),
VMSTATE_UINT32(mode, MSDState),
VMSTATE_UINT32(scsi_len, MSDState),
VMSTATE_UINT32(scsi_off, MSDState),
VMSTATE_UINT32(data_len, MSDState),
VMSTATE_UINT32(csw.sig, MSDState),
VMSTATE_UINT32(csw.tag, MSDState),
VMSTATE_UINT32(csw.residue, MSDState),
VMSTATE_UINT8(csw.status, MSDState),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
} }
}; };

File diff suppressed because it is too large Load Diff

View File

@ -131,10 +131,14 @@ struct UHCIState {
uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */ uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
int64_t expire_time; int64_t expire_time;
QEMUTimer *frame_timer; QEMUTimer *frame_timer;
QEMUBH *bh;
uint32_t frame_bytes;
uint32_t frame_bandwidth;
UHCIPort ports[NB_PORTS]; UHCIPort ports[NB_PORTS];
/* Interrupts that should be raised at the end of the current frame. */ /* Interrupts that should be raised at the end of the current frame. */
uint32_t pending_int_mask; uint32_t pending_int_mask;
int irq_pin;
/* Active packets */ /* Active packets */
QTAILQ_HEAD(, UHCIQueue) queues; QTAILQ_HEAD(, UHCIQueue) queues;
@ -337,7 +341,7 @@ static void uhci_update_irq(UHCIState *s)
} else { } else {
level = 0; level = 0;
} }
qemu_set_irq(s->dev.irq[3], level); qemu_set_irq(s->dev.irq[s->irq_pin], level);
} }
static void uhci_reset(void *opaque) static void uhci_reset(void *opaque)
@ -369,16 +373,10 @@ static void uhci_reset(void *opaque)
} }
uhci_async_cancel_all(s); uhci_async_cancel_all(s);
qemu_bh_cancel(s->bh);
uhci_update_irq(s); uhci_update_irq(s);
} }
static void uhci_pre_save(void *opaque)
{
UHCIState *s = opaque;
uhci_async_cancel_all(s);
}
static const VMStateDescription vmstate_uhci_port = { static const VMStateDescription vmstate_uhci_port = {
.name = "uhci port", .name = "uhci port",
.version_id = 1, .version_id = 1,
@ -395,7 +393,6 @@ static const VMStateDescription vmstate_uhci = {
.version_id = 2, .version_id = 2,
.minimum_version_id = 1, .minimum_version_id = 1,
.minimum_version_id_old = 1, .minimum_version_id_old = 1,
.pre_save = uhci_pre_save,
.fields = (VMStateField []) { .fields = (VMStateField []) {
VMSTATE_PCI_DEVICE(dev, UHCIState), VMSTATE_PCI_DEVICE(dev, UHCIState),
VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState), VMSTATE_UINT8_EQUAL(num_ports_vmstate, UHCIState),
@ -905,7 +902,9 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet)
uhci_async_free(async); uhci_async_free(async);
} else { } else {
async->done = 1; async->done = 1;
uhci_process_frame(s); if (s->frame_bytes < s->frame_bandwidth) {
qemu_bh_schedule(s->bh);
}
} }
} }
@ -985,7 +984,7 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td)
static void uhci_process_frame(UHCIState *s) static void uhci_process_frame(UHCIState *s)
{ {
uint32_t frame_addr, link, old_td_ctrl, val, int_mask; uint32_t frame_addr, link, old_td_ctrl, val, int_mask;
uint32_t curr_qh, td_count = 0, bytes_count = 0; uint32_t curr_qh, td_count = 0;
int cnt, ret; int cnt, ret;
UHCI_TD td; UHCI_TD td;
UHCI_QH qh; UHCI_QH qh;
@ -1002,6 +1001,12 @@ static void uhci_process_frame(UHCIState *s)
qhdb_reset(&qhdb); qhdb_reset(&qhdb);
for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) { for (cnt = FRAME_MAX_LOOPS; is_valid(link) && cnt; cnt--) {
if (s->frame_bytes >= s->frame_bandwidth) {
/* We've reached the usb 1.1 bandwidth, which is
1280 bytes/frame, stop processing */
trace_usb_uhci_frame_stop_bandwidth();
break;
}
if (is_qh(link)) { if (is_qh(link)) {
/* QH */ /* QH */
trace_usb_uhci_qh_load(link & ~0xf); trace_usb_uhci_qh_load(link & ~0xf);
@ -1011,18 +1016,12 @@ static void uhci_process_frame(UHCIState *s)
* We're going in circles. Which is not a bug because * We're going in circles. Which is not a bug because
* HCD is allowed to do that as part of the BW management. * HCD is allowed to do that as part of the BW management.
* *
* Stop processing here if * Stop processing here if no transaction has been done
* (a) no transaction has been done since we've been * since we've been here last time.
* here last time, or
* (b) we've reached the usb 1.1 bandwidth, which is
* 1280 bytes/frame.
*/ */
if (td_count == 0) { if (td_count == 0) {
trace_usb_uhci_frame_loop_stop_idle(); trace_usb_uhci_frame_loop_stop_idle();
break; break;
} else if (bytes_count >= 1280) {
trace_usb_uhci_frame_loop_stop_bandwidth();
break;
} else { } else {
trace_usb_uhci_frame_loop_continue(); trace_usb_uhci_frame_loop_continue();
td_count = 0; td_count = 0;
@ -1085,7 +1084,7 @@ static void uhci_process_frame(UHCIState *s)
trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf); trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf);
link = td.link; link = td.link;
td_count++; td_count++;
bytes_count += (td.ctrl & 0x7ff) + 1; s->frame_bytes += (td.ctrl & 0x7ff) + 1;
if (curr_qh) { if (curr_qh) {
/* update QH element link */ /* update QH element link */
@ -1112,12 +1111,20 @@ out:
s->pending_int_mask |= int_mask; s->pending_int_mask |= int_mask;
} }
static void uhci_bh(void *opaque)
{
UHCIState *s = opaque;
uhci_process_frame(s);
}
static void uhci_frame_timer(void *opaque) static void uhci_frame_timer(void *opaque)
{ {
UHCIState *s = opaque; UHCIState *s = opaque;
/* prepare the timer for the next frame */ /* prepare the timer for the next frame */
s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ); s->expire_time += (get_ticks_per_sec() / FRAME_TIMER_FREQ);
s->frame_bytes = 0;
qemu_bh_cancel(s->bh);
if (!(s->cmd & UHCI_CMD_RS)) { if (!(s->cmd & UHCI_CMD_RS)) {
/* Full stop */ /* Full stop */
@ -1178,15 +1185,31 @@ static USBBusOps uhci_bus_ops = {
static int usb_uhci_common_initfn(PCIDevice *dev) static int usb_uhci_common_initfn(PCIDevice *dev)
{ {
PCIDeviceClass *pc = PCI_DEVICE_GET_CLASS(dev);
UHCIState *s = DO_UPCAST(UHCIState, dev, dev); UHCIState *s = DO_UPCAST(UHCIState, dev, dev);
uint8_t *pci_conf = s->dev.config; uint8_t *pci_conf = s->dev.config;
int i; int i;
pci_conf[PCI_CLASS_PROG] = 0x00; pci_conf[PCI_CLASS_PROG] = 0x00;
/* TODO: reset value should be 0. */ /* TODO: reset value should be 0. */
pci_conf[PCI_INTERRUPT_PIN] = 4; /* interrupt pin D */
pci_conf[USB_SBRN] = USB_RELEASE_1; // release number pci_conf[USB_SBRN] = USB_RELEASE_1; // release number
switch (pc->device_id) {
case PCI_DEVICE_ID_INTEL_82801I_UHCI1:
s->irq_pin = 0; /* A */
break;
case PCI_DEVICE_ID_INTEL_82801I_UHCI2:
s->irq_pin = 1; /* B */
break;
case PCI_DEVICE_ID_INTEL_82801I_UHCI3:
s->irq_pin = 2; /* C */
break;
default:
s->irq_pin = 3; /* D */
break;
}
pci_config_set_interrupt_pin(pci_conf, s->irq_pin + 1);
if (s->masterbus) { if (s->masterbus) {
USBPort *ports[NB_PORTS]; USBPort *ports[NB_PORTS];
for(i = 0; i < NB_PORTS; i++) { for(i = 0; i < NB_PORTS; i++) {
@ -1204,6 +1227,7 @@ static int usb_uhci_common_initfn(PCIDevice *dev)
USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
} }
} }
s->bh = qemu_bh_new(uhci_bh, s);
s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s); s->frame_timer = qemu_new_timer_ns(vm_clock, uhci_frame_timer, s);
s->num_ports_vmstate = NB_PORTS; s->num_ports_vmstate = NB_PORTS;
QTAILQ_INIT(&s->queues); QTAILQ_INIT(&s->queues);
@ -1244,6 +1268,7 @@ static int usb_uhci_exit(PCIDevice *dev)
static Property uhci_properties[] = { static Property uhci_properties[] = {
DEFINE_PROP_STRING("masterbus", UHCIState, masterbus), DEFINE_PROP_STRING("masterbus", UHCIState, masterbus),
DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0), DEFINE_PROP_UINT32("firstport", UHCIState, firstport, 0),
DEFINE_PROP_UINT32("bandwidth", UHCIState, frame_bandwidth, 1280),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };

View File

@ -23,6 +23,7 @@
#include "hw/usb.h" #include "hw/usb.h"
#include "hw/pci.h" #include "hw/pci.h"
#include "hw/msi.h" #include "hw/msi.h"
#include "trace.h"
//#define DEBUG_XHCI //#define DEBUG_XHCI
//#define DEBUG_DATA //#define DEBUG_DATA
@ -421,7 +422,6 @@ typedef struct XHCIEvRingSeg {
uint32_t rsvd; uint32_t rsvd;
} XHCIEvRingSeg; } XHCIEvRingSeg;
#ifdef DEBUG_XHCI
static const char *TRBType_names[] = { static const char *TRBType_names[] = {
[TRB_RESERVED] = "TRB_RESERVED", [TRB_RESERVED] = "TRB_RESERVED",
[TR_NORMAL] = "TR_NORMAL", [TR_NORMAL] = "TR_NORMAL",
@ -473,7 +473,6 @@ static const char *trb_name(XHCITRB *trb)
return lookup_name(TRB_TYPE(*trb), TRBType_names, return lookup_name(TRB_TYPE(*trb), TRBType_names,
ARRAY_SIZE(TRBType_names)); ARRAY_SIZE(TRBType_names));
} }
#endif
static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid,
unsigned int epid); unsigned int epid);
@ -505,14 +504,13 @@ static void xhci_irq_update(XHCIState *xhci)
level = 1; level = 1;
} }
DPRINTF("xhci_irq_update(): %d\n", level);
if (xhci->msi && msi_enabled(&xhci->pci_dev)) { if (xhci->msi && msi_enabled(&xhci->pci_dev)) {
if (level) { if (level) {
DPRINTF("xhci_irq_update(): MSI signal\n"); trace_usb_xhci_irq_msi(0);
msi_notify(&xhci->pci_dev, 0); msi_notify(&xhci->pci_dev, 0);
} }
} else { } else {
trace_usb_xhci_irq_intx(level);
qemu_set_irq(xhci->irq, level); qemu_set_irq(xhci->irq, level);
} }
} }
@ -542,9 +540,8 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event)
} }
ev_trb.control = cpu_to_le32(ev_trb.control); ev_trb.control = cpu_to_le32(ev_trb.control);
DPRINTF("xhci_write_event(): [%d] %016"PRIx64" %08x %08x %s\n", trace_usb_xhci_queue_event(xhci->er_ep_idx, trb_name(&ev_trb),
xhci->er_ep_idx, ev_trb.parameter, ev_trb.status, ev_trb.control, ev_trb.parameter, ev_trb.status, ev_trb.control);
trb_name(&ev_trb));
addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx; addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx;
pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE); pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE);
@ -704,10 +701,8 @@ static TRBType xhci_ring_fetch(XHCIState *xhci, XHCIRing *ring, XHCITRB *trb,
le32_to_cpus(&trb->status); le32_to_cpus(&trb->status);
le32_to_cpus(&trb->control); le32_to_cpus(&trb->control);
DPRINTF("xhci: TRB fetched [" DMA_ADDR_FMT "]: " trace_usb_xhci_fetch_trb(ring->dequeue, trb_name(trb),
"%016" PRIx64 " %08x %08x %s\n", trb->parameter, trb->status, trb->control);
ring->dequeue, trb->parameter, trb->status, trb->control,
trb_name(trb));
if ((trb->control & TRB_C) != ring->ccs) { if ((trb->control & TRB_C) != ring->ccs) {
return 0; return 0;
@ -746,10 +741,6 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring)
le32_to_cpus(&trb.status); le32_to_cpus(&trb.status);
le32_to_cpus(&trb.control); le32_to_cpus(&trb.control);
DPRINTF("xhci: TRB peeked [" DMA_ADDR_FMT "]: "
"%016" PRIx64 " %08x %08x\n",
dequeue, trb.parameter, trb.status, trb.control);
if ((trb.control & TRB_C) != ccs) { if ((trb.control & TRB_C) != ccs) {
return -length; return -length;
} }
@ -812,14 +803,13 @@ static void xhci_er_reset(XHCIState *xhci)
static void xhci_run(XHCIState *xhci) static void xhci_run(XHCIState *xhci)
{ {
DPRINTF("xhci_run()\n"); trace_usb_xhci_run();
xhci->usbsts &= ~USBSTS_HCH; xhci->usbsts &= ~USBSTS_HCH;
} }
static void xhci_stop(XHCIState *xhci) static void xhci_stop(XHCIState *xhci)
{ {
DPRINTF("xhci_stop()\n"); trace_usb_xhci_stop();
xhci->usbsts |= USBSTS_HCH; xhci->usbsts |= USBSTS_HCH;
xhci->crcr_low &= ~CRCR_CRR; xhci->crcr_low &= ~CRCR_CRR;
} }
@ -852,11 +842,10 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid,
dma_addr_t dequeue; dma_addr_t dequeue;
int i; int i;
trace_usb_xhci_ep_enable(slotid, epid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(epid >= 1 && epid <= 31); assert(epid >= 1 && epid <= 31);
DPRINTF("xhci_enable_ep(%d, %d)\n", slotid, epid);
slot = &xhci->slots[slotid-1]; slot = &xhci->slots[slotid-1];
if (slot->eps[epid-1]) { if (slot->eps[epid-1]) {
fprintf(stderr, "xhci: slot %d ep %d already enabled!\n", slotid, epid); fprintf(stderr, "xhci: slot %d ep %d already enabled!\n", slotid, epid);
@ -971,11 +960,10 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid,
XHCISlot *slot; XHCISlot *slot;
XHCIEPContext *epctx; XHCIEPContext *epctx;
trace_usb_xhci_ep_disable(slotid, epid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(epid >= 1 && epid <= 31); assert(epid >= 1 && epid <= 31);
DPRINTF("xhci_disable_ep(%d, %d)\n", slotid, epid);
slot = &xhci->slots[slotid-1]; slot = &xhci->slots[slotid-1];
if (!slot->eps[epid-1]) { if (!slot->eps[epid-1]) {
@ -1001,8 +989,7 @@ static TRBCCode xhci_stop_ep(XHCIState *xhci, unsigned int slotid,
XHCISlot *slot; XHCISlot *slot;
XHCIEPContext *epctx; XHCIEPContext *epctx;
DPRINTF("xhci_stop_ep(%d, %d)\n", slotid, epid); trace_usb_xhci_ep_stop(slotid, epid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
if (epid < 1 || epid > 31) { if (epid < 1 || epid > 31) {
@ -1036,10 +1023,9 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid,
XHCIEPContext *epctx; XHCIEPContext *epctx;
USBDevice *dev; USBDevice *dev;
trace_usb_xhci_ep_reset(slotid, epid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
DPRINTF("xhci_reset_ep(%d, %d)\n", slotid, epid);
if (epid < 1 || epid > 31) { if (epid < 1 || epid > 31) {
fprintf(stderr, "xhci: bad ep %d\n", epid); fprintf(stderr, "xhci: bad ep %d\n", epid);
return CC_TRB_ERROR; return CC_TRB_ERROR;
@ -1416,12 +1402,14 @@ static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev)
static int xhci_complete_packet(XHCITransfer *xfer, int ret) static int xhci_complete_packet(XHCITransfer *xfer, int ret)
{ {
if (ret == USB_RET_ASYNC) { if (ret == USB_RET_ASYNC) {
trace_usb_xhci_xfer_async(xfer);
xfer->running_async = 1; xfer->running_async = 1;
xfer->running_retry = 0; xfer->running_retry = 0;
xfer->complete = 0; xfer->complete = 0;
xfer->cancelled = 0; xfer->cancelled = 0;
return 0; return 0;
} else if (ret == USB_RET_NAK) { } else if (ret == USB_RET_NAK) {
trace_usb_xhci_xfer_nak(xfer);
xfer->running_async = 0; xfer->running_async = 0;
xfer->running_retry = 1; xfer->running_retry = 1;
xfer->complete = 0; xfer->complete = 0;
@ -1436,10 +1424,12 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret)
if (ret >= 0) { if (ret >= 0) {
xfer->status = CC_SUCCESS; xfer->status = CC_SUCCESS;
xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1); xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1);
trace_usb_xhci_xfer_success(xfer, ret);
return 0; return 0;
} }
/* error */ /* error */
trace_usb_xhci_xfer_error(xfer, ret);
switch (ret) { switch (ret) {
case USB_RET_NODEV: case USB_RET_NODEV:
xfer->status = CC_USB_TRANSACTION_ERROR; xfer->status = CC_USB_TRANSACTION_ERROR;
@ -1475,11 +1465,12 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer)
USBDevice *dev; USBDevice *dev;
int ret; int ret;
DPRINTF("xhci_fire_ctl_transfer(slot=%d)\n", xfer->slotid);
trb_setup = &xfer->trbs[0]; trb_setup = &xfer->trbs[0];
trb_status = &xfer->trbs[xfer->trb_count-1]; trb_status = &xfer->trbs[xfer->trb_count-1];
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid,
trb_setup->parameter >> 48);
/* at most one Event Data TRB allowed after STATUS */ /* at most one Event Data TRB allowed after STATUS */
if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) { if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) {
trb_status--; trb_status--;
@ -1620,15 +1611,14 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext
unsigned int length = 0; unsigned int length = 0;
XHCITRB *trb; XHCITRB *trb;
DPRINTF("xhci_fire_transfer(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid);
for (i = 0; i < xfer->trb_count; i++) { for (i = 0; i < xfer->trb_count; i++) {
trb = &xfer->trbs[i]; trb = &xfer->trbs[i];
if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) { if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) {
length += trb->status & 0x1ffff; length += trb->status & 0x1ffff;
} }
} }
DPRINTF("xhci: total TD length=%d\n", length);
trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length);
if (!epctx->has_bg) { if (!epctx->has_bg) {
xfer->data_length = length; xfer->data_length = length;
@ -1664,9 +1654,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
int length; int length;
int i; int i;
trace_usb_xhci_ep_kick(slotid, epid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
assert(epid >= 1 && epid <= 31); assert(epid >= 1 && epid <= 31);
DPRINTF("xhci_kick_ep(%d, %d)\n", slotid, epid);
if (!xhci->slots[slotid-1].enabled) { if (!xhci->slots[slotid-1].enabled) {
fprintf(stderr, "xhci: xhci_kick_ep for disabled slot %d\n", slotid); fprintf(stderr, "xhci: xhci_kick_ep for disabled slot %d\n", slotid);
@ -1684,15 +1674,13 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
XHCITransfer *xfer = epctx->retry; XHCITransfer *xfer = epctx->retry;
int result; int result;
DPRINTF("xhci: retry nack'ed transfer ...\n"); trace_usb_xhci_xfer_retry(xfer);
assert(xfer->running_retry); assert(xfer->running_retry);
xhci_setup_packet(xfer, xfer->packet.ep->dev); xhci_setup_packet(xfer, xfer->packet.ep->dev);
result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet);
if (result == USB_RET_NAK) { if (result == USB_RET_NAK) {
DPRINTF("xhci: ... xfer still nacked\n");
return; return;
} }
DPRINTF("xhci: ... result %d\n", result);
xhci_complete_packet(xfer, result); xhci_complete_packet(xfer, result);
assert(!xfer->running_retry); assert(!xfer->running_retry);
epctx->retry = NULL; epctx->retry = NULL;
@ -1708,21 +1696,14 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
while (1) { while (1) {
XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer]; XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer];
if (xfer->running_async || xfer->running_retry || xfer->backgrounded) { if (xfer->running_async || xfer->running_retry || xfer->backgrounded) {
DPRINTF("xhci: ep is busy (#%d,%d,%d,%d)\n",
epctx->next_xfer, xfer->running_async,
xfer->running_retry, xfer->backgrounded);
break; break;
} else {
DPRINTF("xhci: ep: using #%d\n", epctx->next_xfer);
} }
length = xhci_ring_chain_length(xhci, &epctx->ring); length = xhci_ring_chain_length(xhci, &epctx->ring);
if (length < 0) { if (length < 0) {
DPRINTF("xhci: incomplete TD (%d TRBs)\n", -length);
break; break;
} else if (length == 0) { } else if (length == 0) {
break; break;
} }
DPRINTF("xhci: fetching %d-TRB TD\n", length);
if (xfer->trbs && xfer->trb_alloced < length) { if (xfer->trbs && xfer->trb_alloced < length) {
xfer->trb_count = 0; xfer->trb_count = 0;
xfer->trb_alloced = 0; xfer->trb_alloced = 0;
@ -1757,7 +1738,6 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
} }
if (epctx->state == EP_HALTED) { if (epctx->state == EP_HALTED) {
DPRINTF("xhci: ep halted, stopping schedule\n");
break; break;
} }
if (xfer->running_retry) { if (xfer->running_retry) {
@ -1770,8 +1750,8 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid
static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid) static TRBCCode xhci_enable_slot(XHCIState *xhci, unsigned int slotid)
{ {
trace_usb_xhci_slot_enable(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
DPRINTF("xhci_enable_slot(%d)\n", slotid);
xhci->slots[slotid-1].enabled = 1; xhci->slots[slotid-1].enabled = 1;
xhci->slots[slotid-1].port = 0; xhci->slots[slotid-1].port = 0;
memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31); memset(xhci->slots[slotid-1].eps, 0, sizeof(XHCIEPContext*)*31);
@ -1783,8 +1763,8 @@ static TRBCCode xhci_disable_slot(XHCIState *xhci, unsigned int slotid)
{ {
int i; int i;
trace_usb_xhci_slot_disable(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
DPRINTF("xhci_disable_slot(%d)\n", slotid);
for (i = 1; i <= 31; i++) { for (i = 1; i <= 31; i++) {
if (xhci->slots[slotid-1].eps[i-1]) { if (xhci->slots[slotid-1].eps[i-1]) {
@ -1810,8 +1790,8 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid,
int i; int i;
TRBCCode res; TRBCCode res;
trace_usb_xhci_slot_address(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
DPRINTF("xhci_address_slot(%d)\n", slotid);
dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high); dcbaap = xhci_addr64(xhci->dcbaap_low, xhci->dcbaap_high);
pci_dma_read(&xhci->pci_dev, dcbaap + 8*slotid, &poctx, sizeof(poctx)); pci_dma_read(&xhci->pci_dev, dcbaap + 8*slotid, &poctx, sizeof(poctx));
@ -1897,8 +1877,8 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid,
int i; int i;
TRBCCode res; TRBCCode res;
trace_usb_xhci_slot_configure(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
DPRINTF("xhci_configure_slot(%d)\n", slotid);
ictx = xhci_mask64(pictx); ictx = xhci_mask64(pictx);
octx = xhci->slots[slotid-1].ctx; octx = xhci->slots[slotid-1].ctx;
@ -1985,8 +1965,8 @@ static TRBCCode xhci_evaluate_slot(XHCIState *xhci, unsigned int slotid,
uint32_t islot_ctx[4]; uint32_t islot_ctx[4];
uint32_t slot_ctx[4]; uint32_t slot_ctx[4];
trace_usb_xhci_slot_evaluate(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
DPRINTF("xhci_evaluate_slot(%d)\n", slotid);
ictx = xhci_mask64(pictx); ictx = xhci_mask64(pictx);
octx = xhci->slots[slotid-1].ctx; octx = xhci->slots[slotid-1].ctx;
@ -2048,8 +2028,8 @@ static TRBCCode xhci_reset_slot(XHCIState *xhci, unsigned int slotid)
dma_addr_t octx; dma_addr_t octx;
int i; int i;
trace_usb_xhci_slot_reset(slotid);
assert(slotid >= 1 && slotid <= MAXSLOTS); assert(slotid >= 1 && slotid <= MAXSLOTS);
DPRINTF("xhci_reset_slot(%d)\n", slotid);
octx = xhci->slots[slotid-1].ctx; octx = xhci->slots[slotid-1].ctx;
@ -2296,12 +2276,12 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach)
} }
} }
static void xhci_reset(void *opaque) static void xhci_reset(DeviceState *dev)
{ {
XHCIState *xhci = opaque; XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev.qdev, dev);
int i; int i;
DPRINTF("xhci: full reset\n"); trace_usb_xhci_reset();
if (!(xhci->usbsts & USBSTS_HCH)) { if (!(xhci->usbsts & USBSTS_HCH)) {
fprintf(stderr, "xhci: reset while running!\n"); fprintf(stderr, "xhci: reset while running!\n");
} }
@ -2342,77 +2322,98 @@ static void xhci_reset(void *opaque)
static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg)
{ {
DPRINTF("xhci_cap_read(0x%x)\n", reg); uint32_t ret;
switch (reg) { switch (reg) {
case 0x00: /* HCIVERSION, CAPLENGTH */ case 0x00: /* HCIVERSION, CAPLENGTH */
return 0x01000000 | LEN_CAP; ret = 0x01000000 | LEN_CAP;
break;
case 0x04: /* HCSPARAMS 1 */ case 0x04: /* HCSPARAMS 1 */
return (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS; ret = (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS;
break;
case 0x08: /* HCSPARAMS 2 */ case 0x08: /* HCSPARAMS 2 */
return 0x0000000f; ret = 0x0000000f;
break;
case 0x0c: /* HCSPARAMS 3 */ case 0x0c: /* HCSPARAMS 3 */
return 0x00000000; ret = 0x00000000;
break;
case 0x10: /* HCCPARAMS */ case 0x10: /* HCCPARAMS */
#if TARGET_PHYS_ADDR_BITS > 32 if (sizeof(dma_addr_t) == 4) {
return 0x00081001; ret = 0x00081000;
#else } else {
return 0x00081000; ret = 0x00081001;
#endif }
break;
case 0x14: /* DBOFF */ case 0x14: /* DBOFF */
return OFF_DOORBELL; ret = OFF_DOORBELL;
break;
case 0x18: /* RTSOFF */ case 0x18: /* RTSOFF */
return OFF_RUNTIME; ret = OFF_RUNTIME;
break;
/* extended capabilities */ /* extended capabilities */
case 0x20: /* Supported Protocol:00 */ case 0x20: /* Supported Protocol:00 */
#if USB3_PORTS > 0 ret = 0x02000402; /* USB 2.0 */
return 0x02000402; /* USB 2.0 */ break;
#else
return 0x02000002; /* USB 2.0 */
#endif
case 0x24: /* Supported Protocol:04 */ case 0x24: /* Supported Protocol:04 */
return 0x20425455; /* "USB " */ ret = 0x20425455; /* "USB " */
break;
case 0x28: /* Supported Protocol:08 */ case 0x28: /* Supported Protocol:08 */
return 0x00000001 | (USB2_PORTS<<8); ret = 0x00000001 | (USB2_PORTS<<8);
break;
case 0x2c: /* Supported Protocol:0c */ case 0x2c: /* Supported Protocol:0c */
return 0x00000000; /* reserved */ ret = 0x00000000; /* reserved */
#if USB3_PORTS > 0 break;
case 0x30: /* Supported Protocol:00 */ case 0x30: /* Supported Protocol:00 */
return 0x03000002; /* USB 3.0 */ ret = 0x03000002; /* USB 3.0 */
break;
case 0x34: /* Supported Protocol:04 */ case 0x34: /* Supported Protocol:04 */
return 0x20425455; /* "USB " */ ret = 0x20425455; /* "USB " */
break;
case 0x38: /* Supported Protocol:08 */ case 0x38: /* Supported Protocol:08 */
return 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8); ret = 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8);
break;
case 0x3c: /* Supported Protocol:0c */ case 0x3c: /* Supported Protocol:0c */
return 0x00000000; /* reserved */ ret = 0x00000000; /* reserved */
#endif break;
default: default:
fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg); fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg);
ret = 0;
} }
return 0;
trace_usb_xhci_cap_read(reg, ret);
return ret;
} }
static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg) static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg)
{ {
uint32_t port = reg >> 4; uint32_t port = reg >> 4;
uint32_t ret;
if (port >= MAXPORTS) { if (port >= MAXPORTS) {
fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
return 0; ret = 0;
goto out;
} }
switch (reg & 0xf) { switch (reg & 0xf) {
case 0x00: /* PORTSC */ case 0x00: /* PORTSC */
return xhci->ports[port].portsc; ret = xhci->ports[port].portsc;
break;
case 0x04: /* PORTPMSC */ case 0x04: /* PORTPMSC */
case 0x08: /* PORTLI */ case 0x08: /* PORTLI */
return 0; ret = 0;
break;
case 0x0c: /* reserved */ case 0x0c: /* reserved */
default: default:
fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n", fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n",
port, reg); port, reg);
return 0; ret = 0;
} }
out:
trace_usb_xhci_port_read(port, reg & 0x0f, ret);
return ret;
} }
static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
@ -2420,6 +2421,8 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
uint32_t port = reg >> 4; uint32_t port = reg >> 4;
uint32_t portsc; uint32_t portsc;
trace_usb_xhci_port_write(port, reg & 0x0f, val);
if (port >= MAXPORTS) { if (port >= MAXPORTS) {
fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port);
return; return;
@ -2457,7 +2460,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val)
static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg)
{ {
DPRINTF("xhci_oper_read(0x%x)\n", reg); uint32_t ret;
if (reg >= 0x400) { if (reg >= 0x400) {
return xhci_port_read(xhci, reg - 0x400); return xhci_port_read(xhci, reg - 0x400);
@ -2465,38 +2468,50 @@ static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg)
switch (reg) { switch (reg) {
case 0x00: /* USBCMD */ case 0x00: /* USBCMD */
return xhci->usbcmd; ret = xhci->usbcmd;
break;
case 0x04: /* USBSTS */ case 0x04: /* USBSTS */
return xhci->usbsts; ret = xhci->usbsts;
break;
case 0x08: /* PAGESIZE */ case 0x08: /* PAGESIZE */
return 1; /* 4KiB */ ret = 1; /* 4KiB */
break;
case 0x14: /* DNCTRL */ case 0x14: /* DNCTRL */
return xhci->dnctrl; ret = xhci->dnctrl;
break;
case 0x18: /* CRCR low */ case 0x18: /* CRCR low */
return xhci->crcr_low & ~0xe; ret = xhci->crcr_low & ~0xe;
break;
case 0x1c: /* CRCR high */ case 0x1c: /* CRCR high */
return xhci->crcr_high; ret = xhci->crcr_high;
break;
case 0x30: /* DCBAAP low */ case 0x30: /* DCBAAP low */
return xhci->dcbaap_low; ret = xhci->dcbaap_low;
break;
case 0x34: /* DCBAAP high */ case 0x34: /* DCBAAP high */
return xhci->dcbaap_high; ret = xhci->dcbaap_high;
break;
case 0x38: /* CONFIG */ case 0x38: /* CONFIG */
return xhci->config; ret = xhci->config;
break;
default: default:
fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg); fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg);
ret = 0;
} }
return 0;
trace_usb_xhci_oper_read(reg, ret);
return ret;
} }
static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
{ {
DPRINTF("xhci_oper_write(0x%x, 0x%08x)\n", reg, val);
if (reg >= 0x400) { if (reg >= 0x400) {
xhci_port_write(xhci, reg - 0x400, val); xhci_port_write(xhci, reg - 0x400, val);
return; return;
} }
trace_usb_xhci_oper_write(reg, val);
switch (reg) { switch (reg) {
case 0x00: /* USBCMD */ case 0x00: /* USBCMD */
if ((val & USBCMD_RS) && !(xhci->usbcmd & USBCMD_RS)) { if ((val & USBCMD_RS) && !(xhci->usbcmd & USBCMD_RS)) {
@ -2506,7 +2521,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
} }
xhci->usbcmd = val & 0xc0f; xhci->usbcmd = val & 0xc0f;
if (val & USBCMD_HCRST) { if (val & USBCMD_HCRST) {
xhci_reset(xhci); xhci_reset(&xhci->pci_dev.qdev);
} }
xhci_irq_update(xhci); xhci_irq_update(xhci);
break; break;
@ -2552,35 +2567,46 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val)
static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg)
{ {
DPRINTF("xhci_runtime_read(0x%x)\n", reg); uint32_t ret;
switch (reg) { switch (reg) {
case 0x00: /* MFINDEX */ case 0x00: /* MFINDEX */
fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n"); fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n");
return xhci->mfindex; ret = xhci->mfindex;
break;
case 0x20: /* IMAN */ case 0x20: /* IMAN */
return xhci->iman; ret = xhci->iman;
break;
case 0x24: /* IMOD */ case 0x24: /* IMOD */
return xhci->imod; ret = xhci->imod;
break;
case 0x28: /* ERSTSZ */ case 0x28: /* ERSTSZ */
return xhci->erstsz; ret = xhci->erstsz;
break;
case 0x30: /* ERSTBA low */ case 0x30: /* ERSTBA low */
return xhci->erstba_low; ret = xhci->erstba_low;
break;
case 0x34: /* ERSTBA high */ case 0x34: /* ERSTBA high */
return xhci->erstba_high; ret = xhci->erstba_high;
break;
case 0x38: /* ERDP low */ case 0x38: /* ERDP low */
return xhci->erdp_low; ret = xhci->erdp_low;
break;
case 0x3c: /* ERDP high */ case 0x3c: /* ERDP high */
return xhci->erdp_high; ret = xhci->erdp_high;
break;
default: default:
fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg);
ret = 0;
} }
return 0;
trace_usb_xhci_runtime_read(reg, ret);
return ret;
} }
static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
{ {
DPRINTF("xhci_runtime_write(0x%x, 0x%08x)\n", reg, val); trace_usb_xhci_runtime_read(reg, val);
switch (reg) { switch (reg) {
case 0x20: /* IMAN */ case 0x20: /* IMAN */
@ -2623,14 +2649,14 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val)
static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg) static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg)
{ {
DPRINTF("xhci_doorbell_read(0x%x)\n", reg);
/* doorbells always read as 0 */ /* doorbells always read as 0 */
trace_usb_xhci_doorbell_read(reg, 0);
return 0; return 0;
} }
static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val) static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val)
{ {
DPRINTF("xhci_doorbell_write(0x%x, 0x%08x)\n", reg, val); trace_usb_xhci_doorbell_write(reg, val);
if (!xhci_running(xhci)) { if (!xhci_running(xhci)) {
fprintf(stderr, "xhci: wrote doorbell while xHC stopped or paused\n"); fprintf(stderr, "xhci: wrote doorbell while xHC stopped or paused\n");
@ -2831,8 +2857,6 @@ static void usb_xhci_init(XHCIState *xhci, DeviceState *dev)
for (i = 0; i < MAXSLOTS; i++) { for (i = 0; i < MAXSLOTS; i++) {
xhci->slots[i].enabled = 0; xhci->slots[i].enabled = 0;
} }
qemu_register_reset(xhci_reset, xhci);
} }
static int usb_xhci_initfn(struct PCIDevice *dev) static int usb_xhci_initfn(struct PCIDevice *dev)
@ -2895,6 +2919,7 @@ static void xhci_class_init(ObjectClass *klass, void *data)
dc->vmsd = &vmstate_xhci; dc->vmsd = &vmstate_xhci;
dc->props = xhci_properties; dc->props = xhci_properties;
dc->reset = xhci_reset;
k->init = usb_xhci_initfn; k->init = usb_xhci_initfn;
k->vendor_id = PCI_VENDOR_ID_NEC; k->vendor_id = PCI_VENDOR_ID_NEC;
k->device_id = PCI_DEVICE_ID_NEC_UPD720200; k->device_id = PCI_DEVICE_ID_NEC_UPD720200;

View File

@ -257,19 +257,20 @@ usb_ehci_port_detach(uint32_t port) "detach port #%d"
usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d" usb_ehci_port_reset(uint32_t port, int enable) "reset port #%d - %d"
usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d" usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t len, uint32_t bufpos) "write %d, cpage %d, offset 0x%03x, addr 0x%08x, len %d, bufpos %d"
usb_ehci_queue_action(void *q, const char *action) "q %p: %s" usb_ehci_queue_action(void *q, const char *action) "q %p: %s"
usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s"
# hw/usb/hcd-uhci.c # hw/usb/hcd-uhci.c
usb_uhci_reset(void) "=== RESET ===" usb_uhci_reset(void) "=== RESET ==="
usb_uhci_schedule_start(void) "" usb_uhci_schedule_start(void) ""
usb_uhci_schedule_stop(void) "" usb_uhci_schedule_stop(void) ""
usb_uhci_frame_start(uint32_t num) "nr %d" usb_uhci_frame_start(uint32_t num) "nr %d"
usb_uhci_frame_stop_bandwidth(void) ""
usb_uhci_frame_loop_stop_idle(void) "" usb_uhci_frame_loop_stop_idle(void) ""
usb_uhci_frame_loop_stop_bandwidth(void) ""
usb_uhci_frame_loop_continue(void) "" usb_uhci_frame_loop_continue(void) ""
usb_uhci_mmio_readw(uint32_t addr, uint32_t val) "addr %04x, ret 0x04%x" usb_uhci_mmio_readw(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%04x"
usb_uhci_mmio_writew(uint32_t addr, uint32_t val) "addr %04x, val 0x04%x" usb_uhci_mmio_writew(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%04x"
usb_uhci_mmio_readl(uint32_t addr, uint32_t val) "addr %04x, ret 0x08%x" usb_uhci_mmio_readl(uint32_t addr, uint32_t val) "addr 0x%04x, ret 0x%08x"
usb_uhci_mmio_writel(uint32_t addr, uint32_t val) "addr %04x, val 0x08%x" usb_uhci_mmio_writel(uint32_t addr, uint32_t val) "addr 0x%04x, val 0x%08x"
usb_uhci_queue_add(uint32_t token) "token 0x%x" usb_uhci_queue_add(uint32_t token) "token 0x%x"
usb_uhci_queue_del(uint32_t token) "token 0x%x" usb_uhci_queue_del(uint32_t token) "token 0x%x"
usb_uhci_packet_add(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x" usb_uhci_packet_add(uint32_t token, uint32_t addr) "token 0x%x, td 0x%x"
@ -289,6 +290,41 @@ usb_uhci_td_nextqh(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
usb_uhci_td_async(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x" usb_uhci_td_async(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
usb_uhci_td_complete(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x" usb_uhci_td_complete(uint32_t qh, uint32_t td) "qh 0x%x, td 0x%x"
# hw/usb/hcd-xhci.c
usb_xhci_reset(void) "=== RESET ==="
usb_xhci_run(void) ""
usb_xhci_stop(void) ""
usb_xhci_cap_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x"
usb_xhci_oper_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x"
usb_xhci_port_read(uint32_t port, uint32_t off, uint32_t val) "port %d, off 0x%04x, ret 0x%08x"
usb_xhci_runtime_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x"
usb_xhci_doorbell_read(uint32_t off, uint32_t val) "off 0x%04x, ret 0x%08x"
usb_xhci_oper_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x"
usb_xhci_port_write(uint32_t port, uint32_t off, uint32_t val) "port %d, off 0x%04x, val 0x%08x"
usb_xhci_runtime_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x"
usb_xhci_doorbell_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x"
usb_xhci_irq_intx(uint32_t level) "level %d"
usb_xhci_irq_msi(uint32_t nr) "nr %d"
usb_xhci_queue_event(uint32_t idx, const char *name, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, p %016" PRIx64 ", s %08x, c 0x%08x"
usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x"
usb_xhci_slot_enable(uint32_t slotid) "slotid %d"
usb_xhci_slot_disable(uint32_t slotid) "slotid %d"
usb_xhci_slot_address(uint32_t slotid) "slotid %d"
usb_xhci_slot_configure(uint32_t slotid) "slotid %d"
usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d"
usb_xhci_slot_reset(uint32_t slotid) "slotid %d"
usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d"
usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t length) "%p: slotid %d, epid %d, length %d"
usb_xhci_xfer_async(void *xfer) "%p"
usb_xhci_xfer_nak(void *xfer) "%p"
usb_xhci_xfer_retry(void *xfer) "%p"
usb_xhci_xfer_success(void *xfer, uint32_t bytes) "%p: len %d"
usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d"
# 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"
usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d" usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device qualifier, len %d, ret %d"