diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/char/cadence_uart.c | 4 | ||||
-rw-r--r-- | hw/display/vmware_vga.c | 1 | ||||
-rw-r--r-- | hw/i386/acpi-build.c | 5 | ||||
-rw-r--r-- | hw/i386/pc_piix.c | 16 | ||||
-rw-r--r-- | hw/i386/pc_q35.c | 13 | ||||
-rw-r--r-- | hw/net/virtio-net.c | 2 | ||||
-rw-r--r-- | hw/nvram/eeprom93xx.c | 62 | ||||
-rw-r--r-- | hw/ppc/mac.h | 1 | ||||
-rw-r--r-- | hw/ppc/ppc.c | 6 | ||||
-rw-r--r-- | hw/ppc/ppc405_uc.c | 2 | ||||
-rw-r--r-- | hw/ppc/ppc_booke.c | 4 | ||||
-rw-r--r-- | hw/scsi/scsi-bus.c | 10 | ||||
-rw-r--r-- | hw/scsi/scsi-disk.c | 154 | ||||
-rw-r--r-- | hw/timer/m48t59.c | 4 | ||||
-rw-r--r-- | hw/usb/bus.c | 18 | ||||
-rw-r--r-- | hw/usb/core.c | 22 | ||||
-rw-r--r-- | hw/usb/desc.c | 12 | ||||
-rw-r--r-- | hw/usb/desc.h | 11 | ||||
-rw-r--r-- | hw/usb/dev-hid.c | 2 | ||||
-rw-r--r-- | hw/usb/dev-uas.c | 156 | ||||
-rw-r--r-- | hw/usb/hcd-ehci.c | 19 | ||||
-rw-r--r-- | hw/usb/hcd-ehci.h | 1 | ||||
-rw-r--r-- | hw/usb/hcd-xhci.c | 138 | ||||
-rw-r--r-- | hw/xen/xen_pt.c | 3 | ||||
-rw-r--r-- | hw/xen/xen_pvdevice.c | 6 |
25 files changed, 511 insertions, 161 deletions
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c index f8ccbdd13a..f18db53bca 100644 --- a/hw/char/cadence_uart.c +++ b/hw/char/cadence_uart.c @@ -120,8 +120,8 @@ typedef struct { uint64_t char_tx_time; CharDriverState *chr; qemu_irq irq; - struct QEMUTimer *fifo_trigger_handle; - struct QEMUTimer *tx_time_handle; + QEMUTimer *fifo_trigger_handle; + QEMUTimer *tx_time_handle; } UartState; static void uart_update_status(UartState *s) diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c index a6a8cdc2e1..aba292ccde 100644 --- a/hw/display/vmware_vga.c +++ b/hw/display/vmware_vga.c @@ -23,6 +23,7 @@ */ #include "hw/hw.h" #include "hw/loader.h" +#include "trace.h" #include "ui/console.h" #include "hw/pci/pci.h" diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c index 1f22fb60a4..befc39f253 100644 --- a/hw/i386/acpi-build.c +++ b/hw/i386/acpi-build.c @@ -285,7 +285,8 @@ static inline void build_append_array(GArray *array, GArray *val) g_array_append_vals(array, val->data, val->len); } -static void build_append_nameseg(GArray *array, const char *format, ...) +static void GCC_FMT_ATTR(2, 3) +build_append_nameseg(GArray *array, const char *format, ...) { /* It would be nicer to use g_string_vprintf but it's only there in 2.22 */ char s[] = "XXXX"; @@ -630,7 +631,7 @@ build_append_notify(GArray *device, const char *name, GArray *method = build_alloc_array(); uint8_t op = 0x14; /* MethodOp */ - build_append_nameseg(method, name); + build_append_nameseg(method, "%s", name); build_append_byte(method, 0x02); /* MethodFlags: ArgCount */ for (i = skip; i < count; i++) { GArray *target = build_alloc_array(); diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c index 2111f0192c..ab562853b8 100644 --- a/hw/i386/pc_piix.c +++ b/hw/i386/pc_piix.c @@ -339,13 +339,24 @@ static void pc_xen_hvm_init(QEMUMachineInitArgs *args) .desc = "Standard PC (i440FX + PIIX, 1996)", \ .hot_add_cpu = pc_hot_add_cpu +#define PC_I440FX_2_0_MACHINE_OPTIONS \ + PC_I440FX_MACHINE_OPTIONS, \ + .default_machine_opts = "firmware=bios-256k.bin" + +static QEMUMachine pc_i440fx_machine_v2_0 = { + PC_I440FX_2_0_MACHINE_OPTIONS, + .name = "pc-i440fx-2.0", + .alias = "pc", + .init = pc_init_pci, + .is_default = 1, +}; + #define PC_I440FX_1_7_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS + static QEMUMachine pc_i440fx_machine_v1_7 = { PC_I440FX_1_7_MACHINE_OPTIONS, .name = "pc-i440fx-1.7", - .alias = "pc", .init = pc_init_pci, - .is_default = 1, }; #define PC_I440FX_1_6_MACHINE_OPTIONS PC_I440FX_MACHINE_OPTIONS @@ -747,6 +758,7 @@ static QEMUMachine xenfv_machine = { static void pc_machine_init(void) { + qemu_register_machine(&pc_i440fx_machine_v2_0); qemu_register_machine(&pc_i440fx_machine_v1_7); qemu_register_machine(&pc_i440fx_machine_v1_6); qemu_register_machine(&pc_i440fx_machine_v1_5); diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c index 600fc02ebe..97aa84264c 100644 --- a/hw/i386/pc_q35.c +++ b/hw/i386/pc_q35.c @@ -259,12 +259,22 @@ static void pc_q35_init_1_4(QEMUMachineInitArgs *args) .desc = "Standard PC (Q35 + ICH9, 2009)", \ .hot_add_cpu = pc_hot_add_cpu +#define PC_Q35_2_0_MACHINE_OPTIONS \ + PC_Q35_MACHINE_OPTIONS, \ + .default_machine_opts = "firmware=bios-256k.bin" + +static QEMUMachine pc_q35_machine_v2_0 = { + PC_Q35_2_0_MACHINE_OPTIONS, + .name = "pc-q35-2.0", + .alias = "q35", + .init = pc_q35_init, +}; + #define PC_Q35_1_7_MACHINE_OPTIONS PC_Q35_MACHINE_OPTIONS static QEMUMachine pc_q35_machine_v1_7 = { PC_Q35_1_7_MACHINE_OPTIONS, .name = "pc-q35-1.7", - .alias = "q35", .init = pc_q35_init, }; @@ -306,6 +316,7 @@ static QEMUMachine pc_q35_machine_v1_4 = { static void pc_q35_machine_init(void) { + qemu_register_machine(&pc_q35_machine_v2_0); qemu_register_machine(&pc_q35_machine_v1_7); qemu_register_machine(&pc_q35_machine_v1_6); qemu_register_machine(&pc_q35_machine_v1_5); diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index b75c753305..90eca9a87e 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1428,7 +1428,7 @@ static NetClientInfo net_virtio_info = { .size = sizeof(NICState), .can_receive = virtio_net_can_receive, .receive = virtio_net_receive, - .cleanup = virtio_net_cleanup, + .cleanup = virtio_net_cleanup, .link_status_changed = virtio_net_set_link_status, .query_rx_filter = virtio_net_query_rxfilter, }; diff --git a/hw/nvram/eeprom93xx.c b/hw/nvram/eeprom93xx.c index 08f4df586c..a98f924b81 100644 --- a/hw/nvram/eeprom93xx.c +++ b/hw/nvram/eeprom93xx.c @@ -126,7 +126,7 @@ static const VMStateDescription vmstate_eeprom = { .version_id = EEPROM_VERSION, .minimum_version_id = OLD_EEPROM_VERSION, .minimum_version_id_old = OLD_EEPROM_VERSION, - .fields = (VMStateField []) { + .fields = (VMStateField[]) { VMSTATE_UINT8(tick, eeprom_t), VMSTATE_UINT8(address, eeprom_t), VMSTATE_UINT8(command, eeprom_t), @@ -157,13 +157,13 @@ void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi) logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n", eecs, eesk, eedi, eedo, tick); - if (! eeprom->eecs && eecs) { + if (!eeprom->eecs && eecs) { /* Start chip select cycle. */ logout("Cycle start, waiting for 1st start bit (0)\n"); tick = 0; command = 0x0; address = 0x0; - } else if (eeprom->eecs && ! eecs) { + } else if (eeprom->eecs && !eecs) { /* End chip select cycle. This triggers write / erase. */ if (eeprom->writable) { uint8_t subcommand = address >> (eeprom->addrbits - 2); @@ -189,7 +189,7 @@ void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi) } /* Output DO is tristate, read results in 1. */ eedo = 1; - } else if (eecs && ! eeprom->eesk && eesk) { + } else if (eecs && !eeprom->eesk && eesk) { /* Raising edge of clock shifts data in. */ if (tick == 0) { /* Wait for 1st start bit. */ @@ -230,20 +230,20 @@ void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi) if (command == 0) { /* Command code in upper 2 bits of address. */ switch (address >> (eeprom->addrbits - 2)) { - case 0: - logout("write disable command\n"); - eeprom->writable = 0; - break; - case 1: - logout("write all command\n"); - break; - case 2: - logout("erase all command\n"); - break; - case 3: - logout("write enable command\n"); - eeprom->writable = 1; - break; + case 0: + logout("write disable command\n"); + eeprom->writable = 0; + break; + case 1: + logout("write all command\n"); + break; + case 2: + logout("erase all command\n"); + break; + case 3: + logout("write enable command\n"); + eeprom->writable = 1; + break; } } else { /* Read, write or erase word. */ @@ -276,7 +276,7 @@ uint16_t eeprom93xx_read(eeprom_t *eeprom) { /* Return status of pin DO (0 or 1). */ logout("CS=%u DO=%u\n", eeprom->eecs, eeprom->eedo); - return (eeprom->eedo); + return eeprom->eedo; } #if 0 @@ -296,18 +296,18 @@ eeprom_t *eeprom93xx_new(DeviceState *dev, uint16_t nwords) uint8_t addrbits; switch (nwords) { - case 16: - case 64: - addrbits = 6; - break; - case 128: - case 256: - addrbits = 8; - break; - default: - assert(!"Unsupported EEPROM size, fallback to 64 words!"); - nwords = 64; - addrbits = 6; + case 16: + case 64: + addrbits = 6; + break; + case 128: + case 256: + addrbits = 8; + break; + default: + assert(!"Unsupported EEPROM size, fallback to 64 words!"); + nwords = 64; + addrbits = 6; } eeprom = (eeprom_t *)g_malloc0(sizeof(*eeprom) + nwords * 2); diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 1e578dd59d..c1faf9ce27 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -34,7 +34,6 @@ #define MAX_CPUS 1 #define BIOS_SIZE (1024 * 1024) -#define BIOS_FILENAME "ppc_rom.bin" #define NVRAM_SIZE 0x2000 #define PROM_FILENAME "openbios-ppc" #define PROM_ADDR 0xfff00000 diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c index bf2d3d4b35..114be64480 100644 --- a/hw/ppc/ppc.c +++ b/hw/ppc/ppc.c @@ -684,7 +684,7 @@ static inline void cpu_ppc_hdecr_excp(PowerPCCPU *cpu) } static void __cpu_ppc_store_decr(PowerPCCPU *cpu, uint64_t *nextp, - struct QEMUTimer *timer, + QEMUTimer *timer, void (*raise_excp)(PowerPCCPU *), uint32_t decr, uint32_t value, int is_excp) @@ -856,9 +856,9 @@ typedef struct ppc40x_timer_t ppc40x_timer_t; struct ppc40x_timer_t { uint64_t pit_reload; /* PIT auto-reload value */ uint64_t fit_next; /* Tick for next FIT interrupt */ - struct QEMUTimer *fit_timer; + QEMUTimer *fit_timer; uint64_t wdt_next; /* Tick for next WDT interrupt */ - struct QEMUTimer *wdt_timer; + QEMUTimer *wdt_timer; /* 405 have the PIT, 440 have a DECR. */ unsigned int decr_excp; diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index 6d6a7f1203..8109f92200 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -1234,7 +1234,7 @@ struct ppc4xx_gpt_t { MemoryRegion iomem; int64_t tb_offset; uint32_t tb_freq; - struct QEMUTimer *timer; + QEMUTimer *timer; qemu_irq irqs[5]; uint32_t oe; uint32_t ol; diff --git a/hw/ppc/ppc_booke.c b/hw/ppc/ppc_booke.c index b421620708..d8399602d6 100644 --- a/hw/ppc/ppc_booke.c +++ b/hw/ppc/ppc_booke.c @@ -64,10 +64,10 @@ typedef struct booke_timer_t booke_timer_t; struct booke_timer_t { uint64_t fit_next; - struct QEMUTimer *fit_timer; + QEMUTimer *fit_timer; uint64_t wdt_next; - struct QEMUTimer *wdt_timer; + QEMUTimer *wdt_timer; uint32_t flags; }; diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c index ea916d1466..3e5e31da8f 100644 --- a/hw/scsi/scsi-bus.c +++ b/hw/scsi/scsi-bus.c @@ -1293,6 +1293,11 @@ const struct SCSISense sense_code_ILLEGAL_REQ_REMOVAL_PREVENTED = { .key = ILLEGAL_REQUEST, .asc = 0x53, .ascq = 0x02 }; +/* Illegal request, Invalid Transfer Tag */ +const struct SCSISense sense_code_INVALID_TAG = { + .key = ILLEGAL_REQUEST, .asc = 0x4b, .ascq = 0x01 +}; + /* Command aborted, I/O process terminated */ const struct SCSISense sense_code_IO_ERROR = { .key = ABORTED_COMMAND, .asc = 0x00, .ascq = 0x06 @@ -1308,6 +1313,11 @@ const struct SCSISense sense_code_LUN_FAILURE = { .key = ABORTED_COMMAND, .asc = 0x3e, .ascq = 0x01 }; +/* Command aborted, Overlapped Commands Attempted */ +const struct SCSISense sense_code_OVERLAPPED_COMMANDS = { + .key = ABORTED_COMMAND, .asc = 0x4e, .ascq = 0x00 +}; + /* Unit attention, Capacity data has changed */ const struct SCSISense sense_code_CAPACITY_CHANGED = { .key = UNIT_ATTENTION, .asc = 0x2a, .ascq = 0x09 diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 74e6a14c29..efadfc023f 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -41,6 +41,7 @@ do { printf("scsi-disk: " fmt , ## __VA_ARGS__); } while (0) #include <scsi/sg.h> #endif +#define SCSI_WRITE_SAME_MAX 524288 #define SCSI_DMA_BUF_SIZE 131072 #define SCSI_MAX_INQUIRY_LEN 256 #define SCSI_MAX_MODE_LEN 256 @@ -634,6 +635,8 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) buflen = 0x40; memset(outbuf + 4, 0, buflen - 4); + outbuf[4] = 0x1; /* wsnz */ + /* optimal transfer length granularity */ outbuf[6] = (min_io_size >> 8) & 0xff; outbuf[7] = min_io_size & 0xff; @@ -1543,10 +1546,16 @@ done: static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); uint8_t *p = inbuf; int len = r->req.cmd.xfer; UnmapCBData *data; + /* Reject ANCHOR=1. */ + if (r->req.cmd.buf[1] & 0x1) { + goto invalid_field; + } + if (len < 8) { goto invalid_param_len; } @@ -1560,6 +1569,11 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) goto invalid_param_len; } + if (bdrv_is_read_only(s->qdev.conf.bs)) { + scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); + return; + } + data = g_new0(UnmapCBData, 1); data->r = r; data->inbuf = &p[8]; @@ -1572,6 +1586,115 @@ static void scsi_disk_emulate_unmap(SCSIDiskReq *r, uint8_t *inbuf) invalid_param_len: scsi_check_condition(r, SENSE_CODE(INVALID_PARAM_LEN)); + return; + +invalid_field: + scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); +} + +typedef struct WriteSameCBData { + SCSIDiskReq *r; + int64_t sector; + int nb_sectors; + QEMUIOVector qiov; + struct iovec iov; +} WriteSameCBData; + +static void scsi_write_same_complete(void *opaque, int ret) +{ + WriteSameCBData *data = opaque; + SCSIDiskReq *r = data->r; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + + assert(r->req.aiocb != NULL); + r->req.aiocb = NULL; + bdrv_acct_done(s->qdev.conf.bs, &r->acct); + if (r->req.io_canceled) { + goto done; + } + + if (ret < 0) { + if (scsi_handle_rw_error(r, -ret)) { + goto done; + } + } + + data->nb_sectors -= data->iov.iov_len / 512; + data->sector += data->iov.iov_len / 512; + data->iov.iov_len = MIN(data->nb_sectors * 512, data->iov.iov_len); + if (data->iov.iov_len) { + bdrv_acct_start(s->qdev.conf.bs, &r->acct, data->iov.iov_len, BDRV_ACCT_WRITE); + r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, data->sector, + &data->qiov, data->iov.iov_len / 512, + scsi_write_same_complete, r); + return; + } + + scsi_req_complete(&r->req, GOOD); + +done: + if (!r->req.io_canceled) { + scsi_req_unref(&r->req); + } + qemu_vfree(data->iov.iov_base); + g_free(data); +} + +static void scsi_disk_emulate_write_same(SCSIDiskReq *r, uint8_t *inbuf) +{ + SCSIRequest *req = &r->req; + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev); + uint32_t nb_sectors = scsi_data_cdb_length(r->req.cmd.buf); + WriteSameCBData *data; + uint8_t *buf; + int i; + + /* Fail if PBDATA=1 or LBDATA=1 or ANCHOR=1. */ + if (nb_sectors == 0 || (req->cmd.buf[1] & 0x16)) { + scsi_check_condition(r, SENSE_CODE(INVALID_FIELD)); + return; + } + + if (bdrv_is_read_only(s->qdev.conf.bs)) { + scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); + return; + } + if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) { + scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); + return; + } + + if (buffer_is_zero(inbuf, s->qdev.blocksize)) { + int flags = (req->cmd.buf[1] & 0x8) ? BDRV_REQ_MAY_UNMAP : 0; + + /* The request is used as the AIO opaque value, so add a ref. */ + scsi_req_ref(&r->req); + bdrv_acct_start(s->qdev.conf.bs, &r->acct, nb_sectors * s->qdev.blocksize, + BDRV_ACCT_WRITE); + r->req.aiocb = bdrv_aio_write_zeroes(s->qdev.conf.bs, + r->req.cmd.lba * (s->qdev.blocksize / 512), + nb_sectors * (s->qdev.blocksize / 512), + flags, scsi_aio_complete, r); + return; + } + + data = g_new0(WriteSameCBData, 1); + data->r = r; + data->sector = r->req.cmd.lba * (s->qdev.blocksize / 512); + data->nb_sectors = nb_sectors * (s->qdev.blocksize / 512); + data->iov.iov_len = MIN(data->nb_sectors * 512, SCSI_WRITE_SAME_MAX); + data->iov.iov_base = buf = qemu_blockalign(s->qdev.conf.bs, data->iov.iov_len); + qemu_iovec_init_external(&data->qiov, &data->iov, 1); + + for (i = 0; i < data->iov.iov_len; i += s->qdev.blocksize) { + memcpy(&buf[i], inbuf, s->qdev.blocksize); + } + + scsi_req_ref(&r->req); + bdrv_acct_start(s->qdev.conf.bs, &r->acct, data->iov.iov_len, BDRV_ACCT_WRITE); + r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, data->sector, + &data->qiov, data->iov.iov_len / 512, + scsi_write_same_complete, data); } static void scsi_disk_emulate_write_data(SCSIRequest *req) @@ -1597,6 +1720,10 @@ static void scsi_disk_emulate_write_data(SCSIRequest *req) scsi_disk_emulate_unmap(r, r->iov.iov_base); break; + case WRITE_SAME_10: + case WRITE_SAME_16: + scsi_disk_emulate_write_same(r, r->iov.iov_base); + break; default: abort(); } @@ -1839,29 +1966,10 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) break; case WRITE_SAME_10: case WRITE_SAME_16: - nb_sectors = scsi_data_cdb_length(r->req.cmd.buf); - if (bdrv_is_read_only(s->qdev.conf.bs)) { - scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); - return 0; - } - if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) { - goto illegal_lba; - } - - /* - * We only support WRITE SAME with the unmap bit set for now. - */ - if (!(req->cmd.buf[1] & 0x8)) { - goto illegal_request; - } - - /* The request is used as the AIO opaque value, so add a ref. */ - scsi_req_ref(&r->req); - r->req.aiocb = bdrv_aio_discard(s->qdev.conf.bs, - r->req.cmd.lba * (s->qdev.blocksize / 512), - nb_sectors * (s->qdev.blocksize / 512), - scsi_aio_complete, r); - return 0; + DPRINTF("WRITE SAME %d (len %lu)\n", + req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16, + (long)r->req.cmd.xfer); + break; default: DPRINTF("Unknown SCSI command (%2.2x)\n", buf[0]); scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE)); diff --git a/hw/timer/m48t59.c b/hw/timer/m48t59.c index d3d78ec5a8..be0592b53d 100644 --- a/hw/timer/m48t59.c +++ b/hw/timer/m48t59.c @@ -61,8 +61,8 @@ struct M48t59State { time_t stop_time; /* Alarm & watchdog */ struct tm alarm; - struct QEMUTimer *alrm_timer; - struct QEMUTimer *wd_timer; + QEMUTimer *alrm_timer; + QEMUTimer *wd_timer; /* NVRAM storage */ uint8_t *buffer; /* Model parameters */ diff --git a/hw/usb/bus.c b/hw/usb/bus.c index ca329bef29..09848c6320 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -203,6 +203,24 @@ void usb_device_ep_stopped(USBDevice *dev, USBEndpoint *ep) } } +int usb_device_alloc_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps, + int streams) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->alloc_streams) { + return klass->alloc_streams(dev, eps, nr_eps, streams); + } + return 0; +} + +void usb_device_free_streams(USBDevice *dev, USBEndpoint **eps, int nr_eps) +{ + USBDeviceClass *klass = USB_DEVICE_GET_CLASS(dev); + if (klass->free_streams) { + klass->free_streams(dev, eps, nr_eps); + } +} + static int usb_qdev_init(DeviceState *qdev) { USBDevice *dev = USB_DEVICE(qdev); diff --git a/hw/usb/core.c b/hw/usb/core.c index cf59a1abcf..67ba7d6018 100644 --- a/hw/usb/core.c +++ b/hw/usb/core.c @@ -623,6 +623,7 @@ void usb_ep_reset(USBDevice *dev) dev->ep_ctl.type = USB_ENDPOINT_XFER_CONTROL; dev->ep_ctl.ifnum = 0; dev->ep_ctl.max_packet_size = 64; + dev->ep_ctl.max_streams = 0; dev->ep_ctl.dev = dev; dev->ep_ctl.pipeline = false; for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { @@ -636,6 +637,8 @@ void usb_ep_reset(USBDevice *dev) dev->ep_out[ep].ifnum = USB_INTERFACE_INVALID; dev->ep_in[ep].max_packet_size = 0; dev->ep_out[ep].max_packet_size = 0; + dev->ep_in[ep].max_streams = 0; + dev->ep_out[ep].max_streams = 0; dev->ep_in[ep].dev = dev; dev->ep_out[ep].dev = dev; dev->ep_in[ep].pipeline = false; @@ -764,6 +767,25 @@ int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep) return uep->max_packet_size; } +void usb_ep_set_max_streams(USBDevice *dev, int pid, int ep, uint8_t raw) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + int MaxStreams; + + MaxStreams = raw & 0x1f; + if (MaxStreams) { + uep->max_streams = 1 << MaxStreams; + } else { + uep->max_streams = 0; + } +} + +int usb_ep_get_max_streams(USBDevice *dev, int pid, int ep) +{ + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + return uep->max_streams; +} + void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled) { struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); diff --git a/hw/usb/desc.c b/hw/usb/desc.c index bf6c522682..f18a043500 100644 --- a/hw/usb/desc.c +++ b/hw/usb/desc.c @@ -6,16 +6,6 @@ /* ------------------------------------------------------------------ */ -static uint8_t usb_lo(uint16_t val) -{ - return val & 0xff; -} - -static uint8_t usb_hi(uint16_t val) -{ - return (val >> 8) & 0xff; -} - int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, uint8_t *dest, size_t len) { @@ -385,6 +375,8 @@ static void usb_desc_ep_init(USBDevice *dev) usb_ep_set_ifnum(dev, pid, ep, iface->bInterfaceNumber); usb_ep_set_max_packet_size(dev, pid, ep, iface->eps[e].wMaxPacketSize); + usb_ep_set_max_streams(dev, pid, ep, + iface->eps[e].bmAttributes_super); } } } diff --git a/hw/usb/desc.h b/hw/usb/desc.h index ddd3e7485c..81327b0e74 100644 --- a/hw/usb/desc.h +++ b/hw/usb/desc.h @@ -194,6 +194,17 @@ struct USBDesc { #define USB_DESC_FLAG_SUPER (1 << 1) +/* little helpers */ +static inline uint8_t usb_lo(uint16_t val) +{ + return val & 0xff; +} + +static inline uint8_t usb_hi(uint16_t val) +{ + return (val >> 8) & 0xff; +} + /* generate usb packages from structs */ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, uint8_t *dest, size_t len); diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 59567200ae..5e667f0199 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -236,7 +236,7 @@ static const USBDescDevice desc_device_tablet2 = { .bNumInterfaces = 1, .bConfigurationValue = 1, .iConfiguration = STR_CONFIG_TABLET, - .bmAttributes = 0x80, + .bmAttributes = 0xa0, .bMaxPower = 50, .nif = 1, .ifs = &desc_iface_tablet2, diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 70ed2d1dbd..997b715952 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -55,7 +55,7 @@ typedef struct { uint8_t id; uint8_t reserved; uint16_t tag; -} QEMU_PACKED uas_ui_header; +} QEMU_PACKED uas_iu_header; typedef struct { uint8_t prio_taskattr; /* 6:3 priority, 2:0 task attribute */ @@ -65,7 +65,7 @@ typedef struct { uint64_t lun; uint8_t cdb[16]; uint8_t add_cdb[]; -} QEMU_PACKED uas_ui_command; +} QEMU_PACKED uas_iu_command; typedef struct { uint16_t status_qualifier; @@ -73,29 +73,29 @@ typedef struct { uint8_t reserved[7]; uint16_t sense_length; uint8_t sense_data[18]; -} QEMU_PACKED uas_ui_sense; +} QEMU_PACKED uas_iu_sense; typedef struct { - uint16_t add_response_info; + uint8_t add_response_info[3]; uint8_t response_code; -} QEMU_PACKED uas_ui_response; +} QEMU_PACKED uas_iu_response; typedef struct { uint8_t function; uint8_t reserved; uint16_t task_tag; uint64_t lun; -} QEMU_PACKED uas_ui_task_mgmt; +} QEMU_PACKED uas_iu_task_mgmt; typedef struct { - uas_ui_header hdr; + uas_iu_header hdr; union { - uas_ui_command command; - uas_ui_sense sense; - uas_ui_task_mgmt task; - uas_ui_response response; + uas_iu_command command; + uas_iu_sense sense; + uas_iu_task_mgmt task; + uas_iu_response response; }; -} QEMU_PACKED uas_ui; +} QEMU_PACKED uas_iu; /* --------------------------------------------------------------------- */ @@ -122,8 +122,8 @@ struct UASDevice { UASRequest *dataout2; /* usb 3.0 only */ - USBPacket *data3[UAS_MAX_STREAMS]; - USBPacket *status3[UAS_MAX_STREAMS]; + USBPacket *data3[UAS_MAX_STREAMS + 1]; + USBPacket *status3[UAS_MAX_STREAMS + 1]; }; struct UASRequest { @@ -145,7 +145,7 @@ struct UASRequest { struct UASStatus { uint32_t stream; - uas_ui status; + uas_iu status; uint32_t length; QTAILQ_ENTRY(UASStatus) next; }; @@ -338,7 +338,7 @@ static UASStatus *usb_uas_alloc_status(UASDevice *uas, uint8_t id, uint16_t tag) st->status.hdr.id = id; st->status.hdr.tag = cpu_to_be16(tag); - st->length = sizeof(uas_ui_header); + st->length = sizeof(uas_iu_header); if (uas_using_streams(uas)) { st->stream = tag; } @@ -392,15 +392,13 @@ static void usb_uas_queue_status(UASDevice *uas, UASStatus *st, int length) } } -static void usb_uas_queue_response(UASDevice *uas, uint16_t tag, - uint8_t code, uint16_t add_info) +static void usb_uas_queue_response(UASDevice *uas, uint16_t tag, uint8_t code) { UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_RESPONSE, tag); trace_usb_uas_response(uas->dev.addr, tag, code); st->status.response.response_code = code; - st->status.response.add_response_info = cpu_to_be16(add_info); - usb_uas_queue_status(uas, st, sizeof(uas_ui_response)); + usb_uas_queue_status(uas, st, sizeof(uas_iu_response)); } static void usb_uas_queue_sense(UASRequest *req, uint8_t status) @@ -416,10 +414,28 @@ static void usb_uas_queue_sense(UASRequest *req, uint8_t status) sizeof(st->status.sense.sense_data)); st->status.sense.sense_length = cpu_to_be16(slen); } - len = sizeof(uas_ui_sense) - sizeof(st->status.sense.sense_data) + slen; + len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen; usb_uas_queue_status(req->uas, st, len); } +static void usb_uas_queue_fake_sense(UASDevice *uas, uint16_t tag, + struct SCSISense sense) +{ + UASStatus *st = usb_uas_alloc_status(uas, UAS_UI_SENSE, tag); + int len, slen = 0; + + st->status.sense.status = CHECK_CONDITION; + st->status.sense.status_qualifier = cpu_to_be16(0); + st->status.sense.sense_data[0] = 0x70; + st->status.sense.sense_data[2] = sense.key; + st->status.sense.sense_data[7] = 10; + st->status.sense.sense_data[12] = sense.asc; + st->status.sense.sense_data[13] = sense.ascq; + slen = 18; + len = sizeof(uas_iu_sense) - sizeof(st->status.sense.sense_data) + slen; + usb_uas_queue_status(uas, st, len); +} + static void usb_uas_queue_read_ready(UASRequest *req) { UASStatus *st = usb_uas_alloc_status(req->uas, UAS_UI_READ_READY, @@ -518,14 +534,14 @@ static void usb_uas_start_next_transfer(UASDevice *uas) } } -static UASRequest *usb_uas_alloc_request(UASDevice *uas, uas_ui *ui) +static UASRequest *usb_uas_alloc_request(UASDevice *uas, uas_iu *iu) { UASRequest *req; req = g_new0(UASRequest, 1); req->uas = uas; - req->tag = be16_to_cpu(ui->hdr.tag); - req->lun = be64_to_cpu(ui->command.lun); + req->tag = be16_to_cpu(iu->hdr.tag); + req->lun = be64_to_cpu(iu->command.lun); req->dev = usb_uas_get_dev(req->uas, req->lun); return req; } @@ -648,7 +664,7 @@ static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p) return; } if (uas_using_streams(uas)) { - for (i = 0; i < UAS_MAX_STREAMS; i++) { + for (i = 0; i <= UAS_MAX_STREAMS; i++) { if (uas->status3[i] == p) { uas->status3[i] = NULL; return; @@ -668,16 +684,20 @@ static void usb_uas_cancel_io(USBDevice *dev, USBPacket *p) assert(!"canceled usb packet not found"); } -static void usb_uas_command(UASDevice *uas, uas_ui *ui) +static void usb_uas_command(UASDevice *uas, uas_iu *iu) { UASRequest *req; uint32_t len; + uint16_t tag = be16_to_cpu(iu->hdr.tag); - req = usb_uas_find_request(uas, be16_to_cpu(ui->hdr.tag)); + if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) { + goto invalid_tag; + } + req = usb_uas_find_request(uas, tag); if (req) { goto overlapped_tag; } - req = usb_uas_alloc_request(uas, ui); + req = usb_uas_alloc_request(uas, iu); if (req->dev == NULL) { goto bad_target; } @@ -694,7 +714,7 @@ static void usb_uas_command(UASDevice *uas, uas_ui *ui) req->req = scsi_req_new(req->dev, req->tag, usb_uas_get_lun(req->lun), - ui->command.cdb, req); + iu->command.cdb, req); if (uas->requestlog) { scsi_req_print(req->req); } @@ -705,105 +725,97 @@ static void usb_uas_command(UASDevice *uas, uas_ui *ui) } return; +invalid_tag: + usb_uas_queue_fake_sense(uas, tag, sense_code_INVALID_TAG); + return; + overlapped_tag: - usb_uas_queue_response(uas, req->tag, UAS_RC_OVERLAPPED_TAG, 0); + usb_uas_queue_fake_sense(uas, tag, sense_code_OVERLAPPED_COMMANDS); return; bad_target: - /* - * FIXME: Seems to upset linux, is this wrong? - * NOTE: Happens only with no scsi devices at the bus, not sure - * this is a valid UAS setup in the first place. - */ - usb_uas_queue_response(uas, req->tag, UAS_RC_INVALID_INFO_UNIT, 0); + usb_uas_queue_fake_sense(uas, tag, sense_code_LUN_NOT_SUPPORTED); g_free(req); } -static void usb_uas_task(UASDevice *uas, uas_ui *ui) +static void usb_uas_task(UASDevice *uas, uas_iu *iu) { - uint16_t tag = be16_to_cpu(ui->hdr.tag); - uint64_t lun64 = be64_to_cpu(ui->task.lun); + uint16_t tag = be16_to_cpu(iu->hdr.tag); + uint64_t lun64 = be64_to_cpu(iu->task.lun); SCSIDevice *dev = usb_uas_get_dev(uas, lun64); int lun = usb_uas_get_lun(lun64); UASRequest *req; uint16_t task_tag; - req = usb_uas_find_request(uas, be16_to_cpu(ui->hdr.tag)); + if (uas_using_streams(uas) && tag > UAS_MAX_STREAMS) { + goto invalid_tag; + } + req = usb_uas_find_request(uas, be16_to_cpu(iu->hdr.tag)); if (req) { goto overlapped_tag; } + if (dev == NULL) { + goto incorrect_lun; + } - switch (ui->task.function) { + switch (iu->task.function) { case UAS_TMF_ABORT_TASK: - task_tag = be16_to_cpu(ui->task.task_tag); + task_tag = be16_to_cpu(iu->task.task_tag); trace_usb_uas_tmf_abort_task(uas->dev.addr, tag, task_tag); - if (dev == NULL) { - goto bad_target; - } - if (dev->lun != lun) { - goto incorrect_lun; - } req = usb_uas_find_request(uas, task_tag); if (req && req->dev == dev) { scsi_req_cancel(req->req); } - usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE, 0); + usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE); break; case UAS_TMF_LOGICAL_UNIT_RESET: trace_usb_uas_tmf_logical_unit_reset(uas->dev.addr, tag, lun); - if (dev == NULL) { - goto bad_target; - } - if (dev->lun != lun) { - goto incorrect_lun; - } qdev_reset_all(&dev->qdev); - usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE, 0); + usb_uas_queue_response(uas, tag, UAS_RC_TMF_COMPLETE); break; default: - trace_usb_uas_tmf_unsupported(uas->dev.addr, tag, ui->task.function); - usb_uas_queue_response(uas, tag, UAS_RC_TMF_NOT_SUPPORTED, 0); + trace_usb_uas_tmf_unsupported(uas->dev.addr, tag, iu->task.function); + usb_uas_queue_response(uas, tag, UAS_RC_TMF_NOT_SUPPORTED); break; } return; -overlapped_tag: - usb_uas_queue_response(uas, req->tag, UAS_RC_OVERLAPPED_TAG, 0); +invalid_tag: + usb_uas_queue_response(uas, tag, UAS_RC_INVALID_INFO_UNIT); return; -bad_target: - /* FIXME: correct? [see long comment in usb_uas_command()] */ - usb_uas_queue_response(uas, tag, UAS_RC_INVALID_INFO_UNIT, 0); +overlapped_tag: + usb_uas_queue_response(uas, req->tag, UAS_RC_OVERLAPPED_TAG); return; incorrect_lun: - usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN, 0); + usb_uas_queue_response(uas, tag, UAS_RC_INCORRECT_LUN); } static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) { UASDevice *uas = DO_UPCAST(UASDevice, dev, dev); - uas_ui ui; + uas_iu iu; UASStatus *st; UASRequest *req; int length; switch (p->ep->nr) { case UAS_PIPE_ID_COMMAND: - length = MIN(sizeof(ui), p->iov.size); - usb_packet_copy(p, &ui, length); - switch (ui.hdr.id) { + length = MIN(sizeof(iu), p->iov.size); + usb_packet_copy(p, &iu, length); + switch (iu.hdr.id) { case UAS_UI_COMMAND: - usb_uas_command(uas, &ui); + usb_uas_command(uas, &iu); break; case UAS_UI_TASK_MGMT: - usb_uas_task(uas, &ui); + usb_uas_task(uas, &iu); break; default: - fprintf(stderr, "%s: unknown command ui: id 0x%x\n", - __func__, ui.hdr.id); + fprintf(stderr, "%s: unknown command iu: id 0x%x\n", + __func__, iu.hdr.id); p->status = USB_RET_STALL; break; } diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c index 22bdbf4a7d..355bbd6bed 100644 --- a/hw/usb/hcd-ehci.c +++ b/hw/usb/hcd-ehci.c @@ -28,6 +28,7 @@ */ #include "hw/usb/hcd-ehci.h" +#include "trace.h" /* Capability Registers Base Address - section 2.2 */ #define CAPLENGTH 0x0000 /* 1-byte, 0x0001 reserved */ @@ -826,9 +827,9 @@ static void ehci_child_detach(USBPort *port, USBDevice *child) static void ehci_wakeup(USBPort *port) { EHCIState *s = port->opaque; - uint32_t portsc = s->portsc[port->index]; + uint32_t *portsc = &s->portsc[port->index]; - if (portsc & PORTSC_POWNER) { + if (*portsc & PORTSC_POWNER) { USBPort *companion = s->companion_ports[port->index]; if (companion->ops->wakeup) { companion->ops->wakeup(companion); @@ -836,6 +837,12 @@ static void ehci_wakeup(USBPort *port) return; } + if (*portsc & PORTSC_SUSPEND) { + trace_usb_ehci_port_wakeup(port->index); + *portsc |= PORTSC_FPRES; + ehci_raise_irq(s, USBSTS_PCD); + } + qemu_bh_schedule(s->async_bh); } @@ -1067,6 +1074,14 @@ static void ehci_port_write(void *ptr, hwaddr addr, } } + if ((val & PORTSC_SUSPEND) && !(*portsc & PORTSC_SUSPEND)) { + trace_usb_ehci_port_suspend(port); + } + if (!(val & PORTSC_FPRES) && (*portsc & PORTSC_FPRES)) { + trace_usb_ehci_port_resume(port); + val &= ~PORTSC_SUSPEND; + } + *portsc &= ~PORTSC_RO_MASK; *portsc |= val; trace_usb_ehci_portsc_change(addr + s->portscbase, addr >> 2, *portsc, old); diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index 065c9fa741..1ad4b96cce 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -21,7 +21,6 @@ #include "qemu/timer.h" #include "hw/usb.h" #include "monitor/monitor.h" -#include "trace.h" #include "sysemu/dma.h" #include "sysemu/sysemu.h" #include "hw/pci/pci.h" diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 835f65ed81..bafe08590b 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1150,6 +1150,111 @@ static void xhci_free_streams(XHCIEPContext *epctx) epctx->nr_pstreams = 0; } +static int xhci_epmask_to_eps_with_streams(XHCIState *xhci, + unsigned int slotid, + uint32_t epmask, + XHCIEPContext **epctxs, + USBEndpoint **eps) +{ + XHCISlot *slot; + XHCIEPContext *epctx; + USBEndpoint *ep; + int i, j; + + assert(slotid >= 1 && slotid <= xhci->numslots); + + slot = &xhci->slots[slotid - 1]; + + for (i = 2, j = 0; i <= 31; i++) { + if (!(epmask & (1 << i))) { + continue; + } + + epctx = slot->eps[i - 1]; + ep = xhci_epid_to_usbep(xhci, slotid, i); + if (!epctx || !epctx->nr_pstreams || !ep) { + continue; + } + + if (epctxs) { + epctxs[j] = epctx; + } + eps[j++] = ep; + } + return j; +} + +static void xhci_free_device_streams(XHCIState *xhci, unsigned int slotid, + uint32_t epmask) +{ + USBEndpoint *eps[30]; + int nr_eps; + + nr_eps = xhci_epmask_to_eps_with_streams(xhci, slotid, epmask, NULL, eps); + if (nr_eps) { + usb_device_free_streams(eps[0]->dev, eps, nr_eps); + } +} + +static TRBCCode xhci_alloc_device_streams(XHCIState *xhci, unsigned int slotid, + uint32_t epmask) +{ + XHCIEPContext *epctxs[30]; + USBEndpoint *eps[30]; + int i, r, nr_eps, req_nr_streams, dev_max_streams; + + nr_eps = xhci_epmask_to_eps_with_streams(xhci, slotid, epmask, epctxs, + eps); + if (nr_eps == 0) { + return CC_SUCCESS; + } + + req_nr_streams = epctxs[0]->nr_pstreams; + dev_max_streams = eps[0]->max_streams; + + for (i = 1; i < nr_eps; i++) { + /* + * HdG: I don't expect these to ever trigger, but if they do we need + * to come up with another solution, ie group identical endpoints + * together and make an usb_device_alloc_streams call per group. + */ + if (epctxs[i]->nr_pstreams != req_nr_streams) { + FIXME("guest streams config not identical for all eps"); + return CC_RESOURCE_ERROR; + } + if (eps[i]->max_streams != dev_max_streams) { + FIXME("device streams config not identical for all eps"); + return CC_RESOURCE_ERROR; + } + } + + /* + * max-streams in both the device descriptor and in the controller is a + * power of 2. But stream id 0 is reserved, so if a device can do up to 4 + * streams the guest will ask for 5 rounded up to the next power of 2 which + * becomes 8. For emulated devices usb_device_alloc_streams is a nop. + * + * For redirected devices however this is an issue, as there we must ask + * the real xhci controller to alloc streams, and the host driver for the + * real xhci controller will likely disallow allocating more streams then + * the device can handle. + * + * So we limit the requested nr_streams to the maximum number the device + * can handle. + */ + if (req_nr_streams > dev_max_streams) { + req_nr_streams = dev_max_streams; + } + + r = usb_device_alloc_streams(eps[0]->dev, eps, nr_eps, req_nr_streams); + if (r != 0) { + fprintf(stderr, "xhci: alloc streams failed\n"); + return CC_RESOURCE_ERROR; + } + + return CC_SUCCESS; +} + static XHCIStreamContext *xhci_find_stream(XHCIEPContext *epctx, unsigned int streamid, uint32_t *cc_error) @@ -1495,7 +1600,8 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, } if (!xhci->slots[slotid-1].uport || - !xhci->slots[slotid-1].uport->dev) { + !xhci->slots[slotid-1].uport->dev || + !xhci->slots[slotid-1].uport->dev->attached) { return CC_USB_TRANSACTION_ERROR; } @@ -1982,6 +2088,14 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, return; } + /* If the device has been detached, but the guest has not noticed this + yet the 2 above checks will succeed, but we must NOT continue */ + if (!xhci->slots[slotid - 1].uport || + !xhci->slots[slotid - 1].uport->dev || + !xhci->slots[slotid - 1].uport->dev->attached) { + return; + } + if (epctx->retry) { XHCITransfer *xfer = epctx->retry; @@ -2206,7 +2320,7 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, trace_usb_xhci_slot_address(slotid, uport->path); dev = uport->dev; - if (!dev) { + if (!dev || !dev->attached) { fprintf(stderr, "xhci: port %s not connected\n", uport->path); return CC_USB_TRANSACTION_ERROR; } @@ -2313,6 +2427,8 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, return CC_CONTEXT_STATE_ERROR; } + xhci_free_device_streams(xhci, slotid, ictl_ctx[0] | ictl_ctx[1]); + for (i = 2; i <= 31; i++) { if (ictl_ctx[0] & (1<<i)) { xhci_disable_ep(xhci, slotid, i); @@ -2334,6 +2450,16 @@ static TRBCCode xhci_configure_slot(XHCIState *xhci, unsigned int slotid, } } + res = xhci_alloc_device_streams(xhci, slotid, ictl_ctx[1]); + if (res != CC_SUCCESS) { + for (i = 2; i <= 31; i++) { + if (ictl_ctx[1] & (1 << i)) { + xhci_disable_ep(xhci, slotid, i); + } + } + return res; + } + slot_ctx[3] &= ~(SLOT_STATE_MASK << SLOT_STATE_SHIFT); slot_ctx[3] |= SLOT_CONFIGURED << SLOT_STATE_SHIFT; slot_ctx[0] &= ~(SLOT_CONTEXT_ENTRIES_MASK << SLOT_CONTEXT_ENTRIES_SHIFT); @@ -3016,6 +3142,14 @@ static void xhci_oper_write(void *ptr, hwaddr reg, } else if (!(val & USBCMD_RS) && (xhci->usbcmd & USBCMD_RS)) { xhci_stop(xhci); } + if (val & USBCMD_CSS) { + /* save state */ + xhci->usbsts &= ~USBSTS_SRE; + } + if (val & USBCMD_CRS) { + /* restore state */ + xhci->usbsts |= USBSTS_SRE; + } xhci->usbcmd = val & 0xc0f; xhci_mfwrap_update(xhci); if (val & USBCMD_HCRST) { diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index ca2d460785..d58cb616b1 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -570,7 +570,8 @@ static void xen_pt_region_update(XenPCIPassthroughState *s, if (args.rc) { XEN_PT_WARN(d, "Region: %d (addr: %#"FMT_PCIBUS ", len: %#"FMT_PCIBUS") is overlapped.\n", - bar, sec->offset_within_address_space, sec->size); + bar, sec->offset_within_address_space, + int128_get64(sec->size)); } if (d->io_regions[bar].type & PCI_BASE_ADDRESS_SPACE_IO) { diff --git a/hw/xen/xen_pvdevice.c b/hw/xen/xen_pvdevice.c index 1132c8934f..c2189473ba 100644 --- a/hw/xen/xen_pvdevice.c +++ b/hw/xen/xen_pvdevice.c @@ -74,6 +74,10 @@ static int xen_pv_init(PCIDevice *pci_dev) XenPVDevice *d = XEN_PV_DEVICE(pci_dev); uint8_t *pci_conf; + /* device-id property must always be supplied */ + if (d->device_id == 0xffff) + return -1; + pci_conf = pci_dev->config; pci_set_word(pci_conf + PCI_VENDOR_ID, d->vendor_id); @@ -99,7 +103,7 @@ static int xen_pv_init(PCIDevice *pci_dev) static Property xen_pv_props[] = { DEFINE_PROP_UINT16("vendor-id", XenPVDevice, vendor_id, PCI_VENDOR_ID_XEN), - DEFINE_PROP_UINT16("device-id", XenPVDevice, device_id, PCI_DEVICE_ID_XEN_PVDEVICE), + DEFINE_PROP_UINT16("device-id", XenPVDevice, device_id, 0xffff), DEFINE_PROP_UINT8("revision", XenPVDevice, revision, 0x01), DEFINE_PROP_UINT32("size", XenPVDevice, size, 0x400000), DEFINE_PROP_END_OF_LIST() |