diff options
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/bt/sdp.c | 17 | ||||
| -rw-r--r-- | hw/scsi/vmw_pvscsi.c | 12 | ||||
| -rw-r--r-- | hw/timer/mc146818rtc.c | 37 |
3 files changed, 35 insertions, 31 deletions
diff --git a/hw/bt/sdp.c b/hw/bt/sdp.c index f67b3b89c0..3cb60b9495 100644 --- a/hw/bt/sdp.c +++ b/hw/bt/sdp.c @@ -580,7 +580,7 @@ static void bt_l2cap_sdp_close_ch(void *opaque) int i; for (i = 0; i < sdp->services; i ++) { - g_free(sdp->service_list[i].attribute_list->pair); + g_free(sdp->service_list[i].attribute_list[0].pair); g_free(sdp->service_list[i].attribute_list); g_free(sdp->service_list[i].uuid); } @@ -720,6 +720,8 @@ static void sdp_service_record_build(struct sdp_service_record_s *record, len += sdp_attr_max_size(&def->attributes[record->attributes ++].data, &record->uuids); } + + assert(len > 0); record->uuids = pow2ceil(record->uuids); record->attribute_list = g_malloc0(record->attributes * sizeof(*record->attribute_list)); @@ -730,12 +732,14 @@ static void sdp_service_record_build(struct sdp_service_record_s *record, record->attributes = 0; uuid = record->uuid; while (def->attributes[record->attributes].data.type) { + int attribute_id = def->attributes[record->attributes].id; record->attribute_list[record->attributes].pair = data; + record->attribute_list[record->attributes].attribute_id = attribute_id; len = 0; data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2; - data[len ++] = def->attributes[record->attributes].id >> 8; - data[len ++] = def->attributes[record->attributes].id & 0xff; + data[len ++] = attribute_id >> 8; + data[len ++] = attribute_id & 0xff; len += sdp_attr_write(data + len, &def->attributes[record->attributes].data, &uuid); @@ -749,10 +753,15 @@ static void sdp_service_record_build(struct sdp_service_record_s *record, data += len; } - /* Sort the attribute list by the AttributeID */ + /* Sort the attribute list by the AttributeID. The first must be + * SDP_ATTR_RECORD_HANDLE so that bt_l2cap_sdp_close_ch can free + * the buffer. + */ qsort(record->attribute_list, record->attributes, sizeof(*record->attribute_list), (void *) sdp_attributeid_compare); + assert(record->attribute_list[0].pair == data); + /* Sort the searchable UUIDs list for bisection */ qsort(record->uuid, record->uuids, sizeof(*record->uuid), diff --git a/hw/scsi/vmw_pvscsi.c b/hw/scsi/vmw_pvscsi.c index 4a106da856..77d8b6f9e2 100644 --- a/hw/scsi/vmw_pvscsi.c +++ b/hw/scsi/vmw_pvscsi.c @@ -1103,8 +1103,8 @@ static const struct SCSIBusInfo pvscsi_scsi_info = { .cancel = pvscsi_request_cancelled, }; -static int -pvscsi_init(PCIDevice *pci_dev) +static void +pvscsi_realizefn(PCIDevice *pci_dev, Error **errp) { PVSCSIState *s = PVSCSI(pci_dev); @@ -1138,18 +1138,12 @@ pvscsi_init(PCIDevice *pci_dev) } s->completion_worker = qemu_bh_new(pvscsi_process_completion_queue, s); - if (!s->completion_worker) { - pvscsi_cleanup_msi(s); - return -ENOMEM; - } scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(pci_dev), &pvscsi_scsi_info, NULL); /* override default SCSI bus hotplug-handler, with pvscsi's one */ qbus_set_hotplug_handler(BUS(&s->bus), DEVICE(s), &error_abort); pvscsi_reset_state(s); - - return 0; } static void @@ -1282,7 +1276,7 @@ static void pvscsi_class_init(ObjectClass *klass, void *data) PVSCSIClass *pvs_k = PVSCSI_DEVICE_CLASS(klass); HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); - k->init = pvscsi_init; + k->realize = pvscsi_realizefn; k->exit = pvscsi_uninit; k->vendor_id = PCI_VENDOR_ID_VMWARE; k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI; diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 1b8d3d7d4c..82843ed03f 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -291,26 +291,15 @@ static void check_update_timer(RTCState *s) /* From the data sheet: "Holding the dividers in reset prevents * interrupts from operating, while setting the SET bit allows" - * them to occur. However, it will prevent an alarm interrupt - * from occurring, because the time of day is not updated. + * them to occur. */ if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) { - timer_del(s->update_timer); - return; - } - if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && - (s->cmos_data[RTC_REG_B] & REG_B_SET)) { - timer_del(s->update_timer); - return; - } - if ((s->cmos_data[RTC_REG_C] & REG_C_UF) && - (s->cmos_data[RTC_REG_C] & REG_C_AF)) { + assert((s->cmos_data[RTC_REG_A] & REG_A_UIP) == 0); timer_del(s->update_timer); return; } guest_nsec = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND; - /* if UF is clear, reprogram to next second */ next_update_time = qemu_clock_get_ns(rtc_clock) + NANOSECONDS_PER_SECOND - guest_nsec; @@ -321,7 +310,21 @@ static void check_update_timer(RTCState *s) s->next_alarm_time = next_update_time + (next_alarm_sec - 1) * NANOSECONDS_PER_SECOND; - if (s->cmos_data[RTC_REG_C] & REG_C_UF) { + /* If update_in_progress latched the UIP bit, we must keep the timer + * programmed to the next second, so that UIP is cleared. Otherwise, + * if UF is already set, we might be able to optimize. + */ + if (!(s->cmos_data[RTC_REG_A] & REG_A_UIP) && + (s->cmos_data[RTC_REG_C] & REG_C_UF)) { + /* If AF cannot change (i.e. either it is set already, or + * SET=1 and then the time is not updated), nothing to do. + */ + if ((s->cmos_data[RTC_REG_B] & REG_B_SET) || + (s->cmos_data[RTC_REG_C] & REG_C_AF)) { + timer_del(s->update_timer); + return; + } + /* UF is set, but AF is clear. Program the timer to target * the alarm time. */ next_update_time = s->next_alarm_time; @@ -727,12 +730,10 @@ static uint64_t cmos_ioport_read(void *opaque, hwaddr addr, ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_A: + ret = s->cmos_data[s->cmos_index]; if (update_in_progress(s)) { - s->cmos_data[s->cmos_index] |= REG_A_UIP; - } else { - s->cmos_data[s->cmos_index] &= ~REG_A_UIP; + ret |= REG_A_UIP; } - ret = s->cmos_data[s->cmos_index]; break; case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; |