diff options
Diffstat (limited to 'hw')
| -rw-r--r-- | hw/Makefile.objs | 10 | ||||
| -rw-r--r-- | hw/adb.c | 252 | ||||
| -rw-r--r-- | hw/adb.h | 46 | ||||
| -rw-r--r-- | hw/arm_boot.c | 9 | ||||
| -rw-r--r-- | hw/arm_sysctl.c | 2 | ||||
| -rw-r--r-- | hw/cuda.c | 106 | ||||
| -rw-r--r-- | hw/etraxfs_eth.c | 922 | ||||
| -rw-r--r-- | hw/fw_cfg.c | 14 | ||||
| -rw-r--r-- | hw/grackle_pci.c | 2 | ||||
| -rw-r--r-- | hw/heathrow_pic.c | 2 | ||||
| -rw-r--r-- | hw/ide.h | 4 | ||||
| -rw-r--r-- | hw/ide/ahci.c | 98 | ||||
| -rw-r--r-- | hw/ide/ahci.h | 20 | ||||
| -rw-r--r-- | hw/ide/core.c | 33 | ||||
| -rw-r--r-- | hw/ide/ich.c | 14 | ||||
| -rw-r--r-- | hw/ide/macio.c | 84 | ||||
| -rw-r--r-- | hw/lsi53c895a.c | 7 | ||||
| -rw-r--r-- | hw/m25p80.c | 2 | ||||
| -rw-r--r-- | hw/mac_nvram.c | 88 | ||||
| -rw-r--r-- | hw/macio.c | 289 | ||||
| -rw-r--r-- | hw/omap1.c | 3 | ||||
| -rw-r--r-- | hw/omap_dma.c | 12 | ||||
| -rw-r--r-- | hw/omap_spi.c | 24 | ||||
| -rw-r--r-- | hw/openpic.c | 363 | ||||
| -rw-r--r-- | hw/openpic.h | 1 | ||||
| -rw-r--r-- | hw/pc.c | 40 | ||||
| -rw-r--r-- | hw/pc_piix.c | 26 | ||||
| -rw-r--r-- | hw/pci/Makefile.objs | 2 | ||||
| -rw-r--r-- | hw/pflash_cfi02.c | 1 | ||||
| -rw-r--r-- | hw/ppc/Makefile.objs | 9 | ||||
| -rw-r--r-- | hw/ppc/e500.c | 6 | ||||
| -rw-r--r-- | hw/ppc/e500.h | 2 | ||||
| -rw-r--r-- | hw/ppc/e500plat.c | 4 | ||||
| -rw-r--r-- | hw/ppc/mac.h | 181 | ||||
| -rw-r--r-- | hw/ppc/mac_newworld.c (renamed from hw/ppc_newworld.c) | 75 | ||||
| -rw-r--r-- | hw/ppc/mac_oldworld.c (renamed from hw/ppc_oldworld.c) | 66 | ||||
| -rw-r--r-- | hw/ppc/mpc8544ds.c | 2 | ||||
| -rw-r--r-- | hw/ppc_mac.h | 81 | ||||
| -rw-r--r-- | hw/pxa2xx_timer.c | 47 | ||||
| -rw-r--r-- | hw/qxl.c | 24 | ||||
| -rw-r--r-- | hw/scsi-bus.c | 2 | ||||
| -rw-r--r-- | hw/scsi-disk.c | 4 | ||||
| -rw-r--r-- | hw/serial.c | 4 | ||||
| -rw-r--r-- | hw/smc91c111.c | 1 | ||||
| -rw-r--r-- | hw/spapr.c | 13 | ||||
| -rw-r--r-- | hw/spapr_pci.c | 102 | ||||
| -rw-r--r-- | hw/spapr_pci.h | 22 | ||||
| -rw-r--r-- | hw/spapr_vio.c | 2 | ||||
| -rw-r--r-- | hw/sun4m.c | 3 | ||||
| -rw-r--r-- | hw/sun4u.c | 1 | ||||
| -rw-r--r-- | hw/unin_pci.c | 2 | ||||
| -rw-r--r-- | hw/usb/dev-storage.c | 96 | ||||
| -rw-r--r-- | hw/usb/hcd-ohci.c | 1 | ||||
| -rw-r--r-- | hw/virtio-balloon.c | 175 | ||||
| -rw-r--r-- | hw/vmware_vga.c | 18 | ||||
| -rw-r--r-- | hw/xilinx_ethlite.c | 23 |
56 files changed, 2284 insertions, 1158 deletions
diff --git a/hw/Makefile.objs b/hw/Makefile.objs index 23ac24977e..447e32a42e 100644 --- a/hw/Makefile.objs +++ b/hw/Makefile.objs @@ -1,9 +1,10 @@ # core qdev-related obj files, also used by *-user: -universal-obj-y += qdev.o qdev-properties.o +common-obj-y += qdev.o qdev-properties.o # irq.o needed for qdev GPIO handling: -universal-obj-y += irq.o +common-obj-y += irq.o -common-obj-y = usb/ ide/ pci/ +ifeq ($(CONFIG_SOFTMMU),y) +common-obj-y += usb/ ide/ pci/ common-obj-y += loader.o common-obj-$(CONFIG_VIRTIO) += virtio-console.o common-obj-$(CONFIG_VIRTIO) += virtio-rng.o @@ -43,8 +44,6 @@ common-obj-$(CONFIG_I8259) += i8259_common.o i8259.o common-obj-y += fifo.o common-obj-y += pam.o -extra-obj-y += pci/ - # PPC devices common-obj-$(CONFIG_PREP_PCI) += prep_pci.o common-obj-$(CONFIG_I82378) += i82378.o @@ -217,3 +216,4 @@ obj-$(CONFIG_LINUX) += vfio_pci.o endif $(obj)/baum.o: QEMU_CFLAGS += $(SDL_CFLAGS) +endif diff --git a/hw/adb.c b/hw/adb.c index cc8ad8e057..6cf54650c8 100644 --- a/hw/adb.c +++ b/hw/adb.c @@ -48,16 +48,21 @@ do { printf("ADB: " fmt , ## __VA_ARGS__); } while (0) #define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00 /* ADB default device IDs (upper 4 bits of ADB command byte) */ -#define ADB_DONGLE 1 -#define ADB_KEYBOARD 2 -#define ADB_MOUSE 3 -#define ADB_TABLET 4 -#define ADB_MODEM 5 -#define ADB_MISC 7 +#define ADB_DEVID_DONGLE 1 +#define ADB_DEVID_KEYBOARD 2 +#define ADB_DEVID_MOUSE 3 +#define ADB_DEVID_TABLET 4 +#define ADB_DEVID_MODEM 5 +#define ADB_DEVID_MISC 7 /* error codes */ #define ADB_RET_NOTPRESENT (-2) +static void adb_device_reset(ADBDevice *d) +{ + qdev_reset_all(DEVICE(d)); +} + int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) { ADBDevice *d; @@ -66,18 +71,17 @@ int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len) cmd = buf[0] & 0xf; if (cmd == ADB_BUSRESET) { for(i = 0; i < s->nb_devices; i++) { - d = &s->devices[i]; - if (d->devreset) { - d->devreset(d); - } + d = s->devices[i]; + adb_device_reset(d); } return 0; } devaddr = buf[0] >> 4; for(i = 0; i < s->nb_devices; i++) { - d = &s->devices[i]; + d = s->devices[i]; if (d->devaddr == devaddr) { - return d->devreq(d, obuf, buf, len); + ADBDeviceClass *adc = ADB_DEVICE_GET_CLASS(d); + return adc->devreq(d, obuf, buf, len); } } return ADB_RET_NOTPRESENT; @@ -94,7 +98,7 @@ int adb_poll(ADBBusState *s, uint8_t *obuf) for(i = 0; i < s->nb_devices; i++) { if (s->poll_index >= s->nb_devices) s->poll_index = 0; - d = &s->devices[s->poll_index]; + d = s->devices[s->poll_index]; buf[0] = ADB_READREG | (d->devaddr << 4); olen = adb_request(s, obuf + 1, buf, 1); /* if there is data, we poll again the same device */ @@ -108,32 +112,67 @@ int adb_poll(ADBBusState *s, uint8_t *obuf) return olen; } -static ADBDevice *adb_register_device(ADBBusState *s, int devaddr, - ADBDeviceRequest *devreq, - ADBDeviceReset *devreset, - void *opaque) +static const TypeInfo adb_bus_type_info = { + .name = TYPE_ADB_BUS, + .parent = TYPE_BUS, + .instance_size = sizeof(ADBBusState), +}; + +static void adb_device_realizefn(DeviceState *dev, Error **errp) { - ADBDevice *d; - if (s->nb_devices >= MAX_ADB_DEVICES) - return NULL; - d = &s->devices[s->nb_devices++]; - d->bus = s; - d->devaddr = devaddr; - d->devreq = devreq; - d->devreset = devreset; - d->opaque = opaque; - qemu_register_reset((QEMUResetHandler *)devreset, d); - return d; + ADBDevice *d = ADB_DEVICE(dev); + ADBBusState *bus = ADB_BUS(qdev_get_parent_bus(dev)); + + if (bus->nb_devices >= MAX_ADB_DEVICES) { + return; + } + + bus->devices[bus->nb_devices++] = d; } +static void adb_device_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = adb_device_realizefn; + dc->bus_type = TYPE_ADB_BUS; +} + +static const TypeInfo adb_device_type_info = { + .name = TYPE_ADB_DEVICE, + .parent = TYPE_DEVICE, + .instance_size = sizeof(ADBDevice), + .abstract = true, + .class_init = adb_device_class_init, +}; + /***************************************************************/ /* Keyboard ADB device */ +#define ADB_KEYBOARD(obj) OBJECT_CHECK(KBDState, (obj), TYPE_ADB_KEYBOARD) + typedef struct KBDState { + /*< private >*/ + ADBDevice parent_obj; + /*< public >*/ + uint8_t data[128]; int rptr, wptr, count; } KBDState; +#define ADB_KEYBOARD_CLASS(class) \ + OBJECT_CLASS_CHECK(ADBKeyboardClass, (class), TYPE_ADB_KEYBOARD) +#define ADB_KEYBOARD_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ADBKeyboardClass, (obj), TYPE_ADB_KEYBOARD) + +typedef struct ADBKeyboardClass { + /*< private >*/ + ADBDeviceClass parent_class; + /*< public >*/ + + DeviceRealize parent_realize; +} ADBKeyboardClass; + static const uint8_t pc_to_adb_keycode[256] = { 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1, @@ -155,8 +194,7 @@ static const uint8_t pc_to_adb_keycode[256] = { static void adb_kbd_put_keycode(void *opaque, int keycode) { - ADBDevice *d = opaque; - KBDState *s = d->opaque; + KBDState *s = opaque; if (s->count < sizeof(s->data)) { s->data[s->wptr] = keycode; @@ -169,7 +207,7 @@ static void adb_kbd_put_keycode(void *opaque, int keycode) static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) { static int ext_keycode; - KBDState *s = d->opaque; + KBDState *s = ADB_KEYBOARD(d); int adb_keycode, keycode; int olen; @@ -203,7 +241,7 @@ static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf) static int adb_kbd_request(ADBDevice *d, uint8_t *obuf, const uint8_t *buf, int len) { - KBDState *s = d->opaque; + KBDState *s = ADB_KEYBOARD(d); int cmd, reg, olen; if ((buf[0] & 0x0f) == ADB_FLUSH) { @@ -275,41 +313,90 @@ static const VMStateDescription vmstate_adb_kbd = { } }; -static int adb_kbd_reset(ADBDevice *d) +static void adb_kbd_reset(DeviceState *dev) { - KBDState *s = d->opaque; + ADBDevice *d = ADB_DEVICE(dev); + KBDState *s = ADB_KEYBOARD(dev); d->handler = 1; - d->devaddr = ADB_KEYBOARD; - memset(s, 0, sizeof(KBDState)); - - return 0; + d->devaddr = ADB_DEVID_KEYBOARD; + memset(s->data, 0, sizeof(s->data)); + s->rptr = 0; + s->wptr = 0; + s->count = 0; } -void adb_kbd_init(ADBBusState *bus) +static void adb_kbd_realizefn(DeviceState *dev, Error **errp) { - ADBDevice *d; - KBDState *s; - s = g_malloc0(sizeof(KBDState)); - d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request, - adb_kbd_reset, s); + ADBDevice *d = ADB_DEVICE(dev); + ADBKeyboardClass *akc = ADB_KEYBOARD_GET_CLASS(dev); + + akc->parent_realize(dev, errp); + qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); - vmstate_register(NULL, -1, &vmstate_adb_kbd, s); } +static void adb_kbd_initfn(Object *obj) +{ + ADBDevice *d = ADB_DEVICE(obj); + + d->devaddr = ADB_DEVID_KEYBOARD; +} + +static void adb_kbd_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); + ADBKeyboardClass *akc = ADB_KEYBOARD_CLASS(oc); + + akc->parent_realize = dc->realize; + dc->realize = adb_kbd_realizefn; + + adc->devreq = adb_kbd_request; + dc->reset = adb_kbd_reset; + dc->vmsd = &vmstate_adb_kbd; +} + +static const TypeInfo adb_kbd_type_info = { + .name = TYPE_ADB_KEYBOARD, + .parent = TYPE_ADB_DEVICE, + .instance_size = sizeof(KBDState), + .instance_init = adb_kbd_initfn, + .class_init = adb_kbd_class_init, + .class_size = sizeof(ADBKeyboardClass), +}; + /***************************************************************/ /* Mouse ADB device */ +#define ADB_MOUSE(obj) OBJECT_CHECK(MouseState, (obj), TYPE_ADB_MOUSE) + typedef struct MouseState { + /*< public >*/ + ADBDevice parent_obj; + /*< private >*/ + int buttons_state, last_buttons_state; int dx, dy, dz; } MouseState; +#define ADB_MOUSE_CLASS(class) \ + OBJECT_CLASS_CHECK(ADBMouseClass, (class), TYPE_ADB_MOUSE) +#define ADB_MOUSE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ADBMouseClass, (obj), TYPE_ADB_MOUSE) + +typedef struct ADBMouseClass { + /*< public >*/ + ADBDeviceClass parent_class; + /*< private >*/ + + DeviceRealize parent_realize; +} ADBMouseClass; + static void adb_mouse_event(void *opaque, int dx1, int dy1, int dz1, int buttons_state) { - ADBDevice *d = opaque; - MouseState *s = d->opaque; + MouseState *s = opaque; s->dx += dx1; s->dy += dy1; @@ -320,7 +407,7 @@ static void adb_mouse_event(void *opaque, static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) { - MouseState *s = d->opaque; + MouseState *s = ADB_MOUSE(d); int dx, dy; if (s->last_buttons_state == s->buttons_state && @@ -359,7 +446,7 @@ static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf) static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, const uint8_t *buf, int len) { - MouseState *s = d->opaque; + MouseState *s = ADB_MOUSE(d); int cmd, reg, olen; if ((buf[0] & 0x0f) == ADB_FLUSH) { @@ -416,15 +503,15 @@ static int adb_mouse_request(ADBDevice *d, uint8_t *obuf, return olen; } -static int adb_mouse_reset(ADBDevice *d) +static void adb_mouse_reset(DeviceState *dev) { - MouseState *s = d->opaque; + ADBDevice *d = ADB_DEVICE(dev); + MouseState *s = ADB_MOUSE(dev); d->handler = 2; - d->devaddr = ADB_MOUSE; - memset(s, 0, sizeof(MouseState)); - - return 0; + d->devaddr = ADB_DEVID_MOUSE; + s->last_buttons_state = s->buttons_state = 0; + s->dx = s->dy = s->dz = 0; } static const VMStateDescription vmstate_adb_mouse = { @@ -442,14 +529,53 @@ static const VMStateDescription vmstate_adb_mouse = { } }; -void adb_mouse_init(ADBBusState *bus) +static void adb_mouse_realizefn(DeviceState *dev, Error **errp) { - ADBDevice *d; - MouseState *s; + MouseState *s = ADB_MOUSE(dev); + ADBMouseClass *amc = ADB_MOUSE_GET_CLASS(dev); + + amc->parent_realize(dev, errp); + + qemu_add_mouse_event_handler(adb_mouse_event, s, 0, "QEMU ADB Mouse"); +} + +static void adb_mouse_initfn(Object *obj) +{ + ADBDevice *d = ADB_DEVICE(obj); + + d->devaddr = ADB_DEVID_MOUSE; +} + +static void adb_mouse_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + ADBDeviceClass *adc = ADB_DEVICE_CLASS(oc); + ADBMouseClass *amc = ADB_MOUSE_CLASS(oc); + + amc->parent_realize = dc->realize; + dc->realize = adb_mouse_realizefn; - s = g_malloc0(sizeof(MouseState)); - d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request, - adb_mouse_reset, s); - qemu_add_mouse_event_handler(adb_mouse_event, d, 0, "QEMU ADB Mouse"); - vmstate_register(NULL, -1, &vmstate_adb_mouse, s); + adc->devreq = adb_mouse_request; + dc->reset = adb_mouse_reset; + dc->vmsd = &vmstate_adb_mouse; } + +static const TypeInfo adb_mouse_type_info = { + .name = TYPE_ADB_MOUSE, + .parent = TYPE_ADB_DEVICE, + .instance_size = sizeof(MouseState), + .instance_init = adb_mouse_initfn, + .class_init = adb_mouse_class_init, + .class_size = sizeof(ADBMouseClass), +}; + + +static void adb_register_types(void) +{ + type_register_static(&adb_bus_type_info); + type_register_static(&adb_device_type_info); + type_register_static(&adb_kbd_type_info); + type_register_static(&adb_mouse_type_info); +} + +type_init(adb_register_types) diff --git a/hw/adb.h b/hw/adb.h index 5b27da2dd3..721f1ac43e 100644 --- a/hw/adb.h +++ b/hw/adb.h @@ -26,38 +26,62 @@ #if !defined(__ADB_H__) #define __ADB_H__ +#include "qdev.h" + #define MAX_ADB_DEVICES 16 #define ADB_MAX_OUT_LEN 16 +typedef struct ADBBusState ADBBusState; typedef struct ADBDevice ADBDevice; /* buf = NULL means polling */ typedef int ADBDeviceRequest(ADBDevice *d, uint8_t *buf_out, const uint8_t *buf, int len); -typedef int ADBDeviceReset(ADBDevice *d); + +#define TYPE_ADB_DEVICE "adb-device" +#define ADB_DEVICE(obj) OBJECT_CHECK(ADBDevice, (obj), TYPE_ADB_DEVICE) struct ADBDevice { - struct ADBBusState *bus; + /*< private >*/ + DeviceState parent_obj; + /*< public >*/ + int devaddr; int handler; - ADBDeviceRequest *devreq; - ADBDeviceReset *devreset; - void *opaque; }; -typedef struct ADBBusState { - ADBDevice devices[MAX_ADB_DEVICES]; +#define ADB_DEVICE_CLASS(cls) \ + OBJECT_CLASS_CHECK(ADBDeviceClass, (cls), TYPE_ADB_DEVICE) +#define ADB_DEVICE_GET_CLASS(obj) \ + OBJECT_GET_CLASS(ADBDeviceClass, (obj), TYPE_ADB_DEVICE) + +typedef struct ADBDeviceClass { + /*< private >*/ + DeviceClass parent_class; + /*< public >*/ + + ADBDeviceRequest *devreq; +} ADBDeviceClass; + +#define TYPE_ADB_BUS "apple-desktop-bus" +#define ADB_BUS(obj) OBJECT_CHECK(ADBBusState, (obj), TYPE_ADB_BUS) + +struct ADBBusState { + /*< private >*/ + BusState parent_obj; + /*< public >*/ + + ADBDevice *devices[MAX_ADB_DEVICES]; int nb_devices; int poll_index; -} ADBBusState; +}; int adb_request(ADBBusState *s, uint8_t *buf_out, const uint8_t *buf, int len); int adb_poll(ADBBusState *s, uint8_t *buf_out); -void adb_kbd_init(ADBBusState *bus); -void adb_mouse_init(ADBBusState *bus); +#define TYPE_ADB_KEYBOARD "adb-keyboard" +#define TYPE_ADB_MOUSE "adb-mouse" -extern ADBBusState adb_bus; #endif /* !defined(__ADB_H__) */ diff --git a/hw/arm_boot.c b/hw/arm_boot.c index 115f583876..4065424d60 100644 --- a/hw/arm_boot.c +++ b/hw/arm_boot.c @@ -441,9 +441,12 @@ void arm_load_kernel(ARMCPU *cpu, struct arm_boot_info *info) * we point to the kernel args. */ if (info->dtb_filename) { - /* Place the DTB after the initrd in memory */ - hwaddr dtb_start = TARGET_PAGE_ALIGN(info->initrd_start + - initrd_size); + /* Place the DTB after the initrd in memory. Note that some + * kernels will trash anything in the 4K page the initrd + * ends in, so make sure the DTB isn't caught up in that. + */ + hwaddr dtb_start = QEMU_ALIGN_UP(info->initrd_start + initrd_size, + 4096); if (load_dtb(dtb_start, info)) { exit(1); } diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c index 755a5df2c9..da36f8a435 100644 --- a/hw/arm_sysctl.c +++ b/hw/arm_sysctl.c @@ -199,6 +199,7 @@ static void arm_sysctl_write(void *opaque, hwaddr offset, switch (offset) { case 0x08: /* LED */ s->leds = val; + break; case 0x0c: /* OSC0 */ case 0x10: /* OSC1 */ case 0x14: /* OSC2 */ @@ -295,6 +296,7 @@ static void arm_sysctl_write(void *opaque, hwaddr offset, /* On VExpress this register is unimplemented and will RAZ/WI */ break; } + break; case 0x54: /* CLCDSER */ case 0x64: /* DMAPSR0 */ case 0x68: /* DMAPSR1 */ diff --git a/hw/cuda.c b/hw/cuda.c index d59e0aeaa9..b36c53527a 100644 --- a/hw/cuda.c +++ b/hw/cuda.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ #include "hw.h" -#include "ppc_mac.h" +#include "ppc/mac.h" #include "adb.h" #include "qemu/timer.h" #include "sysemu/sysemu.h" @@ -108,50 +108,6 @@ /* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */ #define RTC_OFFSET 2082844800 -typedef struct CUDATimer { - int index; - uint16_t latch; - uint16_t counter_value; /* counter value at load time */ - int64_t load_time; - int64_t next_irq_time; - QEMUTimer *timer; -} CUDATimer; - -typedef struct CUDAState { - MemoryRegion mem; - /* cuda registers */ - uint8_t b; /* B-side data */ - uint8_t a; /* A-side data */ - uint8_t dirb; /* B-side direction (1=output) */ - uint8_t dira; /* A-side direction (1=output) */ - uint8_t sr; /* Shift register */ - uint8_t acr; /* Auxiliary control register */ - uint8_t pcr; /* Peripheral control register */ - uint8_t ifr; /* Interrupt flag register */ - uint8_t ier; /* Interrupt enable register */ - uint8_t anh; /* A-side data, no handshake */ - - CUDATimer timers[2]; - - uint32_t tick_offset; - - uint8_t last_b; /* last value of B register */ - uint8_t last_acr; /* last value of B register */ - - int data_in_size; - int data_in_index; - int data_out_index; - - qemu_irq irq; - uint8_t autopoll; - uint8_t data_in[128]; - uint8_t data_out[16]; - QEMUTimer *adb_poll_timer; -} CUDAState; - -static CUDAState cuda_state; -ADBBusState adb_bus; - static void cuda_update(CUDAState *s); static void cuda_receive_packet_from_host(CUDAState *s, const uint8_t *data, int len); @@ -501,7 +457,7 @@ static void cuda_adb_poll(void *opaque) uint8_t obuf[ADB_MAX_OUT_LEN + 2]; int olen; - olen = adb_poll(&adb_bus, obuf + 2); + olen = adb_poll(&s->adb_bus, obuf + 2); if (olen > 0) { obuf[0] = ADB_PACKET; obuf[1] = 0x40; /* polled data */ @@ -597,7 +553,7 @@ static void cuda_receive_packet_from_host(CUDAState *s, { uint8_t obuf[ADB_MAX_OUT_LEN + 2]; int olen; - olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1); + olen = adb_request(&s->adb_bus, obuf + 2, data + 1, len - 1); if (olen > 0) { obuf[0] = ADB_PACKET; obuf[1] = 0x00; @@ -701,9 +657,9 @@ static const VMStateDescription vmstate_cuda = { } }; -static void cuda_reset(void *opaque) +static void cuda_reset(DeviceState *dev) { - CUDAState *s = opaque; + CUDAState *s = CUDA(dev); s->b = 0; s->a = 0; @@ -728,25 +684,57 @@ static void cuda_reset(void *opaque) set_counter(s, &s->timers[1], 0xffff); } -void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq) +static void cuda_realizefn(DeviceState *dev, Error **errp) { + CUDAState *s = CUDA(dev); struct tm tm; - CUDAState *s = &cuda_state; - - s->irq = irq; - s->timers[0].index = 0; s->timers[0].timer = qemu_new_timer_ns(vm_clock, cuda_timer1, s); - s->timers[1].index = 1; - qemu_get_timedate(&tm, 0); s->tick_offset = (uint32_t)mktimegm(&tm) + RTC_OFFSET; s->adb_poll_timer = qemu_new_timer_ns(vm_clock, cuda_adb_poll, s); +} + +static void cuda_initfn(Object *obj) +{ + SysBusDevice *d = SYS_BUS_DEVICE(obj); + CUDAState *s = CUDA(obj); + int i; + memory_region_init_io(&s->mem, &cuda_ops, s, "cuda", 0x2000); + sysbus_init_mmio(d, &s->mem); + sysbus_init_irq(d, &s->irq); + + for (i = 0; i < ARRAY_SIZE(s->timers); i++) { + s->timers[i].index = i; + } - *cuda_mem = &s->mem; - vmstate_register(NULL, -1, &vmstate_cuda, s); - qemu_register_reset(cuda_reset, s); + qbus_create_inplace((BusState *)&s->adb_bus, TYPE_ADB_BUS, DEVICE(obj), + "adb.0"); } + +static void cuda_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = cuda_realizefn; + dc->reset = cuda_reset; + dc->vmsd = &vmstate_cuda; +} + +static const TypeInfo cuda_type_info = { + .name = TYPE_CUDA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(CUDAState), + .instance_init = cuda_initfn, + .class_init = cuda_class_init, +}; + +static void cuda_register_types(void) +{ + type_register_static(&cuda_type_info); +} + +type_init(cuda_register_types) diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index ec23fa6edf..0b474c0843 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -35,582 +35,592 @@ #define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ #define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ -/* - * The MDIO extensions in the TDK PHY model were reversed engineered from the +/* + * The MDIO extensions in the TDK PHY model were reversed engineered from the * linux driver (PHYID and Diagnostics reg). * TODO: Add friendly names for the register nums. */ struct qemu_phy { - uint32_t regs[32]; + uint32_t regs[32]; - int link; + int link; - unsigned int (*read)(struct qemu_phy *phy, unsigned int req); - void (*write)(struct qemu_phy *phy, unsigned int req, - unsigned int data); + unsigned int (*read)(struct qemu_phy *phy, unsigned int req); + void (*write)(struct qemu_phy *phy, unsigned int req, unsigned int data); }; static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) { - int regnum; - unsigned r = 0; - - regnum = req & 0x1f; - - switch (regnum) { - case 1: - if (!phy->link) - break; - /* MR1. */ - /* Speeds and modes. */ - r |= (1 << 13) | (1 << 14); - r |= (1 << 11) | (1 << 12); - r |= (1 << 5); /* Autoneg complete. */ - r |= (1 << 3); /* Autoneg able. */ - r |= (1 << 2); /* link. */ - break; - case 5: - /* Link partner ability. - We are kind; always agree with whatever best mode - the guest advertises. */ - r = 1 << 14; /* Success. */ - /* Copy advertised modes. */ - r |= phy->regs[4] & (15 << 5); - /* Autoneg support. */ - r |= 1; - break; - case 18: - { - /* Diagnostics reg. */ - int duplex = 0; - int speed_100 = 0; - - if (!phy->link) - break; - - /* Are we advertising 100 half or 100 duplex ? */ - speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); - speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); - - /* Are we advertising 10 duplex or 100 duplex ? */ - duplex = !!(phy->regs[4] & ADVERTISE_100FULL); - duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); - r = (speed_100 << 10) | (duplex << 11); - } - break; - - default: - r = phy->regs[regnum]; - break; - } - D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum)); - return r; + int regnum; + unsigned r = 0; + + regnum = req & 0x1f; + + switch (regnum) { + case 1: + if (!phy->link) { + break; + } + /* MR1. */ + /* Speeds and modes. */ + r |= (1 << 13) | (1 << 14); + r |= (1 << 11) | (1 << 12); + r |= (1 << 5); /* Autoneg complete. */ + r |= (1 << 3); /* Autoneg able. */ + r |= (1 << 2); /* link. */ + break; + case 5: + /* Link partner ability. + We are kind; always agree with whatever best mode + the guest advertises. */ + r = 1 << 14; /* Success. */ + /* Copy advertised modes. */ + r |= phy->regs[4] & (15 << 5); + /* Autoneg support. */ + r |= 1; + break; + case 18: + { + /* Diagnostics reg. */ + int duplex = 0; + int speed_100 = 0; + + if (!phy->link) { + break; + } + + /* Are we advertising 100 half or 100 duplex ? */ + speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); + speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); + + /* Are we advertising 10 duplex or 100 duplex ? */ + duplex = !!(phy->regs[4] & ADVERTISE_100FULL); + duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); + r = (speed_100 << 10) | (duplex << 11); + } + break; + + default: + r = phy->regs[regnum]; + break; + } + D(printf("\n%s %x = reg[%d]\n", __func__, r, regnum)); + return r; } -static void +static void tdk_write(struct qemu_phy *phy, unsigned int req, unsigned int data) { - int regnum; - - regnum = req & 0x1f; - D(printf("%s reg[%d] = %x\n", __func__, regnum, data)); - switch (regnum) { - default: - phy->regs[regnum] = data; - break; - } + int regnum; + + regnum = req & 0x1f; + D(printf("%s reg[%d] = %x\n", __func__, regnum, data)); + switch (regnum) { + default: + phy->regs[regnum] = data; + break; + } } -static void +static void tdk_init(struct qemu_phy *phy) { - phy->regs[0] = 0x3100; - /* PHY Id. */ - phy->regs[2] = 0x0300; - phy->regs[3] = 0xe400; - /* Autonegotiation advertisement reg. */ - phy->regs[4] = 0x01E1; - phy->link = 1; - - phy->read = tdk_read; - phy->write = tdk_write; + phy->regs[0] = 0x3100; + /* PHY Id. */ + phy->regs[2] = 0x0300; + phy->regs[3] = 0xe400; + /* Autonegotiation advertisement reg. */ + phy->regs[4] = 0x01E1; + phy->link = 1; + + phy->read = tdk_read; + phy->write = tdk_write; } struct qemu_mdio { - /* bus. */ - int mdc; - int mdio; - - /* decoder. */ - enum { - PREAMBLE, - SOF, - OPC, - ADDR, - REQ, - TURNAROUND, - DATA - } state; - unsigned int drive; - - unsigned int cnt; - unsigned int addr; - unsigned int opc; - unsigned int req; - unsigned int data; - - struct qemu_phy *devs[32]; + /* bus. */ + int mdc; + int mdio; + + /* decoder. */ + enum { + PREAMBLE, + SOF, + OPC, + ADDR, + REQ, + TURNAROUND, + DATA + } state; + unsigned int drive; + + unsigned int cnt; + unsigned int addr; + unsigned int opc; + unsigned int req; + unsigned int data; + + struct qemu_phy *devs[32]; }; -static void +static void mdio_attach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr) { - bus->devs[addr & 0x1f] = phy; + bus->devs[addr & 0x1f] = phy; } #ifdef USE_THIS_DEAD_CODE -static void +static void mdio_detach(struct qemu_mdio *bus, struct qemu_phy *phy, unsigned int addr) { - bus->devs[addr & 0x1f] = NULL; + bus->devs[addr & 0x1f] = NULL; } #endif static void mdio_read_req(struct qemu_mdio *bus) { - struct qemu_phy *phy; - - phy = bus->devs[bus->addr]; - if (phy && phy->read) - bus->data = phy->read(phy, bus->req); - else - bus->data = 0xffff; + struct qemu_phy *phy; + + phy = bus->devs[bus->addr]; + if (phy && phy->read) { + bus->data = phy->read(phy, bus->req); + } else { + bus->data = 0xffff; + } } static void mdio_write_req(struct qemu_mdio *bus) { - struct qemu_phy *phy; + struct qemu_phy *phy; - phy = bus->devs[bus->addr]; - if (phy && phy->write) - phy->write(phy, bus->req, bus->data); + phy = bus->devs[bus->addr]; + if (phy && phy->write) { + phy->write(phy, bus->req, bus->data); + } } static void mdio_cycle(struct qemu_mdio *bus) { - bus->cnt++; + bus->cnt++; - D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n", - bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive)); + D(printf("mdc=%d mdio=%d state=%d cnt=%d drv=%d\n", + bus->mdc, bus->mdio, bus->state, bus->cnt, bus->drive)); #if 0 - if (bus->mdc) - printf("%d", bus->mdio); + if (bus->mdc) { + printf("%d", bus->mdio); + } #endif - switch (bus->state) - { - case PREAMBLE: - if (bus->mdc) { - if (bus->cnt >= (32 * 2) && !bus->mdio) { - bus->cnt = 0; - bus->state = SOF; - bus->data = 0; - } - } - break; - case SOF: - if (bus->mdc) { - if (bus->mdio != 1) - printf("WARNING: no SOF\n"); - if (bus->cnt == 1*2) { - bus->cnt = 0; - bus->opc = 0; - bus->state = OPC; - } - } - break; - case OPC: - if (bus->mdc) { - bus->opc <<= 1; - bus->opc |= bus->mdio & 1; - if (bus->cnt == 2*2) { - bus->cnt = 0; - bus->addr = 0; - bus->state = ADDR; - } - } - break; - case ADDR: - if (bus->mdc) { - bus->addr <<= 1; - bus->addr |= bus->mdio & 1; - - if (bus->cnt == 5*2) { - bus->cnt = 0; - bus->req = 0; - bus->state = REQ; - } - } - break; - case REQ: - if (bus->mdc) { - bus->req <<= 1; - bus->req |= bus->mdio & 1; - if (bus->cnt == 5*2) { - bus->cnt = 0; - bus->state = TURNAROUND; - } - } - break; - case TURNAROUND: - if (bus->mdc && bus->cnt == 2*2) { - bus->mdio = 0; - bus->cnt = 0; - - if (bus->opc == 2) { - bus->drive = 1; - mdio_read_req(bus); - bus->mdio = bus->data & 1; - } - bus->state = DATA; - } - break; - case DATA: - if (!bus->mdc) { - if (bus->drive) { - bus->mdio = !!(bus->data & (1 << 15)); - bus->data <<= 1; - } - } else { - if (!bus->drive) { - bus->data <<= 1; - bus->data |= bus->mdio; - } - if (bus->cnt == 16 * 2) { - bus->cnt = 0; - bus->state = PREAMBLE; - if (!bus->drive) - mdio_write_req(bus); - bus->drive = 0; - } - } - break; - default: - break; - } + switch (bus->state) { + case PREAMBLE: + if (bus->mdc) { + if (bus->cnt >= (32 * 2) && !bus->mdio) { + bus->cnt = 0; + bus->state = SOF; + bus->data = 0; + } + } + break; + case SOF: + if (bus->mdc) { + if (bus->mdio != 1) { + printf("WARNING: no SOF\n"); + } + if (bus->cnt == 1*2) { + bus->cnt = 0; + bus->opc = 0; + bus->state = OPC; + } + } + break; + case OPC: + if (bus->mdc) { + bus->opc <<= 1; + bus->opc |= bus->mdio & 1; + if (bus->cnt == 2*2) { + bus->cnt = 0; + bus->addr = 0; + bus->state = ADDR; + } + } + break; + case ADDR: + if (bus->mdc) { + bus->addr <<= 1; + bus->addr |= bus->mdio & 1; + + if (bus->cnt == 5*2) { + bus->cnt = 0; + bus->req = 0; + bus->state = REQ; + } + } + break; + case REQ: + if (bus->mdc) { + bus->req <<= 1; + bus->req |= bus->mdio & 1; + if (bus->cnt == 5*2) { + bus->cnt = 0; + bus->state = TURNAROUND; + } + } + break; + case TURNAROUND: + if (bus->mdc && bus->cnt == 2*2) { + bus->mdio = 0; + bus->cnt = 0; + + if (bus->opc == 2) { + bus->drive = 1; + mdio_read_req(bus); + bus->mdio = bus->data & 1; + } + bus->state = DATA; + } + break; + case DATA: + if (!bus->mdc) { + if (bus->drive) { + bus->mdio = !!(bus->data & (1 << 15)); + bus->data <<= 1; + } + } else { + if (!bus->drive) { + bus->data <<= 1; + bus->data |= bus->mdio; + } + if (bus->cnt == 16 * 2) { + bus->cnt = 0; + bus->state = PREAMBLE; + if (!bus->drive) { + mdio_write_req(bus); + } + bus->drive = 0; + } + } + break; + default: + break; + } } /* ETRAX-FS Ethernet MAC block starts here. */ -#define RW_MA0_LO 0x00 -#define RW_MA0_HI 0x01 -#define RW_MA1_LO 0x02 -#define RW_MA1_HI 0x03 -#define RW_GA_LO 0x04 -#define RW_GA_HI 0x05 -#define RW_GEN_CTRL 0x06 -#define RW_REC_CTRL 0x07 -#define RW_TR_CTRL 0x08 -#define RW_CLR_ERR 0x09 -#define RW_MGM_CTRL 0x0a -#define R_STAT 0x0b -#define FS_ETH_MAX_REGS 0x17 +#define RW_MA0_LO 0x00 +#define RW_MA0_HI 0x01 +#define RW_MA1_LO 0x02 +#define RW_MA1_HI 0x03 +#define RW_GA_LO 0x04 +#define RW_GA_HI 0x05 +#define RW_GEN_CTRL 0x06 +#define RW_REC_CTRL 0x07 +#define RW_TR_CTRL 0x08 +#define RW_CLR_ERR 0x09 +#define RW_MGM_CTRL 0x0a +#define R_STAT 0x0b +#define FS_ETH_MAX_REGS 0x17 struct fs_eth { - SysBusDevice busdev; - MemoryRegion mmio; - NICState *nic; - NICConf conf; - - /* Two addrs in the filter. */ - uint8_t macaddr[2][6]; - uint32_t regs[FS_ETH_MAX_REGS]; - - union { - void *vdma_out; - struct etraxfs_dma_client *dma_out; - }; - union { - void *vdma_in; - struct etraxfs_dma_client *dma_in; - }; - - /* MDIO bus. */ - struct qemu_mdio mdio_bus; - unsigned int phyaddr; - int duplex_mismatch; - - /* PHY. */ - struct qemu_phy phy; + SysBusDevice busdev; + MemoryRegion mmio; + NICState *nic; + NICConf conf; + + /* Two addrs in the filter. */ + uint8_t macaddr[2][6]; + uint32_t regs[FS_ETH_MAX_REGS]; + + union { + void *vdma_out; + struct etraxfs_dma_client *dma_out; + }; + union { + void *vdma_in; + struct etraxfs_dma_client *dma_in; + }; + + /* MDIO bus. */ + struct qemu_mdio mdio_bus; + unsigned int phyaddr; + int duplex_mismatch; + + /* PHY. */ + struct qemu_phy phy; }; static void eth_validate_duplex(struct fs_eth *eth) { - struct qemu_phy *phy; - unsigned int phy_duplex; - unsigned int mac_duplex; - int new_mm = 0; - - phy = eth->mdio_bus.devs[eth->phyaddr]; - phy_duplex = !!(phy->read(phy, 18) & (1 << 11)); - mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128); - - if (mac_duplex != phy_duplex) - new_mm = 1; - - if (eth->regs[RW_GEN_CTRL] & 1) { - if (new_mm != eth->duplex_mismatch) { - if (new_mm) - printf("HW: WARNING " - "ETH duplex mismatch MAC=%d PHY=%d\n", - mac_duplex, phy_duplex); - else - printf("HW: ETH duplex ok.\n"); - } - eth->duplex_mismatch = new_mm; - } + struct qemu_phy *phy; + unsigned int phy_duplex; + unsigned int mac_duplex; + int new_mm = 0; + + phy = eth->mdio_bus.devs[eth->phyaddr]; + phy_duplex = !!(phy->read(phy, 18) & (1 << 11)); + mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128); + + if (mac_duplex != phy_duplex) { + new_mm = 1; + } + + if (eth->regs[RW_GEN_CTRL] & 1) { + if (new_mm != eth->duplex_mismatch) { + if (new_mm) { + printf("HW: WARNING ETH duplex mismatch MAC=%d PHY=%d\n", + mac_duplex, phy_duplex); + } else { + printf("HW: ETH duplex ok.\n"); + } + } + eth->duplex_mismatch = new_mm; + } } static uint64_t eth_read(void *opaque, hwaddr addr, unsigned int size) { - struct fs_eth *eth = opaque; - uint32_t r = 0; - - addr >>= 2; - - switch (addr) { - case R_STAT: - r = eth->mdio_bus.mdio & 1; - break; - default: - r = eth->regs[addr]; - D(printf ("%s %x\n", __func__, addr * 4)); - break; - } - return r; + struct fs_eth *eth = opaque; + uint32_t r = 0; + + addr >>= 2; + + switch (addr) { + case R_STAT: + r = eth->mdio_bus.mdio & 1; + break; + default: + r = eth->regs[addr]; + D(printf("%s %x\n", __func__, addr * 4)); + break; + } + return r; } static void eth_update_ma(struct fs_eth *eth, int ma) { - int reg; - int i = 0; - - ma &= 1; - - reg = RW_MA0_LO; - if (ma) - reg = RW_MA1_LO; - - eth->macaddr[ma][i++] = eth->regs[reg]; - eth->macaddr[ma][i++] = eth->regs[reg] >> 8; - eth->macaddr[ma][i++] = eth->regs[reg] >> 16; - eth->macaddr[ma][i++] = eth->regs[reg] >> 24; - eth->macaddr[ma][i++] = eth->regs[reg + 1]; - eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8; - - D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma, - eth->macaddr[ma][0], eth->macaddr[ma][1], - eth->macaddr[ma][2], eth->macaddr[ma][3], - eth->macaddr[ma][4], eth->macaddr[ma][5])); + int reg; + int i = 0; + + ma &= 1; + + reg = RW_MA0_LO; + if (ma) { + reg = RW_MA1_LO; + } + + eth->macaddr[ma][i++] = eth->regs[reg]; + eth->macaddr[ma][i++] = eth->regs[reg] >> 8; + eth->macaddr[ma][i++] = eth->regs[reg] >> 16; + eth->macaddr[ma][i++] = eth->regs[reg] >> 24; + eth->macaddr[ma][i++] = eth->regs[reg + 1]; + eth->macaddr[ma][i] = eth->regs[reg + 1] >> 8; + + D(printf("set mac%d=%x.%x.%x.%x.%x.%x\n", ma, + eth->macaddr[ma][0], eth->macaddr[ma][1], + eth->macaddr[ma][2], eth->macaddr[ma][3], + eth->macaddr[ma][4], eth->macaddr[ma][5])); } static void eth_write(void *opaque, hwaddr addr, uint64_t val64, unsigned int size) { - struct fs_eth *eth = opaque; - uint32_t value = val64; - - addr >>= 2; - switch (addr) - { - case RW_MA0_LO: - case RW_MA0_HI: - eth->regs[addr] = value; - eth_update_ma(eth, 0); - break; - case RW_MA1_LO: - case RW_MA1_HI: - eth->regs[addr] = value; - eth_update_ma(eth, 1); - break; - - case RW_MGM_CTRL: - /* Attach an MDIO/PHY abstraction. */ - if (value & 2) - eth->mdio_bus.mdio = value & 1; - if (eth->mdio_bus.mdc != (value & 4)) { - mdio_cycle(ð->mdio_bus); - eth_validate_duplex(eth); - } - eth->mdio_bus.mdc = !!(value & 4); - eth->regs[addr] = value; - break; - - case RW_REC_CTRL: - eth->regs[addr] = value; - eth_validate_duplex(eth); - break; - - default: - eth->regs[addr] = value; - D(printf ("%s %x %x\n", - __func__, addr, value)); - break; - } + struct fs_eth *eth = opaque; + uint32_t value = val64; + + addr >>= 2; + switch (addr) { + case RW_MA0_LO: + case RW_MA0_HI: + eth->regs[addr] = value; + eth_update_ma(eth, 0); + break; + case RW_MA1_LO: + case RW_MA1_HI: + eth->regs[addr] = value; + eth_update_ma(eth, 1); + break; + + case RW_MGM_CTRL: + /* Attach an MDIO/PHY abstraction. */ + if (value & 2) { + eth->mdio_bus.mdio = value & 1; + } + if (eth->mdio_bus.mdc != (value & 4)) { + mdio_cycle(ð->mdio_bus); + eth_validate_duplex(eth); + } + eth->mdio_bus.mdc = !!(value & 4); + eth->regs[addr] = value; + break; + + case RW_REC_CTRL: + eth->regs[addr] = value; + eth_validate_duplex(eth); + break; + + default: + eth->regs[addr] = value; + D(printf("%s %x %x\n", __func__, addr, value)); + break; + } } /* The ETRAX FS has a groupt address table (GAT) which works like a k=1 bloom - filter dropping group addresses we have not joined. The filter has 64 - bits (m). The has function is a simple nible xor of the group addr. */ + filter dropping group addresses we have not joined. The filter has 64 + bits (m). The has function is a simple nible xor of the group addr. */ static int eth_match_groupaddr(struct fs_eth *eth, const unsigned char *sa) { - unsigned int hsh; - int m_individual = eth->regs[RW_REC_CTRL] & 4; - int match; - - /* First bit on the wire of a MAC address signals multicast or - physical address. */ - if (!m_individual && !(sa[0] & 1)) - return 0; - - /* Calculate the hash index for the GA registers. */ - hsh = 0; - hsh ^= (*sa) & 0x3f; - hsh ^= ((*sa) >> 6) & 0x03; - ++sa; - hsh ^= ((*sa) << 2) & 0x03c; - hsh ^= ((*sa) >> 4) & 0xf; - ++sa; - hsh ^= ((*sa) << 4) & 0x30; - hsh ^= ((*sa) >> 2) & 0x3f; - ++sa; - hsh ^= (*sa) & 0x3f; - hsh ^= ((*sa) >> 6) & 0x03; - ++sa; - hsh ^= ((*sa) << 2) & 0x03c; - hsh ^= ((*sa) >> 4) & 0xf; - ++sa; - hsh ^= ((*sa) << 4) & 0x30; - hsh ^= ((*sa) >> 2) & 0x3f; - - hsh &= 63; - if (hsh > 31) - match = eth->regs[RW_GA_HI] & (1 << (hsh - 32)); - else - match = eth->regs[RW_GA_LO] & (1 << hsh); - D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh, - eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match)); - return match; + unsigned int hsh; + int m_individual = eth->regs[RW_REC_CTRL] & 4; + int match; + + /* First bit on the wire of a MAC address signals multicast or + physical address. */ + if (!m_individual && !(sa[0] & 1)) { + return 0; + } + + /* Calculate the hash index for the GA registers. */ + hsh = 0; + hsh ^= (*sa) & 0x3f; + hsh ^= ((*sa) >> 6) & 0x03; + ++sa; + hsh ^= ((*sa) << 2) & 0x03c; + hsh ^= ((*sa) >> 4) & 0xf; + ++sa; + hsh ^= ((*sa) << 4) & 0x30; + hsh ^= ((*sa) >> 2) & 0x3f; + ++sa; + hsh ^= (*sa) & 0x3f; + hsh ^= ((*sa) >> 6) & 0x03; + ++sa; + hsh ^= ((*sa) << 2) & 0x03c; + hsh ^= ((*sa) >> 4) & 0xf; + ++sa; + hsh ^= ((*sa) << 4) & 0x30; + hsh ^= ((*sa) >> 2) & 0x3f; + + hsh &= 63; + if (hsh > 31) { + match = eth->regs[RW_GA_HI] & (1 << (hsh - 32)); + } else { + match = eth->regs[RW_GA_LO] & (1 << hsh); + } + D(printf("hsh=%x ga=%x.%x mtch=%d\n", hsh, + eth->regs[RW_GA_HI], eth->regs[RW_GA_LO], match)); + return match; } static int eth_can_receive(NetClientState *nc) { - return 1; + return 1; } static ssize_t eth_receive(NetClientState *nc, const uint8_t *buf, size_t size) { - unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; - int use_ma0 = eth->regs[RW_REC_CTRL] & 1; - int use_ma1 = eth->regs[RW_REC_CTRL] & 2; - int r_bcast = eth->regs[RW_REC_CTRL] & 8; - - if (size < 12) - return -1; - - D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], - use_ma0, use_ma1, r_bcast)); - - /* Does the frame get through the address filters? */ - if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6)) - && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) - && (!r_bcast || memcmp(buf, sa_bcast, 6)) - && !eth_match_groupaddr(eth, buf)) - return size; - - /* FIXME: Find another way to pass on the fake csum. */ - etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1); + unsigned char sa_bcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + int use_ma0 = eth->regs[RW_REC_CTRL] & 1; + int use_ma1 = eth->regs[RW_REC_CTRL] & 2; + int r_bcast = eth->regs[RW_REC_CTRL] & 8; + + if (size < 12) { + return -1; + } + + D(printf("%x.%x.%x.%x.%x.%x ma=%d %d bc=%d\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + use_ma0, use_ma1, r_bcast)); + + /* Does the frame get through the address filters? */ + if ((!use_ma0 || memcmp(buf, eth->macaddr[0], 6)) + && (!use_ma1 || memcmp(buf, eth->macaddr[1], 6)) + && (!r_bcast || memcmp(buf, sa_bcast, 6)) + && !eth_match_groupaddr(eth, buf)) { + return size; + } + + /* FIXME: Find another way to pass on the fake csum. */ + etraxfs_dmac_input(eth->dma_in, (void *)buf, size + 4, 1); return size; } static int eth_tx_push(void *opaque, unsigned char *buf, int len, bool eop) { - struct fs_eth *eth = opaque; + struct fs_eth *eth = opaque; - D(printf("%s buf=%p len=%d\n", __func__, buf, len)); - qemu_send_packet(ð->nic->nc, buf, len); - return len; + D(printf("%s buf=%p len=%d\n", __func__, buf, len)); + qemu_send_packet(ð->nic->nc, buf, len); + return len; } static void eth_set_link(NetClientState *nc) { - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; - D(printf("%s %d\n", __func__, nc->link_down)); - eth->phy.link = !nc->link_down; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + D(printf("%s %d\n", __func__, nc->link_down)); + eth->phy.link = !nc->link_down; } static const MemoryRegionOps eth_ops = { - .read = eth_read, - .write = eth_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } + .read = eth_read, + .write = eth_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } }; static void eth_cleanup(NetClientState *nc) { - struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; + struct fs_eth *eth = DO_UPCAST(NICState, nc, nc)->opaque; - /* Disconnect the client. */ - eth->dma_out->client.push = NULL; - eth->dma_out->client.opaque = NULL; - eth->dma_in->client.opaque = NULL; - eth->dma_in->client.pull = NULL; + /* Disconnect the client. */ + eth->dma_out->client.push = NULL; + eth->dma_out->client.opaque = NULL; + eth->dma_in->client.opaque = NULL; + eth->dma_in->client.pull = NULL; g_free(eth); } static NetClientInfo net_etraxfs_info = { - .type = NET_CLIENT_OPTIONS_KIND_NIC, - .size = sizeof(NICState), - .can_receive = eth_can_receive, - .receive = eth_receive, - .cleanup = eth_cleanup, - .link_status_changed = eth_set_link, + .type = NET_CLIENT_OPTIONS_KIND_NIC, + .size = sizeof(NICState), + .can_receive = eth_can_receive, + .receive = eth_receive, + .cleanup = eth_cleanup, + .link_status_changed = eth_set_link, }; static int fs_eth_init(SysBusDevice *dev) { - struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev); + struct fs_eth *s = FROM_SYSBUS(typeof(*s), dev); - if (!s->dma_out || !s->dma_in) { - hw_error("Unconnected ETRAX-FS Ethernet MAC.\n"); - } + if (!s->dma_out || !s->dma_in) { + hw_error("Unconnected ETRAX-FS Ethernet MAC.\n"); + } - s->dma_out->client.push = eth_tx_push; - s->dma_out->client.opaque = s; - s->dma_in->client.opaque = s; - s->dma_in->client.pull = NULL; + s->dma_out->client.push = eth_tx_push; + s->dma_out->client.opaque = s; + s->dma_in->client.opaque = s; + s->dma_in->client.pull = NULL; - memory_region_init_io(&s->mmio, ð_ops, s, "etraxfs-eth", 0x5c); - sysbus_init_mmio(dev, &s->mmio); + memory_region_init_io(&s->mmio, ð_ops, s, "etraxfs-eth", 0x5c); + sysbus_init_mmio(dev, &s->mmio); - qemu_macaddr_default_if_unset(&s->conf.macaddr); - s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf, - object_get_typename(OBJECT(s)), dev->qdev.id, s); - qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); + qemu_macaddr_default_if_unset(&s->conf.macaddr); + s->nic = qemu_new_nic(&net_etraxfs_info, &s->conf, + object_get_typename(OBJECT(s)), dev->qdev.id, s); + qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); - tdk_init(&s->phy); - mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr); - return 0; + tdk_init(&s->phy); + mdio_attach(&s->mdio_bus, &s->phy, s->phyaddr); + return 0; } static Property etraxfs_eth_properties[] = { diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index e4dc7c3c31..02618f2480 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -54,16 +54,17 @@ struct FWCfgState { #define JPG_FILE 0 #define BMP_FILE 1 -static char *read_splashfile(char *filename, int *file_sizep, int *file_typep) +static char *read_splashfile(char *filename, size_t *file_sizep, + int *file_typep) { GError *err = NULL; gboolean res; gchar *content; - int file_type = -1; - unsigned int filehead = 0; + int file_type; + unsigned int filehead; int bmp_bpp; - res = g_file_get_contents(filename, &content, (gsize *)file_sizep, &err); + res = g_file_get_contents(filename, &content, file_sizep, &err); if (res == FALSE) { error_report("failed to read splash file '%s'", filename); g_error_free(err); @@ -111,8 +112,8 @@ static void fw_cfg_bootsplash(FWCfgState *s) const char *boot_splash_filename = NULL; char *p; char *filename, *file_data; - int file_size; - int file_type = -1; + size_t file_size; + int file_type; const char *temp; /* get user configuration */ @@ -503,7 +504,6 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port, fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16); fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC)); fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus); - fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu); fw_cfg_bootsplash(s); fw_cfg_reboot(s); diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c index 948416632a..95639d5735 100644 --- a/hw/grackle_pci.c +++ b/hw/grackle_pci.c @@ -24,7 +24,7 @@ */ #include "pci/pci_host.h" -#include "ppc_mac.h" +#include "ppc/mac.h" #include "pci/pci.h" /* debug Grackle */ diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c index b9ec8e7b4d..c0a71c3d5f 100644 --- a/hw/heathrow_pic.c +++ b/hw/heathrow_pic.c @@ -23,7 +23,7 @@ * THE SOFTWARE. */ #include "hw.h" -#include "ppc_mac.h" +#include "ppc/mac.h" /* debug PIC */ //#define DEBUG_PIC diff --git a/hw/ide.h b/hw/ide.h index 7e23cda8e0..9b357c05a5 100644 --- a/hw/ide.h +++ b/hw/ide.h @@ -19,10 +19,6 @@ PCIDevice *pci_piix3_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn); PCIDevice *pci_piix4_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn); void vt82c686b_ide_init(PCIBus *bus, DriveInfo **hd_table, int devfn); -/* ide-macio.c */ -MemoryRegion *pmac_ide_init (DriveInfo **hd_table, qemu_irq irq, - void *dbdma, int channel, qemu_irq dma_irq); - /* ide-mmio.c */ void mmio_ide_init (hwaddr membase, hwaddr membase2, MemoryRegion *address_space, diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c index 21f50ea5be..ad0094f532 100644 --- a/hw/ide/ahci.c +++ b/hw/ide/ahci.c @@ -241,7 +241,7 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val) if ((pr->cmd & PORT_CMD_FIS_ON) && !s->dev[port].init_d2h_sent) { ahci_init_d2h(&s->dev[port]); - s->dev[port].init_d2h_sent = 1; + s->dev[port].init_d2h_sent = true; } check_cmd(s, port); @@ -494,7 +494,7 @@ static void ahci_reset_port(AHCIState *s, int port) pr->scr_err = 0; pr->scr_act = 0; d->busy_slot = -1; - d->init_d2h_sent = 0; + d->init_d2h_sent = false; ide_state = &s->dev[port].port.ifs[0]; if (!ide_state->bs) { @@ -946,7 +946,7 @@ static int handle_cmd(AHCIState *s, int port, int slot) ide_state->hcyl = 0xeb; debug_print_fis(ide_state->io_buffer, 0x10); ide_state->feature = IDE_FEATURE_DMA; - s->dev[port].done_atapi_packet = 0; + s->dev[port].done_atapi_packet = false; /* XXX send PIO setup FIS */ } @@ -991,7 +991,7 @@ static int ahci_start_transfer(IDEDMA *dma) if (is_atapi && !ad->done_atapi_packet) { /* already prepopulated iobuffer */ - ad->done_atapi_packet = 1; + ad->done_atapi_packet = true; goto out; } @@ -1035,11 +1035,10 @@ out: static void ahci_start_dma(IDEDMA *dma, IDEState *s, BlockDriverCompletionFunc *dma_cb) { +#ifdef DEBUG_AHCI AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); - +#endif DPRINTF(ad->port_no, "\n"); - ad->dma_cb = dma_cb; - ad->dma_status |= BM_STATUS_DMAING; s->io_buffer_offset = 0; dma_cb(s, 0); } @@ -1095,7 +1094,6 @@ static int ahci_dma_set_unit(IDEDMA *dma, int unit) static int ahci_dma_add_status(IDEDMA *dma, int status) { AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); - ad->dma_status |= status; DPRINTF(ad->port_no, "set status: %x\n", status); if (status & BM_STATUS_INT) { @@ -1114,8 +1112,6 @@ static int ahci_dma_set_inactive(IDEDMA *dma) /* update d2h status */ ahci_write_fis_d2h(ad, NULL); - ad->dma_cb = NULL; - if (!ad->check_bh) { /* maybe we still have something to process, check later */ ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad); @@ -1203,6 +1199,82 @@ void ahci_reset(AHCIState *s) } } +static const VMStateDescription vmstate_ahci_device = { + .name = "ahci port", + .version_id = 1, + .fields = (VMStateField []) { + VMSTATE_IDE_BUS(port, AHCIDevice), + VMSTATE_UINT32(port_state, AHCIDevice), + VMSTATE_UINT32(finished, AHCIDevice), + VMSTATE_UINT32(port_regs.lst_addr, AHCIDevice), + VMSTATE_UINT32(port_regs.lst_addr_hi, AHCIDevice), + VMSTATE_UINT32(port_regs.fis_addr, AHCIDevice), + VMSTATE_UINT32(port_regs.fis_addr_hi, AHCIDevice), + VMSTATE_UINT32(port_regs.irq_stat, AHCIDevice), + VMSTATE_UINT32(port_regs.irq_mask, AHCIDevice), + VMSTATE_UINT32(port_regs.cmd, AHCIDevice), + VMSTATE_UINT32(port_regs.tfdata, AHCIDevice), + VMSTATE_UINT32(port_regs.sig, AHCIDevice), + VMSTATE_UINT32(port_regs.scr_stat, AHCIDevice), + VMSTATE_UINT32(port_regs.scr_ctl, AHCIDevice), + VMSTATE_UINT32(port_regs.scr_err, AHCIDevice), + VMSTATE_UINT32(port_regs.scr_act, AHCIDevice), + VMSTATE_UINT32(port_regs.cmd_issue, AHCIDevice), + VMSTATE_BOOL(done_atapi_packet, AHCIDevice), + VMSTATE_INT32(busy_slot, AHCIDevice), + VMSTATE_BOOL(init_d2h_sent, AHCIDevice), + VMSTATE_END_OF_LIST() + }, +}; + +static int ahci_state_post_load(void *opaque, int version_id) +{ + int i; + struct AHCIDevice *ad; + AHCIState *s = opaque; + + for (i = 0; i < s->ports; i++) { + ad = &s->dev[i]; + AHCIPortRegs *pr = &ad->port_regs; + + map_page(&ad->lst, + ((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024); + map_page(&ad->res_fis, + ((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256); + /* + * All pending i/o should be flushed out on a migrate. However, + * we might not have cleared the busy_slot since this is done + * in a bh. Also, issue i/o against any slots that are pending. + */ + if ((ad->busy_slot != -1) && + !(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) { + pr->cmd_issue &= ~(1 << ad->busy_slot); + ad->busy_slot = -1; + } + check_cmd(s, i); + } + + return 0; +} + +const VMStateDescription vmstate_ahci = { + .name = "ahci", + .version_id = 1, + .post_load = ahci_state_post_load, + .fields = (VMStateField []) { + VMSTATE_STRUCT_VARRAY_POINTER_INT32(dev, AHCIState, ports, + vmstate_ahci_device, AHCIDevice), + VMSTATE_UINT32(control_regs.cap, AHCIState), + VMSTATE_UINT32(control_regs.ghc, AHCIState), + VMSTATE_UINT32(control_regs.irqstatus, AHCIState), + VMSTATE_UINT32(control_regs.impl, AHCIState), + VMSTATE_UINT32(control_regs.version, AHCIState), + VMSTATE_UINT32(idp_index, AHCIState), + VMSTATE_INT32(ports, AHCIState), + VMSTATE_END_OF_LIST() + }, +}; + typedef struct SysbusAHCIState { SysBusDevice busdev; AHCIState ahci; @@ -1211,7 +1283,11 @@ typedef struct SysbusAHCIState { static const VMStateDescription vmstate_sysbus_ahci = { .name = "sysbus-ahci", - .unmigratable = 1, + .unmigratable = 1, /* Still buggy under I/O load */ + .fields = (VMStateField []) { + VMSTATE_AHCI(ahci, AHCIPCIState), + VMSTATE_END_OF_LIST() + }, }; static void sysbus_ahci_reset(DeviceState *dev) diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h index 1200a56ada..85f37fe99d 100644 --- a/hw/ide/ahci.h +++ b/hw/ide/ahci.h @@ -281,11 +281,9 @@ struct AHCIDevice { QEMUBH *check_bh; uint8_t *lst; uint8_t *res_fis; - int dma_status; - int done_atapi_packet; - int busy_slot; - int init_d2h_sent; - BlockDriverCompletionFunc *dma_cb; + bool done_atapi_packet; + int32_t busy_slot; + bool init_d2h_sent; AHCICmdHdr *cur_cmd; NCQTransferState ncq_tfs[AHCI_MAX_CMDS]; }; @@ -297,7 +295,7 @@ typedef struct AHCIState { MemoryRegion idp; /* Index-Data Pair I/O port space */ unsigned idp_offset; /* Offset of index in I/O port space */ uint32_t idp_index; /* Current IDP index */ - int ports; + int32_t ports; qemu_irq irq; DMAContext *dma; } AHCIState; @@ -307,6 +305,16 @@ typedef struct AHCIPCIState { AHCIState ahci; } AHCIPCIState; +extern const VMStateDescription vmstate_ahci; + +#define VMSTATE_AHCI(_field, _state) { \ + .name = (stringify(_field)), \ + .size = sizeof(AHCIState), \ + .vmsd = &vmstate_ahci, \ + .flags = VMS_STRUCT, \ + .offset = vmstate_offset_value(_state, _field, AHCIState), \ +} + typedef struct NCQFrame { uint8_t fis_type; uint8_t c; diff --git a/hw/ide/core.c b/hw/ide/core.c index 14ad0799c3..3743dc3b55 100644 --- a/hw/ide/core.c +++ b/hw/ide/core.c @@ -1149,8 +1149,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) } ide_set_irq(s->bus); break; + case WIN_VERIFY_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_VERIFY: case WIN_VERIFY_ONCE: /* do sector number check ? */ @@ -1158,8 +1160,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); break; + case WIN_READ_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_READ: case WIN_READ_ONCE: if (s->drive_kind == IDE_CD) { @@ -1173,8 +1177,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) s->req_nb_sectors = 1; ide_sector_read(s); break; + case WIN_WRITE_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_WRITE: case WIN_WRITE_ONCE: case CFA_WRITE_SECT_WO_ERASE: @@ -1189,8 +1195,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_transfer_start(s, s->io_buffer, 512, ide_sector_write); s->media_changed = 1; break; + case WIN_MULTREAD_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_MULTREAD: if (!s->bs) { goto abort_cmd; @@ -1202,8 +1210,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) s->req_nb_sectors = s->mult_sectors; ide_sector_read(s); break; + case WIN_MULTWRITE_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_MULTWRITE: case CFA_WRITE_MULTI_WO_ERASE: if (!s->bs) { @@ -1222,8 +1232,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write); s->media_changed = 1; break; + case WIN_READDMA_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_READDMA: case WIN_READDMA_ONCE: if (!s->bs) { @@ -1232,8 +1244,10 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_cmd_lba48_transform(s, lba48); ide_sector_start_dma(s, IDE_DMA_READ); break; + case WIN_WRITEDMA_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_WRITEDMA: case WIN_WRITEDMA_ONCE: if (!s->bs) { @@ -1243,14 +1257,17 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) ide_sector_start_dma(s, IDE_DMA_WRITE); s->media_changed = 1; break; + case WIN_READ_NATIVE_MAX_EXT: - lba48 = 1; + lba48 = 1; + /* fall through */ case WIN_READ_NATIVE_MAX: ide_cmd_lba48_transform(s, lba48); ide_set_sector(s, s->nb_sectors - 1); s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); break; + case WIN_CHECKPOWERMODE1: case WIN_CHECKPOWERMODE2: s->error = 0; diff --git a/hw/ide/ich.c b/hw/ide/ich.c index 1fb803d340..cc30adc701 100644 --- a/hw/ide/ich.c +++ b/hw/ide/ich.c @@ -79,9 +79,15 @@ #define ICH9_IDP_INDEX 0x10 #define ICH9_IDP_INDEX_LOG2 0x04 -static const VMStateDescription vmstate_ahci = { - .name = "ahci", - .unmigratable = 1, +static const VMStateDescription vmstate_ich9_ahci = { + .name = "ich9_ahci", + .unmigratable = 1, /* Still buggy under I/O load */ + .version_id = 1, + .fields = (VMStateField []) { + VMSTATE_PCI_DEVICE(card, AHCIPCIState), + VMSTATE_AHCI(ahci, AHCIPCIState), + VMSTATE_END_OF_LIST() + }, }; static void pci_ich9_reset(DeviceState *dev) @@ -152,7 +158,7 @@ static void ich_ahci_class_init(ObjectClass *klass, void *data) k->device_id = PCI_DEVICE_ID_INTEL_82801IR; k->revision = 0x02; k->class_id = PCI_CLASS_STORAGE_SATA; - dc->vmsd = &vmstate_ahci; + dc->vmsd = &vmstate_ich9_ahci; dc->reset = pci_ich9_reset; } diff --git a/hw/ide/macio.c b/hw/ide/macio.c index d8f9b4bce1..375c46f9da 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -22,9 +22,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include <hw/hw.h> -#include <hw/ppc_mac.h> -#include <hw/mac_dbdma.h> +#include "hw/hw.h" +#include "hw/ppc/mac.h" +#include "hw/mac_dbdma.h" #include "block/block.h" #include "sysemu/dma.h" @@ -33,12 +33,6 @@ /***********************************************************/ /* MacIO based PowerPC IDE */ -typedef struct MACIOIDEState { - MemoryRegion mem; - IDEBus bus; - BlockDriverAIOCB *aiocb; -} MACIOIDEState; - #define MACIO_PAGE_SIZE 4096 static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) @@ -321,30 +315,70 @@ static const VMStateDescription vmstate_pmac = { } }; -static void pmac_ide_reset(void *opaque) +static void macio_ide_reset(DeviceState *dev) { - MACIOIDEState *d = opaque; + MACIOIDEState *d = MACIO_IDE(dev); ide_bus_reset(&d->bus); } -/* hd_table must contain 4 block drivers */ -/* PowerMac uses memory mapped registers, not I/O. Return the memory - I/O index to access the ide. */ -MemoryRegion *pmac_ide_init (DriveInfo **hd_table, qemu_irq irq, - void *dbdma, int channel, qemu_irq dma_irq) +static void macio_ide_realizefn(DeviceState *dev, Error **errp) { - MACIOIDEState *d; + MACIOIDEState *s = MACIO_IDE(dev); + + ide_init2(&s->bus, s->irq); +} + +static void macio_ide_initfn(Object *obj) +{ + SysBusDevice *d = SYS_BUS_DEVICE(obj); + MACIOIDEState *s = MACIO_IDE(obj); + + ide_bus_new(&s->bus, DEVICE(obj), 0); + memory_region_init_io(&s->mem, &pmac_ide_ops, s, "pmac-ide", 0x1000); + sysbus_init_mmio(d, &s->mem); + sysbus_init_irq(d, &s->irq); + sysbus_init_irq(d, &s->dma_irq); +} + +static void macio_ide_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = macio_ide_realizefn; + dc->reset = macio_ide_reset; + dc->vmsd = &vmstate_pmac; +} - d = g_malloc0(sizeof(MACIOIDEState)); - ide_init2_with_non_qdev_drives(&d->bus, hd_table[0], hd_table[1], irq); +static const TypeInfo macio_ide_type_info = { + .name = TYPE_MACIO_IDE, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MACIOIDEState), + .instance_init = macio_ide_initfn, + .class_init = macio_ide_class_init, +}; - if (dbdma) - DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d); +static void macio_ide_register_types(void) +{ + type_register_static(&macio_ide_type_info); +} - memory_region_init_io(&d->mem, &pmac_ide_ops, d, "pmac-ide", 0x1000); - vmstate_register(NULL, 0, &vmstate_pmac, d); - qemu_register_reset(pmac_ide_reset, d); +/* hd_table must contain 4 block drivers */ +void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table) +{ + int i; - return &d->mem; + for (i = 0; i < 2; i++) { + if (hd_table[i]) { + ide_create_drive(&s->bus, i, hd_table[i]); + } + } } + +void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel) +{ + DBDMA_register_channel(dbdma, channel, s->dma_irq, + pmac_ide_transfer, pmac_ide_flush, s); +} + +type_init(macio_ide_register_types) diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c index 89c657fb00..860df328e5 100644 --- a/hw/lsi53c895a.c +++ b/hw/lsi53c895a.c @@ -1670,12 +1670,7 @@ static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val) } if (val & LSI_SCNTL1_RST) { if (!(s->sstat0 & LSI_SSTAT0_RST)) { - BusChild *kid; - - QTAILQ_FOREACH(kid, &s->bus.qbus.children, sibling) { - DeviceState *dev = kid->child; - device_reset(dev); - } + qbus_reset_all(&s->bus.qbus); s->sstat0 |= LSI_SSTAT0_RST; lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0); } diff --git a/hw/m25p80.c b/hw/m25p80.c index d39265632b..788c19608c 100644 --- a/hw/m25p80.c +++ b/hw/m25p80.c @@ -358,6 +358,8 @@ static void complete_collecting_data(Flash *s) s->cur_addr |= s->data[1] << 8; s->cur_addr |= s->data[2]; + s->state = STATE_IDLE; + switch (s->cmd_in_progress) { case DPP: case QPP: diff --git a/hw/mac_nvram.c b/hw/mac_nvram.c index 71093c2b10..25121fa482 100644 --- a/hw/mac_nvram.c +++ b/hw/mac_nvram.c @@ -25,7 +25,7 @@ #include "hw.h" #include "firmware_abi.h" #include "sysemu/sysemu.h" -#include "ppc_mac.h" +#include "ppc/mac.h" /* debug NVR */ //#define DEBUG_NVR @@ -37,37 +37,29 @@ #define NVR_DPRINTF(fmt, ...) #endif -struct MacIONVRAMState { - uint32_t size; - MemoryRegion mem; - unsigned int it_shift; - uint8_t *data; -}; - #define DEF_SYSTEM_SIZE 0xc10 /* Direct access to NVRAM */ -uint32_t macio_nvram_read (void *opaque, uint32_t addr) +uint8_t macio_nvram_read(MacIONVRAMState *s, uint32_t addr) { - MacIONVRAMState *s = opaque; uint32_t ret; - if (addr < s->size) + if (addr < s->size) { ret = s->data[addr]; - else + } else { ret = -1; - NVR_DPRINTF("read addr %04x val %x\n", addr, ret); + } + NVR_DPRINTF("read addr %04" PRIx32 " val %" PRIx8 "\n", addr, ret); return ret; } -void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val) +void macio_nvram_write(MacIONVRAMState *s, uint32_t addr, uint8_t val) { - MacIONVRAMState *s = opaque; - - NVR_DPRINTF("write addr %04x val %x\n", addr, val); - if (addr < s->size) + NVR_DPRINTF("write addr %04" PRIx32 " val %" PRIx8 "\n", addr, val); + if (addr < s->size) { s->data[addr] = val; + } } /* macio style NVRAM device */ @@ -78,7 +70,7 @@ static void macio_nvram_writeb(void *opaque, hwaddr addr, addr = (addr >> s->it_shift) & (s->size - 1); s->data[addr] = value; - NVR_DPRINTF("writeb addr %04x val %x\n", (int)addr, value); + NVR_DPRINTF("writeb addr %04" PHYS_PRIx " val %" PRIx64 "\n", addr, value); } static uint64_t macio_nvram_readb(void *opaque, hwaddr addr, @@ -97,7 +89,7 @@ static uint64_t macio_nvram_readb(void *opaque, hwaddr addr, static const MemoryRegionOps macio_nvram_ops = { .read = macio_nvram_readb, .write = macio_nvram_writeb, - .endianness = DEVICE_NATIVE_ENDIAN, + .endianness = DEVICE_BIG_ENDIAN, }; static const VMStateDescription vmstate_macio_nvram = { @@ -112,32 +104,56 @@ static const VMStateDescription vmstate_macio_nvram = { }; -static void macio_nvram_reset(void *opaque) +static void macio_nvram_reset(DeviceState *dev) { } -MacIONVRAMState *macio_nvram_init (hwaddr size, - unsigned int it_shift) +static void macio_nvram_realizefn(DeviceState *dev, Error **errp) { - MacIONVRAMState *s; + SysBusDevice *d = SYS_BUS_DEVICE(dev); + MacIONVRAMState *s = MACIO_NVRAM(dev); - s = g_malloc0(sizeof(MacIONVRAMState)); - s->data = g_malloc0(size); - s->size = size; - s->it_shift = it_shift; + s->data = g_malloc0(s->size); memory_region_init_io(&s->mem, &macio_nvram_ops, s, "macio-nvram", - size << it_shift); - vmstate_register(NULL, -1, &vmstate_macio_nvram, s); - qemu_register_reset(macio_nvram_reset, s); + s->size << s->it_shift); + sysbus_init_mmio(d, &s->mem); +} + +static void macio_nvram_unrealizefn(DeviceState *dev, Error **errp) +{ + MacIONVRAMState *s = MACIO_NVRAM(dev); - return s; + g_free(s->data); } -void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar, - hwaddr mem_base) +static Property macio_nvram_properties[] = { + DEFINE_PROP_UINT32("size", MacIONVRAMState, size, 0), + DEFINE_PROP_UINT32("it_shift", MacIONVRAMState, it_shift, 0), + DEFINE_PROP_END_OF_LIST() +}; + +static void macio_nvram_class_init(ObjectClass *oc, void *data) { - memory_region_add_subregion(bar, mem_base, &s->mem); + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = macio_nvram_realizefn; + dc->unrealize = macio_nvram_unrealizefn; + dc->reset = macio_nvram_reset; + dc->vmsd = &vmstate_macio_nvram; + dc->props = macio_nvram_properties; +} + +static const TypeInfo macio_nvram_type_info = { + .name = TYPE_MACIO_NVRAM, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(MacIONVRAMState), + .class_init = macio_nvram_class_init, +}; + +static void macio_nvram_register_types(void) +{ + type_register_static(&macio_nvram_type_info); } /* Set up a system OpenBIOS NVRAM partition */ @@ -176,3 +192,5 @@ void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len) end = len; OpenBIOS_finish_partition(part_header, end - start); } + +type_init(macio_nvram_register_types) diff --git a/hw/macio.c b/hw/macio.c index 675a71c051..74bdcd1039 100644 --- a/hw/macio.c +++ b/hw/macio.c @@ -23,118 +23,283 @@ * THE SOFTWARE. */ #include "hw.h" -#include "ppc_mac.h" +#include "ppc/mac.h" #include "pci/pci.h" +#include "mac_dbdma.h" #include "escc.h" +#define TYPE_MACIO "macio" +#define MACIO(obj) OBJECT_CHECK(MacIOState, (obj), TYPE_MACIO) + typedef struct MacIOState { + /*< private >*/ PCIDevice parent; - int is_oldworld; + /*< public >*/ + MemoryRegion bar; + CUDAState cuda; + void *dbdma; MemoryRegion *pic_mem; - MemoryRegion *dbdma_mem; - MemoryRegion *cuda_mem; MemoryRegion *escc_mem; - void *nvram; - int nb_ide; - MemoryRegion *ide_mem[4]; } MacIOState; +#define OLDWORLD_MACIO(obj) \ + OBJECT_CHECK(OldWorldMacIOState, (obj), TYPE_OLDWORLD_MACIO) + +typedef struct OldWorldMacIOState { + /*< private >*/ + MacIOState parent_obj; + /*< public >*/ + + qemu_irq irqs[3]; + + MacIONVRAMState nvram; + MACIOIDEState ide; +} OldWorldMacIOState; + +#define NEWWORLD_MACIO(obj) \ + OBJECT_CHECK(NewWorldMacIOState, (obj), TYPE_NEWWORLD_MACIO) + +typedef struct NewWorldMacIOState { + /*< private >*/ + MacIOState parent_obj; + /*< public >*/ + qemu_irq irqs[5]; + MACIOIDEState ide[2]; +} NewWorldMacIOState; + static void macio_bar_setup(MacIOState *macio_state) { - int i; MemoryRegion *bar = &macio_state->bar; - memory_region_init(bar, "macio", 0x80000); - if (macio_state->pic_mem) { - if (macio_state->is_oldworld) { - /* Heathrow PIC */ - memory_region_add_subregion(bar, 0x00000, macio_state->pic_mem); - } else { - /* OpenPIC */ - memory_region_add_subregion(bar, 0x40000, macio_state->pic_mem); - } - } - if (macio_state->dbdma_mem) { - memory_region_add_subregion(bar, 0x08000, macio_state->dbdma_mem); - } if (macio_state->escc_mem) { memory_region_add_subregion(bar, 0x13000, macio_state->escc_mem); } - if (macio_state->cuda_mem) { - memory_region_add_subregion(bar, 0x16000, macio_state->cuda_mem); +} + +static int macio_common_initfn(PCIDevice *d) +{ + MacIOState *s = MACIO(d); + SysBusDevice *sysbus_dev; + int ret; + + d->config[0x3d] = 0x01; // interrupt on pin 1 + + ret = qdev_init(DEVICE(&s->cuda)); + if (ret < 0) { + return ret; } - for (i = 0; i < macio_state->nb_ide; i++) { - if (macio_state->ide_mem[i]) { - memory_region_add_subregion(bar, 0x1f000 + (i * 0x1000), - macio_state->ide_mem[i]); - } + sysbus_dev = SYS_BUS_DEVICE(&s->cuda); + memory_region_add_subregion(&s->bar, 0x16000, + sysbus_mmio_get_region(sysbus_dev, 0)); + + macio_bar_setup(s); + pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar); + + return 0; +} + +static int macio_oldworld_initfn(PCIDevice *d) +{ + MacIOState *s = MACIO(d); + OldWorldMacIOState *os = OLDWORLD_MACIO(d); + SysBusDevice *sysbus_dev; + int ret = macio_common_initfn(d); + if (ret < 0) { + return ret; + } + + sysbus_dev = SYS_BUS_DEVICE(&s->cuda); + sysbus_connect_irq(sysbus_dev, 0, os->irqs[0]); + + ret = qdev_init(DEVICE(&os->nvram)); + if (ret < 0) { + return ret; } - if (macio_state->nvram != NULL) - macio_nvram_setup_bar(macio_state->nvram, bar, 0x60000); + sysbus_dev = SYS_BUS_DEVICE(&os->nvram); + memory_region_add_subregion(&s->bar, 0x60000, + sysbus_mmio_get_region(sysbus_dev, 0)); + pmac_format_nvram_partition(&os->nvram, os->nvram.size); + + if (s->pic_mem) { + /* Heathrow PIC */ + memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem); + } + + sysbus_dev = SYS_BUS_DEVICE(&os->ide); + sysbus_connect_irq(sysbus_dev, 0, os->irqs[1]); + sysbus_connect_irq(sysbus_dev, 1, os->irqs[2]); + macio_ide_register_dma(&os->ide, s->dbdma, 0x16); + ret = qdev_init(DEVICE(&os->ide)); + if (ret < 0) { + return ret; + } + + return 0; } -static int macio_initfn(PCIDevice *d) +static void macio_oldworld_init(Object *obj) { - d->config[0x3d] = 0x01; // interrupt on pin 1 + MacIOState *s = MACIO(obj); + OldWorldMacIOState *os = OLDWORLD_MACIO(obj); + DeviceState *dev; + + qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs)); + + object_initialize(&os->nvram, TYPE_MACIO_NVRAM); + dev = DEVICE(&os->nvram); + qdev_prop_set_uint32(dev, "size", 0x2000); + qdev_prop_set_uint32(dev, "it_shift", 4); + + object_initialize(&os->ide, TYPE_MACIO_IDE); + qdev_set_parent_bus(DEVICE(&os->ide), sysbus_get_default()); + memory_region_add_subregion(&s->bar, 0x1f000 + (1 * 0x1000), &os->ide.mem); + object_property_add_child(obj, "ide", OBJECT(&os->ide), NULL); +} + +static int macio_newworld_initfn(PCIDevice *d) +{ + MacIOState *s = MACIO(d); + NewWorldMacIOState *ns = NEWWORLD_MACIO(d); + SysBusDevice *sysbus_dev; + int ret = macio_common_initfn(d); + if (ret < 0) { + return ret; + } + + sysbus_dev = SYS_BUS_DEVICE(&s->cuda); + sysbus_connect_irq(sysbus_dev, 0, ns->irqs[0]); + + if (s->pic_mem) { + /* OpenPIC */ + memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem); + } + + sysbus_dev = SYS_BUS_DEVICE(&ns->ide[0]); + sysbus_connect_irq(sysbus_dev, 0, ns->irqs[1]); + sysbus_connect_irq(sysbus_dev, 1, ns->irqs[2]); + macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x16); + ret = qdev_init(DEVICE(&ns->ide[0])); + if (ret < 0) { + return ret; + } + + sysbus_dev = SYS_BUS_DEVICE(&ns->ide[1]); + sysbus_connect_irq(sysbus_dev, 0, ns->irqs[3]); + sysbus_connect_irq(sysbus_dev, 1, ns->irqs[4]); + macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x1a); + ret = qdev_init(DEVICE(&ns->ide[1])); + if (ret < 0) { + return ret; + } + return 0; } +static void macio_newworld_init(Object *obj) +{ + MacIOState *s = MACIO(obj); + NewWorldMacIOState *ns = NEWWORLD_MACIO(obj); + int i; + gchar *name; + + qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs)); + + for (i = 0; i < 2; i++) { + object_initialize(&ns->ide[i], TYPE_MACIO_IDE); + qdev_set_parent_bus(DEVICE(&ns->ide[i]), sysbus_get_default()); + memory_region_add_subregion(&s->bar, 0x1f000 + ((i + 1) * 0x1000), + &ns->ide[i].mem); + name = g_strdup_printf("ide[%i]", i); + object_property_add_child(obj, name, OBJECT(&ns->ide[i]), NULL); + g_free(name); + } +} + +static void macio_instance_init(Object *obj) +{ + MacIOState *s = MACIO(obj); + MemoryRegion *dbdma_mem; + + memory_region_init(&s->bar, "macio", 0x80000); + + object_initialize(&s->cuda, TYPE_CUDA); + qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default()); + object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL); + + s->dbdma = DBDMA_init(&dbdma_mem); + memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem); +} + +static void macio_oldworld_class_init(ObjectClass *oc, void *data) +{ + PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); + + pdc->init = macio_oldworld_initfn; + pdc->device_id = PCI_DEVICE_ID_APPLE_343S1201; +} + +static void macio_newworld_class_init(ObjectClass *oc, void *data) +{ + PCIDeviceClass *pdc = PCI_DEVICE_CLASS(oc); + + pdc->init = macio_newworld_initfn; + pdc->device_id = PCI_DEVICE_ID_APPLE_UNI_N_KEYL; +} + static void macio_class_init(ObjectClass *klass, void *data) { PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); - k->init = macio_initfn; k->vendor_id = PCI_VENDOR_ID_APPLE; k->class_id = PCI_CLASS_OTHERS << 8; } -static const TypeInfo macio_info = { - .name = "macio", +static const TypeInfo macio_oldworld_type_info = { + .name = TYPE_OLDWORLD_MACIO, + .parent = TYPE_MACIO, + .instance_size = sizeof(OldWorldMacIOState), + .instance_init = macio_oldworld_init, + .class_init = macio_oldworld_class_init, +}; + +static const TypeInfo macio_newworld_type_info = { + .name = TYPE_NEWWORLD_MACIO, + .parent = TYPE_MACIO, + .instance_size = sizeof(NewWorldMacIOState), + .instance_init = macio_newworld_init, + .class_init = macio_newworld_class_init, +}; + +static const TypeInfo macio_type_info = { + .name = TYPE_MACIO, .parent = TYPE_PCI_DEVICE, .instance_size = sizeof(MacIOState), + .instance_init = macio_instance_init, + .abstract = true, .class_init = macio_class_init, }; static void macio_register_types(void) { - type_register_static(&macio_info); + type_register_static(&macio_type_info); + type_register_static(&macio_oldworld_type_info); + type_register_static(&macio_newworld_type_info); } type_init(macio_register_types) -void macio_init (PCIBus *bus, int device_id, int is_oldworld, - MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, - MemoryRegion *cuda_mem, void *nvram, - int nb_ide, MemoryRegion **ide_mem, - MemoryRegion *escc_mem) +void macio_init(PCIDevice *d, + MemoryRegion *pic_mem, + MemoryRegion *escc_mem) { - PCIDevice *d; - MacIOState *macio_state; - int i; + MacIOState *macio_state = MACIO(d); - d = pci_create_simple(bus, -1, "macio"); - - macio_state = DO_UPCAST(MacIOState, parent, d); - macio_state->is_oldworld = is_oldworld; macio_state->pic_mem = pic_mem; - macio_state->dbdma_mem = dbdma_mem; - macio_state->cuda_mem = cuda_mem; macio_state->escc_mem = escc_mem; - macio_state->nvram = nvram; - if (nb_ide > 4) - nb_ide = 4; - macio_state->nb_ide = nb_ide; - for (i = 0; i < nb_ide; i++) - macio_state->ide_mem[i] = ide_mem[i]; - for (; i < 4; i++) - macio_state->ide_mem[i] = NULL; /* Note: this code is strongly inspirated from the corresponding code in PearPC */ - pci_config_set_device_id(d->config, device_id); - - macio_bar_setup(macio_state); - pci_register_bar(d, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &macio_state->bar); + qdev_init_nofail(DEVICE(d)); } diff --git a/hw/omap1.c b/hw/omap1.c index 1870f4dfed..623b101f80 100644 --- a/hw/omap1.c +++ b/hw/omap1.c @@ -529,6 +529,7 @@ static uint64_t omap_ulpd_pm_read(void *opaque, hwaddr addr, case 0x28: /* Reserved */ case 0x2c: /* Reserved */ OMAP_BAD_REG(addr); + /* fall through */ case 0x00: /* COUNTER_32_LSB */ case 0x04: /* COUNTER_32_MSB */ case 0x08: /* COUNTER_HIGH_FREQ_LSB */ @@ -633,6 +634,7 @@ static void omap_ulpd_pm_write(void *opaque, hwaddr addr, case 0x28: /* Reserved */ case 0x2c: /* Reserved */ OMAP_BAD_REG(addr); + /* fall through */ case 0x24: /* SETUP_ANALOG_CELL3_ULPD1 */ case 0x38: /* COUNTER_32_FIQ */ case 0x48: /* LOCL_TIME */ @@ -1089,6 +1091,7 @@ static void omap_mpui_write(void *opaque, hwaddr addr, /* Not in OMAP310 */ case 0x14: /* DSP_STATUS */ OMAP_RO_REG(addr); + break; case 0x18: /* DSP_BOOT_CONFIG */ case 0x1c: /* DSP_MPUI_CONFIG */ break; diff --git a/hw/omap_dma.c b/hw/omap_dma.c index aec5874311..0c878b6ef2 100644 --- a/hw/omap_dma.c +++ b/hw/omap_dma.c @@ -1709,19 +1709,25 @@ static uint64_t omap_dma4_read(void *opaque, hwaddr addr, case 0x14: /* DMA4_IRQSTATUS_L3 */ irqn ++; + /* fall through */ case 0x10: /* DMA4_IRQSTATUS_L2 */ irqn ++; + /* fall through */ case 0x0c: /* DMA4_IRQSTATUS_L1 */ irqn ++; + /* fall through */ case 0x08: /* DMA4_IRQSTATUS_L0 */ return s->irqstat[irqn]; case 0x24: /* DMA4_IRQENABLE_L3 */ irqn ++; + /* fall through */ case 0x20: /* DMA4_IRQENABLE_L2 */ irqn ++; + /* fall through */ case 0x1c: /* DMA4_IRQENABLE_L1 */ irqn ++; + /* fall through */ case 0x18: /* DMA4_IRQENABLE_L0 */ return s->irqen[irqn]; @@ -1856,10 +1862,13 @@ static void omap_dma4_write(void *opaque, hwaddr addr, switch (addr) { case 0x14: /* DMA4_IRQSTATUS_L3 */ irqn ++; + /* fall through */ case 0x10: /* DMA4_IRQSTATUS_L2 */ irqn ++; + /* fall through */ case 0x0c: /* DMA4_IRQSTATUS_L1 */ irqn ++; + /* fall through */ case 0x08: /* DMA4_IRQSTATUS_L0 */ s->irqstat[irqn] &= ~value; if (!s->irqstat[irqn]) @@ -1868,10 +1877,13 @@ static void omap_dma4_write(void *opaque, hwaddr addr, case 0x24: /* DMA4_IRQENABLE_L3 */ irqn ++; + /* fall through */ case 0x20: /* DMA4_IRQENABLE_L2 */ irqn ++; + /* fall through */ case 0x1c: /* DMA4_IRQENABLE_L1 */ irqn ++; + /* fall through */ case 0x18: /* DMA4_IRQENABLE_L0 */ s->irqen[irqn] = value; return; diff --git a/hw/omap_spi.c b/hw/omap_spi.c index 42d5149a2b..8ff01ed99d 100644 --- a/hw/omap_spi.c +++ b/hw/omap_spi.c @@ -167,32 +167,47 @@ static uint64_t omap_mcspi_read(void *opaque, hwaddr addr, return s->control; case 0x68: ch ++; + /* fall through */ case 0x54: ch ++; + /* fall through */ case 0x40: ch ++; + /* fall through */ case 0x2c: /* MCSPI_CHCONF */ return s->ch[ch].config; case 0x6c: ch ++; + /* fall through */ case 0x58: ch ++; + /* fall through */ case 0x44: ch ++; + /* fall through */ case 0x30: /* MCSPI_CHSTAT */ return s->ch[ch].status; case 0x70: ch ++; + /* fall through */ case 0x5c: ch ++; + /* fall through */ case 0x48: ch ++; + /* fall through */ case 0x34: /* MCSPI_CHCTRL */ return s->ch[ch].control; case 0x74: ch ++; + /* fall through */ case 0x60: ch ++; + /* fall through */ case 0x4c: ch ++; + /* fall through */ case 0x38: /* MCSPI_TX */ return s->ch[ch].tx; case 0x78: ch ++; + /* fall through */ case 0x64: ch ++; + /* fall through */ case 0x50: ch ++; + /* fall through */ case 0x3c: /* MCSPI_RX */ s->ch[ch].status &= ~(1 << 0); /* RXS */ ret = s->ch[ch].rx; @@ -269,8 +284,11 @@ static void omap_mcspi_write(void *opaque, hwaddr addr, break; case 0x68: ch ++; + /* fall through */ case 0x54: ch ++; + /* fall through */ case 0x40: ch ++; + /* fall through */ case 0x2c: /* MCSPI_CHCONF */ if ((value ^ s->ch[ch].config) & (3 << 14)) /* DMAR | DMAW */ omap_mcspi_dmarequest_update(s->ch + ch); @@ -283,8 +301,11 @@ static void omap_mcspi_write(void *opaque, hwaddr addr, break; case 0x70: ch ++; + /* fall through */ case 0x5c: ch ++; + /* fall through */ case 0x48: ch ++; + /* fall through */ case 0x34: /* MCSPI_CHCTRL */ if (value & ~s->ch[ch].control & 1) { /* EN */ s->ch[ch].control |= 1; @@ -294,8 +315,11 @@ static void omap_mcspi_write(void *opaque, hwaddr addr, break; case 0x74: ch ++; + /* fall through */ case 0x60: ch ++; + /* fall through */ case 0x4c: ch ++; + /* fall through */ case 0x38: /* MCSPI_TX */ s->ch[ch].tx = value; s->ch[ch].status &= ~(1 << 1); /* TXS */ diff --git a/hw/openpic.c b/hw/openpic.c index d414f47b7d..20a479c794 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -34,7 +34,7 @@ * */ #include "hw.h" -#include "ppc_mac.h" +#include "ppc/mac.h" #include "pci/pci.h" #include "openpic.h" #include "sysbus.h" @@ -56,7 +56,7 @@ static const int debug_openpic = 0; } \ } while (0) -#define MAX_CPU 15 +#define MAX_CPU 32 #define MAX_SRC 256 #define MAX_TMR 4 #define MAX_IPI 4 @@ -66,6 +66,7 @@ static const int debug_openpic = 0; /* OpenPIC capability flags */ #define OPENPIC_FLAG_IDR_CRIT (1 << 0) +#define OPENPIC_FLAG_ILR (2 << 0) /* OpenPIC address map */ #define OPENPIC_GLB_REG_START 0x0 @@ -74,6 +75,8 @@ static const int debug_openpic = 0; #define OPENPIC_TMR_REG_SIZE 0x220 #define OPENPIC_MSI_REG_START 0x1600 #define OPENPIC_MSI_REG_SIZE 0x200 +#define OPENPIC_SUMMARY_REG_START 0x3800 +#define OPENPIC_SUMMARY_REG_SIZE 0x800 #define OPENPIC_SRC_REG_START 0x10000 #define OPENPIC_SRC_REG_SIZE (MAX_SRC * 0x20) #define OPENPIC_CPU_REG_START 0x20000 @@ -94,33 +97,17 @@ static const int debug_openpic = 0; /* First doorbell IRQ */ #define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI)) -/* FSL_MPIC_20 */ -#define FSL_MPIC_20_MAX_CPU 1 -#define FSL_MPIC_20_MAX_EXT 12 -#define FSL_MPIC_20_MAX_INT 64 -#define FSL_MPIC_20_MAX_IRQ MAX_IRQ +typedef struct FslMpicInfo { + int max_ext; +} FslMpicInfo; -/* Interrupt definitions */ -/* IRQs, accessible through the IRQ region */ -#define FSL_MPIC_20_EXT_IRQ 0x00 -#define FSL_MPIC_20_INT_IRQ 0x10 -#define FSL_MPIC_20_MSG_IRQ 0xb0 -#define FSL_MPIC_20_MSI_IRQ 0xe0 -/* These are available through separate regions, but - for simplicity's sake mapped into the same number space */ -#define FSL_MPIC_20_TMR_IRQ 0x100 -#define FSL_MPIC_20_IPI_IRQ 0x104 +static FslMpicInfo fsl_mpic_20 = { + .max_ext = 12, +}; -/* - * Block Revision Register1 (BRR1): QEMU does not fully emulate - * any version on MPIC. So to start with, set the IP version to 0. - * - * NOTE: This is Freescale MPIC specific register. Keep it here till - * this code is refactored for different variants of OPENPIC and MPIC. - */ -#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */ -#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */ -#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */ +static FslMpicInfo fsl_mpic_42 = { + .max_ext = 12, +}; #define FRR_NIRQ_SHIFT 16 #define FRR_NCPU_SHIFT 8 @@ -146,6 +133,49 @@ static const int debug_openpic = 0; #define IDR_P1_SHIFT 1 #define IDR_P0_SHIFT 0 +#define ILR_INTTGT_MASK 0x000000ff +#define ILR_INTTGT_INT 0x00 +#define ILR_INTTGT_CINT 0x01 /* critical */ +#define ILR_INTTGT_MCP 0x02 /* machine check */ + +/* The currently supported INTTGT values happen to be the same as QEMU's + * openpic output codes, but don't depend on this. The output codes + * could change (unlikely, but...) or support could be added for + * more INTTGT values. + */ +static const int inttgt_output[][2] = { + { ILR_INTTGT_INT, OPENPIC_OUTPUT_INT }, + { ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT }, + { ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK }, +}; + +static int inttgt_to_output(int inttgt) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) { + if (inttgt_output[i][0] == inttgt) { + return inttgt_output[i][1]; + } + } + + fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt); + return OPENPIC_OUTPUT_INT; +} + +static int output_to_inttgt(int output) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) { + if (inttgt_output[i][1] == output) { + return inttgt_output[i][0]; + } + } + + abort(); +} + #define MSIIR_OFFSET 0x140 #define MSIIR_SRS_SHIFT 29 #define MSIIR_SRS_MASK (0x7 << MSIIR_SRS_SHIFT) @@ -230,6 +260,7 @@ typedef struct OpenPICState { MemoryRegion mem; /* Behavior control */ + FslMpicInfo *fsl; uint32_t model; uint32_t flags; uint32_t nb_irqs; @@ -243,7 +274,7 @@ typedef struct OpenPICState { uint32_t mpic_mode_mask; /* Sub-regions */ - MemoryRegion sub_io_mem[5]; + MemoryRegion sub_io_mem[6]; /* Global registers */ uint32_t frr; /* Feature reporting register */ @@ -436,13 +467,13 @@ static void openpic_update_irq(OpenPICState *opp, int n_IRQ) src->ivpr &= ~IVPR_ACTIVITY_MASK; } - if (src->idr == 0) { + if (src->destmask == 0) { /* No target */ DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); return; } - if (src->idr == (1 << src->last_cpu)) { + if (src->destmask == (1 << src->last_cpu)) { /* Only one CPU is allowed to receive this IRQ */ IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active); } else if (!(src->ivpr & IVPR_MODE_MASK)) { @@ -558,6 +589,15 @@ static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ) return opp->src[n_IRQ].idr; } +static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ) +{ + if (opp->flags & OPENPIC_FLAG_ILR) { + return output_to_inttgt(opp->src[n_IRQ].output); + } + + return 0xffffffff; +} + static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ) { return opp->src[n_IRQ].ivpr; @@ -608,6 +648,19 @@ static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) } } +static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val) +{ + if (opp->flags & OPENPIC_FLAG_ILR) { + IRQSource *src = &opp->src[n_IRQ]; + + src->output = inttgt_to_output(val & ILR_INTTGT_MASK); + DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr, + src->output); + + /* TODO: on MPIC v4.0 only, set nomask for non-INT */ + } +} + static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) { uint32_t mask; @@ -792,19 +845,23 @@ static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, OpenPICState *opp = opaque; int idx; + addr += 0x10f0; + DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", __func__, addr, val); if (addr & 0xF) { return; } - idx = (addr >> 6) & 0x3; - addr = addr & 0x30; - if (addr == 0x0) { + if (addr == 0x10f0) { /* TFRR */ opp->tfrr = val; return; } + + idx = (addr >> 6) & 0x3; + addr = addr & 0x30; + switch (addr & 0x30) { case 0x00: /* TCCR */ break; @@ -870,17 +927,20 @@ static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", __func__, addr, val); - if (addr & 0xF) { - return; - } - addr = addr & 0xFFF0; + + addr = addr & 0xffff; idx = addr >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - write_IRQreg_idr(opp, idx, val); - } else { - /* EXVP / IFEVP / IEEVP */ + + switch (addr & 0x1f) { + case 0x00: write_IRQreg_ivpr(opp, idx, val); + break; + case 0x10: + write_IRQreg_idr(opp, idx, val); + break; + case 0x18: + write_IRQreg_ilr(opp, idx, val); + break; } } @@ -892,20 +952,23 @@ static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); retval = 0xFFFFFFFF; - if (addr & 0xF) { - return retval; - } - addr = addr & 0xFFF0; + + addr = addr & 0xffff; idx = addr >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_idr(opp, idx); - } else { - /* EXVP / IFEVP / IEEVP */ + + switch (addr & 0x1f) { + case 0x00: retval = read_IRQreg_ivpr(opp, idx); + break; + case 0x10: + retval = read_IRQreg_idr(opp, idx); + break; + case 0x18: + retval = read_IRQreg_ilr(opp, idx); + break; } - DPRINTF("%s: => 0x%08x\n", __func__, retval); + DPRINTF("%s: => 0x%08x\n", __func__, retval); return retval; } @@ -973,6 +1036,26 @@ static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) return r; } +static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size) +{ + uint64_t r = 0; + + DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); + + /* TODO: EISR/EIMR */ + + return r; +} + +static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", + __func__, addr, val); + + /* TODO: EISR/EIMR */ +} + static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx) { @@ -1000,8 +1083,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, case 0x70: idx = (addr - 0x40) >> 4; /* we use IDE as mask which CPUs to deliver the IPI to still. */ - write_IRQreg_idr(opp, opp->irq_ipi0 + idx, - opp->src[opp->irq_ipi0 + idx].idr | val); + opp->src[opp->irq_ipi0 + idx].destmask |= val; openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); break; @@ -1101,8 +1183,8 @@ static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) } if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + MAX_IPI))) { - src->idr &= ~(1 << cpu); - if (src->idr && !src->level) { + src->destmask &= ~(1 << cpu); + if (src->destmask && !src->level) { /* trigger on CPUs that didn't know about it yet */ openpic_set_irq(opp, irq, 1); openpic_set_irq(opp, irq, 0); @@ -1239,19 +1321,19 @@ static const MemoryRegionOps openpic_src_ops_be = { }, }; -static const MemoryRegionOps openpic_msi_ops_le = { +static const MemoryRegionOps openpic_msi_ops_be = { .read = openpic_msi_read, .write = openpic_msi_write, - .endianness = DEVICE_LITTLE_ENDIAN, + .endianness = DEVICE_BIG_ENDIAN, .impl = { .min_access_size = 4, .max_access_size = 4, }, }; -static const MemoryRegionOps openpic_msi_ops_be = { - .read = openpic_msi_read, - .write = openpic_msi_write, +static const MemoryRegionOps openpic_summary_ops_be = { + .read = openpic_summary_read, + .write = openpic_summary_write, .endianness = DEVICE_BIG_ENDIAN, .impl = { .min_access_size = 4, @@ -1307,6 +1389,7 @@ static void openpic_save(QEMUFile* f, void *opaque) for (i = 0; i < opp->max_irq; i++) { qemu_put_be32s(f, &opp->src[i].ivpr); qemu_put_be32s(f, &opp->src[i].idr); + qemu_get_be32s(f, &opp->src[i].destmask); qemu_put_sbe32s(f, &opp->src[i].last_cpu); qemu_put_sbe32s(f, &opp->src[i].pending); } @@ -1372,6 +1455,7 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->src[i].ivpr); qemu_get_be32s(f, &opp->src[i].idr); + qemu_get_be32s(f, &opp->src[i].destmask); qemu_get_sbe32s(f, &opp->src[i].last_cpu); qemu_get_sbe32s(f, &opp->src[i].pending); } @@ -1382,78 +1466,128 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) typedef struct MemReg { const char *name; MemoryRegionOps const *ops; - bool map; hwaddr start_addr; ram_addr_t size; } MemReg; +static void fsl_common_init(OpenPICState *opp) +{ + int i; + int virq = MAX_SRC; + + opp->vid = VID_REVISION_1_2; + opp->vir = VIR_GENERIC; + opp->vector_mask = 0xFFFF; + opp->tfrr_reset = 0; + opp->ivpr_reset = IVPR_MASK_MASK; + opp->idr_reset = 1 << 0; + opp->max_irq = MAX_IRQ; + + opp->irq_ipi0 = virq; + virq += MAX_IPI; + opp->irq_tim0 = virq; + virq += MAX_TMR; + + assert(virq <= MAX_IRQ); + + opp->irq_msi = 224; + + msi_supported = true; + for (i = 0; i < opp->fsl->max_ext; i++) { + opp->src[i].level = false; + } + + /* Internal interrupts, including message and MSI */ + for (i = 16; i < MAX_SRC; i++) { + opp->src[i].type = IRQ_TYPE_FSLINT; + opp->src[i].level = true; + } + + /* timers and IPIs */ + for (i = MAX_SRC; i < virq; i++) { + opp->src[i].type = IRQ_TYPE_FSLSPECIAL; + opp->src[i].level = false; + } +} + +static void map_list(OpenPICState *opp, const MemReg *list, int *count) +{ + while (list->name) { + assert(*count < ARRAY_SIZE(opp->sub_io_mem)); + + memory_region_init_io(&opp->sub_io_mem[*count], list->ops, opp, + list->name, list->size); + + memory_region_add_subregion(&opp->mem, list->start_addr, + &opp->sub_io_mem[*count]); + + (*count)++; + list++; + } +} + static int openpic_init(SysBusDevice *dev) { OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev); int i, j; - MemReg list_le[] = { - {"glb", &openpic_glb_ops_le, true, + int list_count = 0; + static const MemReg list_le[] = { + {"glb", &openpic_glb_ops_le, OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, - {"tmr", &openpic_tmr_ops_le, true, + {"tmr", &openpic_tmr_ops_le, OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, - {"msi", &openpic_msi_ops_le, true, - OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, - {"src", &openpic_src_ops_le, true, + {"src", &openpic_src_ops_le, OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, - {"cpu", &openpic_cpu_ops_le, true, + {"cpu", &openpic_cpu_ops_le, OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, + {NULL} }; - MemReg list_be[] = { - {"glb", &openpic_glb_ops_be, true, + static const MemReg list_be[] = { + {"glb", &openpic_glb_ops_be, OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, - {"tmr", &openpic_tmr_ops_be, true, + {"tmr", &openpic_tmr_ops_be, OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, - {"msi", &openpic_msi_ops_be, true, - OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, - {"src", &openpic_src_ops_be, true, + {"src", &openpic_src_ops_be, OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, - {"cpu", &openpic_cpu_ops_be, true, + {"cpu", &openpic_cpu_ops_be, OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, + {NULL} + }; + static const MemReg list_fsl[] = { + {"msi", &openpic_msi_ops_be, + OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, + {"summary", &openpic_summary_ops_be, + OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE}, + {NULL} }; - MemReg *list; + + memory_region_init(&opp->mem, "openpic", 0x40000); switch (opp->model) { case OPENPIC_MODEL_FSL_MPIC_20: default: + opp->fsl = &fsl_mpic_20; + opp->brr1 = 0x00400200; opp->flags |= OPENPIC_FLAG_IDR_CRIT; opp->nb_irqs = 80; - opp->vid = VID_REVISION_1_2; - opp->vir = VIR_GENERIC; - opp->vector_mask = 0xFFFF; - opp->tfrr_reset = 0; - opp->ivpr_reset = IVPR_MASK_MASK; - opp->idr_reset = 1 << 0; - opp->max_irq = FSL_MPIC_20_MAX_IRQ; - opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ; - opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ; - opp->irq_msi = FSL_MPIC_20_MSI_IRQ; - opp->brr1 = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN; - /* XXX really only available as of MPIC 4.0 */ - opp->mpic_mode_mask = GCR_MODE_PROXY; + opp->mpic_mode_mask = GCR_MODE_MIXED; - msi_supported = true; - list = list_be; + fsl_common_init(opp); + map_list(opp, list_be, &list_count); + map_list(opp, list_fsl, &list_count); - for (i = 0; i < FSL_MPIC_20_MAX_EXT; i++) { - opp->src[i].level = false; - } + break; - /* Internal interrupts, including message and MSI */ - for (i = 16; i < MAX_SRC; i++) { - opp->src[i].type = IRQ_TYPE_FSLINT; - opp->src[i].level = true; - } + case OPENPIC_MODEL_FSL_MPIC_42: + opp->fsl = &fsl_mpic_42; + opp->brr1 = 0x00400402; + opp->flags |= OPENPIC_FLAG_ILR; + opp->nb_irqs = 196; + opp->mpic_mode_mask = GCR_MODE_PROXY; - /* timers and IPIs */ - for (i = MAX_SRC; i < MAX_IRQ; i++) { - opp->src[i].type = IRQ_TYPE_FSLSPECIAL; - opp->src[i].level = false; - } + fsl_common_init(opp); + map_list(opp, list_be, &list_count); + map_list(opp, list_fsl, &list_count); break; @@ -1470,29 +1604,14 @@ static int openpic_init(SysBusDevice *dev) opp->irq_tim0 = RAVEN_TMR_IRQ; opp->brr1 = -1; opp->mpic_mode_mask = GCR_MODE_MIXED; - list = list_le; - /* Don't map MSI region */ - list[2].map = false; /* Only UP supported today */ if (opp->nb_cpus != 1) { return -EINVAL; } - break; - } - - memory_region_init(&opp->mem, "openpic", 0x40000); - for (i = 0; i < ARRAY_SIZE(list_le); i++) { - if (!list[i].map) { - continue; - } - - memory_region_init_io(&opp->sub_io_mem[i], list[i].ops, opp, - list[i].name, list[i].size); - - memory_region_add_subregion(&opp->mem, list[i].start_addr, - &opp->sub_io_mem[i]); + map_list(opp, list_le, &list_count); + break; } for (i = 0; i < opp->nb_cpus; i++) { diff --git a/hw/openpic.h b/hw/openpic.h index e226d7b563..9dcaf0e7cd 100644 --- a/hw/openpic.h +++ b/hw/openpic.h @@ -13,5 +13,6 @@ enum { #define OPENPIC_MODEL_RAVEN 0 #define OPENPIC_MODEL_FSL_MPIC_20 1 +#define OPENPIC_MODEL_FSL_MPIC_42 2 #endif /* __OPENPIC_H__ */ diff --git a/hw/pc.c b/hw/pc.c index 780b1e4743..34b6dff686 100644 --- a/hw/pc.c +++ b/hw/pc.c @@ -551,6 +551,18 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type) return index; } +/* Calculates the limit to CPU APIC ID values + * + * This function returns the limit for the APIC ID value, so that all + * CPU APIC IDs are < pc_apic_id_limit(). + * + * This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init(). + */ +static unsigned int pc_apic_id_limit(unsigned int max_cpus) +{ + return x86_cpu_apic_id_from_index(max_cpus - 1) + 1; +} + static void *bochs_bios_init(void) { void *fw_cfg; @@ -558,9 +570,24 @@ static void *bochs_bios_init(void) size_t smbios_len; uint64_t *numa_fw_cfg; int i, j; + unsigned int apic_id_limit = pc_apic_id_limit(max_cpus); fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); - + /* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86: + * + * SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug + * QEMU<->SeaBIOS interface is not based on the "CPU index", but on the APIC + * ID of hotplugged CPUs[1]. This means that FW_CFG_MAX_CPUS is not the + * "maximum number of CPUs", but the "limit to the APIC ID values SeaBIOS + * may see". + * + * So, this means we must not use max_cpus, here, but the maximum possible + * APIC ID value, plus one. + * + * [1] The only kind of "CPU identifier" used between SeaBIOS and QEMU is + * the APIC ID, not the "CPU index" + */ + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)apic_id_limit); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES, @@ -579,21 +606,24 @@ static void *bochs_bios_init(void) * of nodes, one word for each VCPU->node and one word for each node to * hold the amount of memory. */ - numa_fw_cfg = g_new0(uint64_t, 1 + max_cpus + nb_numa_nodes); + numa_fw_cfg = g_new0(uint64_t, 1 + apic_id_limit + nb_numa_nodes); numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes); for (i = 0; i < max_cpus; i++) { + unsigned int apic_id = x86_cpu_apic_id_from_index(i); + assert(apic_id < apic_id_limit); for (j = 0; j < nb_numa_nodes; j++) { if (test_bit(i, node_cpumask[j])) { - numa_fw_cfg[i + 1] = cpu_to_le64(j); + numa_fw_cfg[apic_id + 1] = cpu_to_le64(j); break; } } } for (i = 0; i < nb_numa_nodes; i++) { - numa_fw_cfg[max_cpus + 1 + i] = cpu_to_le64(node_mem[i]); + numa_fw_cfg[apic_id_limit + 1 + i] = cpu_to_le64(node_mem[i]); } fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg, - (1 + max_cpus + nb_numa_nodes) * sizeof(*numa_fw_cfg)); + (1 + apic_id_limit + nb_numa_nodes) * + sizeof(*numa_fw_cfg)); return fw_cfg; } diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 0a6923dcef..b9a9b2efe1 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -235,10 +235,18 @@ static void pc_init_pci(QEMUMachineInitArgs *args) static void pc_init_pci_1_3(QEMUMachineInitArgs *args) { - enable_kvm_pv_eoi(); + enable_compat_apic_id_mode(); pc_init_pci(args); } +/* PC machine init function for pc-0.14 to pc-1.2 */ +static void pc_init_pci_1_2(QEMUMachineInitArgs *args) +{ + disable_kvm_pv_eoi(); + pc_init_pci_1_3(args); +} + +/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) { ram_addr_t ram_size = args->ram_size; @@ -247,6 +255,8 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args) const char *kernel_cmdline = args->kernel_cmdline; const char *initrd_filename = args->initrd_filename; const char *boot_device = args->boot_device; + disable_kvm_pv_eoi(); + enable_compat_apic_id_mode(); pc_init1(get_system_memory(), get_system_io(), ram_size, boot_device, @@ -264,6 +274,8 @@ static void pc_init_isa(QEMUMachineInitArgs *args) const char *boot_device = args->boot_device; if (cpu_model == NULL) cpu_model = "486"; + disable_kvm_pv_eoi(); + enable_compat_apic_id_mode(); pc_init1(get_system_memory(), get_system_io(), ram_size, boot_device, @@ -286,7 +298,7 @@ static QEMUMachine pc_i440fx_machine_v1_4 = { .name = "pc-i440fx-1.4", .alias = "pc", .desc = "Standard PC (i440FX + PIIX, 1996)", - .init = pc_init_pci_1_3, + .init = pc_init_pci, .max_cpus = 255, .is_default = 1, DEFAULT_MACHINE_OPTIONS, @@ -342,7 +354,7 @@ static QEMUMachine pc_machine_v1_3 = { static QEMUMachine pc_machine_v1_2 = { .name = "pc-1.2", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_1_2, @@ -386,7 +398,7 @@ static QEMUMachine pc_machine_v1_2 = { static QEMUMachine pc_machine_v1_1 = { .name = "pc-1.1", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_1_1, @@ -422,7 +434,7 @@ static QEMUMachine pc_machine_v1_1 = { static QEMUMachine pc_machine_v1_0 = { .name = "pc-1.0", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_1_0, @@ -438,7 +450,7 @@ static QEMUMachine pc_machine_v1_0 = { static QEMUMachine pc_machine_v0_15 = { .name = "pc-0.15", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_0_15, @@ -471,7 +483,7 @@ static QEMUMachine pc_machine_v0_15 = { static QEMUMachine pc_machine_v0_14 = { .name = "pc-0.14", .desc = "Standard PC", - .init = pc_init_pci, + .init = pc_init_pci_1_2, .max_cpus = 255, .compat_props = (GlobalProperty[]) { PC_COMPAT_0_14, diff --git a/hw/pci/Makefile.objs b/hw/pci/Makefile.objs index fe965fe2f6..1cd6cde2ee 100644 --- a/hw/pci/Makefile.objs +++ b/hw/pci/Makefile.objs @@ -6,4 +6,4 @@ common-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o common-obj-$(CONFIG_PCI) += pcie.o pcie_aer.o pcie_port.o common-obj-$(CONFIG_NO_PCI) += pci-stub.o -extra-obj-y += pci-stub.o +common-obj-$(CONFIG_ALL) += pci-stub.o diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c index b4220c1896..44bd4654f0 100644 --- a/hw/pflash_cfi02.c +++ b/hw/pflash_cfi02.c @@ -157,6 +157,7 @@ static uint32_t pflash_read (pflash_t *pfl, hwaddr offset, DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd); pfl->wcycle = 0; pfl->cmd = 0; + /* fall through to the read code */ case 0x80: /* We accept reads during second unlock sequence... */ case 0x00: diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index afdcc0e531..462146b0b0 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -3,10 +3,6 @@ obj-y = ppc.o ppc_booke.o # PREP target obj-y += mc146818rtc.o obj-y += ppc_prep.o -# OldWorld PowerMac -obj-y += ppc_oldworld.o -# NewWorld PowerMac -obj-y += ppc_newworld.o # IBM pSeries (sPAPR) obj-$(CONFIG_PSERIES) += spapr.o spapr_hcall.o spapr_rtas.o spapr_vio.o obj-$(CONFIG_PSERIES) += xics.o spapr_vty.o spapr_llan.o spapr_vscsi.o @@ -28,4 +24,9 @@ obj-y += xilinx_ethlite.o obj-y := $(addprefix ../,$(obj-y)) +# OldWorld PowerMac +obj-y += mac_oldworld.o +# NewWorld PowerMac +obj-y += mac_newworld.o +# e500 obj-$(CONFIG_FDT) += e500.o mpc8544ds.o e500plat.o diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 9ccf4d1840..b7474c05f9 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -297,7 +297,7 @@ static int ppce500_load_device_tree(CPUPPCState *env, snprintf(mpic, sizeof(mpic), "%s/pic@%llx", soc, MPC8544_MPIC_REGS_OFFSET); qemu_devtree_add_subnode(fdt, mpic); qemu_devtree_setprop_string(fdt, mpic, "device_type", "open-pic"); - qemu_devtree_setprop_string(fdt, mpic, "compatible", "chrp,open-pic"); + qemu_devtree_setprop_string(fdt, mpic, "compatible", "fsl,mpic"); qemu_devtree_setprop_cells(fdt, mpic, "reg", MPC8544_MPIC_REGS_OFFSET, 0x40000); qemu_devtree_setprop_cell(fdt, mpic, "#address-cells", 0); @@ -505,7 +505,7 @@ void ppce500_init(PPCE500Params *params) irqs[i][OPENPIC_OUTPUT_CINT] = input[PPCE500_INPUT_CINT]; env->spr[SPR_BOOKE_PIR] = cs->cpu_index = i; env->mpic_iack = MPC8544_CCSRBAR_BASE + - MPC8544_MPIC_REGS_OFFSET + 0x200A0; + MPC8544_MPIC_REGS_OFFSET + 0xa0; ppc_booke_timers_init(cpu, 400000000, PPC_TIMER_E500); @@ -545,7 +545,7 @@ void ppce500_init(PPCE500Params *params) mpic = g_new(qemu_irq, 256); dev = qdev_create(NULL, "openpic"); qdev_prop_set_uint32(dev, "nb_cpus", smp_cpus); - qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_FSL_MPIC_20); + qdev_prop_set_uint32(dev, "model", params->mpic_version); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); diff --git a/hw/ppc/e500.h b/hw/ppc/e500.h index f5ff27385b..226c93d248 100644 --- a/hw/ppc/e500.h +++ b/hw/ppc/e500.h @@ -16,6 +16,8 @@ typedef struct PPCE500Params { /* required -- must at least add toplevel board compatible */ void (*fixup_devtree)(struct PPCE500Params *params, void *fdt); + + int mpic_version; } PPCE500Params; void ppce500_init(PPCE500Params *params); diff --git a/hw/ppc/e500plat.c b/hw/ppc/e500plat.c index 2dcc4a9852..25ac4b1dae 100644 --- a/hw/ppc/e500plat.c +++ b/hw/ppc/e500plat.c @@ -15,6 +15,7 @@ #include "../boards.h" #include "sysemu/device_tree.h" #include "hw/pci/pci.h" +#include "hw/openpic.h" static void e500plat_fixup_devtree(PPCE500Params *params, void *fdt) { @@ -44,6 +45,7 @@ static void e500plat_init(QEMUMachineInitArgs *args) .pci_first_slot = 0x1, .pci_nr_slots = PCI_SLOT_MAX - 1, .fixup_devtree = e500plat_fixup_devtree, + .mpic_version = OPENPIC_MODEL_FSL_MPIC_42, }; ppce500_init(¶ms); @@ -53,7 +55,7 @@ static QEMUMachine e500plat_machine = { .name = "ppce500", .desc = "generic paravirt e500 platform", .init = e500plat_init, - .max_cpus = 15, + .max_cpus = 32, DEFAULT_MACHINE_OPTIONS, }; diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h new file mode 100644 index 0000000000..b17107b797 --- /dev/null +++ b/hw/ppc/mac.h @@ -0,0 +1,181 @@ +/* + * QEMU PowerMac emulation shared definitions and prototypes + * + * Copyright (c) 2004-2007 Fabrice Bellard + * Copyright (c) 2007 Jocelyn Mayer + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#if !defined(__PPC_MAC_H__) +#define __PPC_MAC_H__ + +#include "exec/memory.h" +#include "hw/sysbus.h" +#include "hw/ide/internal.h" +#include "hw/adb.h" + +/* SMP is not enabled, for now */ +#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 + +#define KERNEL_LOAD_ADDR 0x01000000 +#define KERNEL_GAP 0x00100000 + +#define ESCC_CLOCK 3686400 + +/* Cuda */ +#define TYPE_CUDA "cuda" +#define CUDA(obj) OBJECT_CHECK(CUDAState, (obj), TYPE_CUDA) + +/** + * CUDATimer: + * @counter_value: counter value at load time + */ +typedef struct CUDATimer { + int index; + uint16_t latch; + uint16_t counter_value; + int64_t load_time; + int64_t next_irq_time; + QEMUTimer *timer; +} CUDATimer; + +/** + * CUDAState: + * @b: B-side data + * @a: A-side data + * @dirb: B-side direction (1=output) + * @dira: A-side direction (1=output) + * @sr: Shift register + * @acr: Auxiliary control register + * @pcr: Peripheral control register + * @ifr: Interrupt flag register + * @ier: Interrupt enable register + * @anh: A-side data, no handshake + * @last_b: last value of B register + * @last_acr: last value of ACR register + */ +typedef struct CUDAState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + MemoryRegion mem; + /* cuda registers */ + uint8_t b; + uint8_t a; + uint8_t dirb; + uint8_t dira; + uint8_t sr; + uint8_t acr; + uint8_t pcr; + uint8_t ifr; + uint8_t ier; + uint8_t anh; + + ADBBusState adb_bus; + CUDATimer timers[2]; + + uint32_t tick_offset; + + uint8_t last_b; + uint8_t last_acr; + + int data_in_size; + int data_in_index; + int data_out_index; + + qemu_irq irq; + uint8_t autopoll; + uint8_t data_in[128]; + uint8_t data_out[16]; + QEMUTimer *adb_poll_timer; +} CUDAState; + +/* MacIO */ +#define TYPE_OLDWORLD_MACIO "macio-oldworld" +#define TYPE_NEWWORLD_MACIO "macio-newworld" + +#define TYPE_MACIO_IDE "macio-ide" +#define MACIO_IDE(obj) OBJECT_CHECK(MACIOIDEState, (obj), TYPE_MACIO_IDE) + +typedef struct MACIOIDEState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + qemu_irq irq; + qemu_irq dma_irq; + + MemoryRegion mem; + IDEBus bus; + BlockDriverAIOCB *aiocb; +} MACIOIDEState; + +void macio_ide_init_drives(MACIOIDEState *ide, DriveInfo **hd_table); +void macio_ide_register_dma(MACIOIDEState *ide, void *dbdma, int channel); + +void macio_init(PCIDevice *dev, + MemoryRegion *pic_mem, + MemoryRegion *escc_mem); + +/* Heathrow PIC */ +qemu_irq *heathrow_pic_init(MemoryRegion **pmem, + int nb_cpus, qemu_irq **irqs); + +/* Grackle PCI */ +#define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost" +PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io); + +/* UniNorth PCI */ +PCIBus *pci_pmac_init(qemu_irq *pic, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io); +PCIBus *pci_pmac_u3_init(qemu_irq *pic, + MemoryRegion *address_space_mem, + MemoryRegion *address_space_io); + +/* Mac NVRAM */ +#define TYPE_MACIO_NVRAM "macio-nvram" +#define MACIO_NVRAM(obj) \ + OBJECT_CHECK(MacIONVRAMState, (obj), TYPE_MACIO_NVRAM) + +typedef struct MacIONVRAMState { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + uint32_t size; + uint32_t it_shift; + + MemoryRegion mem; + uint8_t *data; +} MacIONVRAMState; + +void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len); +uint8_t macio_nvram_read(MacIONVRAMState *s, uint32_t addr); +void macio_nvram_write(MacIONVRAMState *s, uint32_t addr, uint8_t val); +#endif /* !defined(__PPC_MAC_H__) */ diff --git a/hw/ppc_newworld.c b/hw/ppc/mac_newworld.c index b1973f18ff..065ea871b3 100644 --- a/hw/ppc_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -46,28 +46,28 @@ * 0001:05:0c.0 IDE interface [0101]: Broadcom K2 SATA [1166:0240] * */ -#include "hw.h" -#include "ppc.h" -#include "ppc_mac.h" -#include "adb.h" -#include "mac_dbdma.h" -#include "nvram.h" -#include "pci/pci.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "hw/ppc/mac.h" +#include "hw/adb.h" +#include "hw/mac_dbdma.h" +#include "hw/nvram.h" +#include "hw/pci/pci.h" #include "net/net.h" #include "sysemu/sysemu.h" -#include "boards.h" -#include "fw_cfg.h" -#include "escc.h" -#include "openpic.h" -#include "ide.h" -#include "loader.h" +#include "hw/boards.h" +#include "hw/fw_cfg.h" +#include "hw/escc.h" +#include "hw/openpic.h" +#include "hw/ide.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" #include "hw/usb.h" #include "sysemu/blockdev.h" #include "exec/address-spaces.h" -#include "sysbus.h" +#include "hw/sysbus.h" #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 @@ -147,15 +147,16 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) hwaddr kernel_base, initrd_base, cmdline_base = 0; long kernel_size, initrd_size; PCIBus *pci_bus; + PCIDevice *macio; + MACIOIDEState *macio_ide; + BusState *adb_bus; MacIONVRAMState *nvr; int bios_size; - MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem, *escc_mem; + MemoryRegion *pic_mem, *escc_mem; MemoryRegion *escc_bar = g_new(MemoryRegion, 1); - MemoryRegion *ide_mem[3]; int ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; - void *dbdma; int machine_arch; SysBusDevice *s; DeviceState *dev; @@ -362,20 +363,31 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); ide_drive_get(hd, MAX_IDE_BUS); - dbdma = DBDMA_init(&dbdma_mem); - /* We only emulate 2 out of 3 IDE controllers for now */ - ide_mem[0] = NULL; - ide_mem[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]); - ide_mem[2] = pmac_ide_init(&hd[MAX_IDE_DEVS], pic[0x0e], dbdma, 0x1a, pic[0x02]); + macio = pci_create(pci_bus, -1, TYPE_NEWWORLD_MACIO); + dev = DEVICE(macio); + qdev_connect_gpio_out(dev, 0, pic[0x19]); /* CUDA */ + qdev_connect_gpio_out(dev, 1, pic[0x0d]); /* IDE */ + qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */ + qdev_connect_gpio_out(dev, 3, pic[0x0e]); /* IDE */ + qdev_connect_gpio_out(dev, 4, pic[0x02]); /* IDE DMA */ + macio_init(macio, pic_mem, escc_bar); - cuda_init(&cuda_mem, pic[0x19]); + /* We only emulate 2 out of 3 IDE controllers for now */ + macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), + "ide[0]")); + macio_ide_init_drives(macio_ide, hd); - adb_kbd_init(&adb_bus); - adb_mouse_init(&adb_bus); + macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), + "ide[1]")); + macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]); - macio_init(pci_bus, PCI_DEVICE_ID_APPLE_UNI_N_KEYL, 0, pic_mem, - dbdma_mem, cuda_mem, NULL, 3, ide_mem, escc_bar); + dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda")); + adb_bus = qdev_get_child_bus(dev, "adb.0"); + dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD); + qdev_init_nofail(dev); + dev = qdev_create(adb_bus, TYPE_ADB_MOUSE); + qdev_init_nofail(dev); if (usb_enabled(machine_arch == ARCH_MAC99_U3)) { pci_create_simple(pci_bus, -1, "pci-ohci"); @@ -391,12 +403,17 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) graphic_depth = 15; /* The NewWorld NVRAM is not located in the MacIO device */ - nvr = macio_nvram_init(0x2000, 1); + dev = qdev_create(NULL, TYPE_MACIO_NVRAM); + qdev_prop_set_uint32(dev, "size", 0x2000); + qdev_prop_set_uint32(dev, "it_shift", 1); + qdev_init_nofail(dev); + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xFFF04000); + nvr = MACIO_NVRAM(dev); pmac_format_nvram_partition(nvr, 0x2000); - macio_nvram_setup_bar(nvr, get_system_memory(), 0xFFF04000); /* No PCI init: the BIOS will do it */ fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, machine_arch); diff --git a/hw/ppc_oldworld.c b/hw/ppc/mac_oldworld.c index de34e7530a..2778e45879 100644 --- a/hw/ppc_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -23,21 +23,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "hw.h" -#include "ppc.h" -#include "ppc_mac.h" -#include "adb.h" -#include "mac_dbdma.h" -#include "nvram.h" +#include "hw/hw.h" +#include "hw/ppc.h" +#include "mac.h" +#include "hw/adb.h" +#include "hw/nvram.h" #include "sysemu/sysemu.h" #include "net/net.h" -#include "isa.h" -#include "pci/pci.h" -#include "boards.h" -#include "fw_cfg.h" -#include "escc.h" -#include "ide.h" -#include "loader.h" +#include "hw/isa.h" +#include "hw/pci/pci.h" +#include "hw/boards.h" +#include "hw/fw_cfg.h" +#include "hw/escc.h" +#include "hw/ide.h" +#include "hw/loader.h" #include "elf.h" #include "sysemu/kvm.h" #include "kvm_ppc.h" @@ -90,14 +89,16 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) uint32_t kernel_base, initrd_base, cmdline_base = 0; int32_t kernel_size, initrd_size; PCIBus *pci_bus; - MacIONVRAMState *nvr; + PCIDevice *macio; + MACIOIDEState *macio_ide; + DeviceState *dev; + BusState *adb_bus; int bios_size; - MemoryRegion *pic_mem, *dbdma_mem, *cuda_mem; - MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1), *ide_mem[2]; + MemoryRegion *pic_mem; + MemoryRegion *escc_mem, *escc_bar = g_new(MemoryRegion, 1); uint16_t ppc_boot_device; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; void *fw_cfg; - void *dbdma; linux_boot = (kernel_filename != NULL); @@ -263,10 +264,17 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) ide_drive_get(hd, MAX_IDE_BUS); + macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO); + dev = DEVICE(macio); + qdev_connect_gpio_out(dev, 0, pic[0x12]); /* CUDA */ + qdev_connect_gpio_out(dev, 1, pic[0x0D]); /* IDE */ + qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */ + macio_init(macio, pic_mem, escc_bar); + /* First IDE channel is a MAC IDE on the MacIO bus */ - dbdma = DBDMA_init(&dbdma_mem); - ide_mem[0] = NULL; - ide_mem[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]); + macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), + "ide")); + macio_ide_init_drives(macio_ide, hd); /* Second IDE channel is a CMD646 on the PCI bus */ hd[0] = hd[MAX_IDE_DEVS]; @@ -274,17 +282,12 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) hd[3] = hd[2] = NULL; pci_cmd646_ide_init(pci_bus, hd, 0); - /* cuda also initialize ADB */ - cuda_init(&cuda_mem, pic[0x12]); - - adb_kbd_init(&adb_bus); - adb_mouse_init(&adb_bus); - - nvr = macio_nvram_init(0x2000, 4); - pmac_format_nvram_partition(nvr, 0x2000); - - macio_init(pci_bus, PCI_DEVICE_ID_APPLE_343S1201, 1, pic_mem, - dbdma_mem, cuda_mem, nvr, 2, ide_mem, escc_bar); + dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda")); + adb_bus = qdev_get_child_bus(dev, "adb.0"); + dev = qdev_create(adb_bus, TYPE_ADB_KEYBOARD); + qdev_init_nofail(dev); + dev = qdev_create(adb_bus, TYPE_ADB_MOUSE); + qdev_init_nofail(dev); if (usb_enabled(false)) { pci_create_simple(pci_bus, -1, "pci-ohci"); @@ -296,6 +299,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) /* No PCI init: the BIOS will do it */ fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_HEATHROW); diff --git a/hw/ppc/mpc8544ds.c b/hw/ppc/mpc8544ds.c index 8e05e55c87..e25c70b1f3 100644 --- a/hw/ppc/mpc8544ds.c +++ b/hw/ppc/mpc8544ds.c @@ -14,6 +14,7 @@ #include "e500.h" #include "../boards.h" #include "sysemu/device_tree.h" +#include "hw/openpic.h" static void mpc8544ds_fixup_devtree(PPCE500Params *params, void *fdt) { @@ -43,6 +44,7 @@ static void mpc8544ds_init(QEMUMachineInitArgs *args) .pci_first_slot = 0x11, .pci_nr_slots = 2, .fixup_devtree = mpc8544ds_fixup_devtree, + .mpic_version = OPENPIC_MODEL_FSL_MPIC_20, }; ppce500_init(¶ms); diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h deleted file mode 100644 index 89c7d66386..0000000000 --- a/hw/ppc_mac.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * QEMU PowerMac emulation shared definitions and prototypes - * - * Copyright (c) 2004-2007 Fabrice Bellard - * Copyright (c) 2007 Jocelyn Mayer - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#if !defined(__PPC_MAC_H__) -#define __PPC_MAC_H__ - -#include "exec/memory.h" - -/* SMP is not enabled, for now */ -#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 - -#define KERNEL_LOAD_ADDR 0x01000000 -#define KERNEL_GAP 0x00100000 - -#define ESCC_CLOCK 3686400 - -/* Cuda */ -void cuda_init (MemoryRegion **cuda_mem, qemu_irq irq); - -/* MacIO */ -void macio_init (PCIBus *bus, int device_id, int is_oldworld, - MemoryRegion *pic_mem, MemoryRegion *dbdma_mem, - MemoryRegion *cuda_mem, void *nvram, - int nb_ide, MemoryRegion **ide_mem, MemoryRegion *escc_mem); - -/* Heathrow PIC */ -qemu_irq *heathrow_pic_init(MemoryRegion **pmem, - int nb_cpus, qemu_irq **irqs); - -/* Grackle PCI */ -#define TYPE_GRACKLE_PCI_HOST_BRIDGE "grackle-pcihost" -PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io); - -/* UniNorth PCI */ -PCIBus *pci_pmac_init(qemu_irq *pic, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io); -PCIBus *pci_pmac_u3_init(qemu_irq *pic, - MemoryRegion *address_space_mem, - MemoryRegion *address_space_io); - -/* Mac NVRAM */ -typedef struct MacIONVRAMState MacIONVRAMState; - -MacIONVRAMState *macio_nvram_init (hwaddr size, - unsigned int it_shift); -void macio_nvram_setup_bar(MacIONVRAMState *s, MemoryRegion *bar, - hwaddr mem_base); -void pmac_format_nvram_partition (MacIONVRAMState *nvr, int len); -uint32_t macio_nvram_read (void *opaque, uint32_t addr); -void macio_nvram_write (void *opaque, uint32_t addr, uint32_t val); -#endif /* !defined(__PPC_MAC_H__) */ diff --git a/hw/pxa2xx_timer.c b/hw/pxa2xx_timer.c index 32c1872680..5c9d2e8bc6 100644 --- a/hw/pxa2xx_timer.c +++ b/hw/pxa2xx_timer.c @@ -157,17 +157,27 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, switch (offset) { case OSMR3: tm ++; + /* fall through */ case OSMR2: tm ++; + /* fall through */ case OSMR1: tm ++; + /* fall through */ case OSMR0: return s->timer[tm].value; case OSMR11: tm ++; + /* fall through */ case OSMR10: tm ++; + /* fall through */ case OSMR9: tm ++; + /* fall through */ case OSMR8: tm ++; + /* fall through */ case OSMR7: tm ++; + /* fall through */ case OSMR6: tm ++; + /* fall through */ case OSMR5: tm ++; + /* fall through */ case OSMR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -176,12 +186,19 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) - s->lastload, s->freq, get_ticks_per_sec()); case OSCR11: tm ++; + /* fall through */ case OSCR10: tm ++; + /* fall through */ case OSCR9: tm ++; + /* fall through */ case OSCR8: tm ++; + /* fall through */ case OSCR7: tm ++; + /* fall through */ case OSCR6: tm ++; + /* fall through */ case OSCR5: tm ++; + /* fall through */ case OSCR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -207,12 +224,19 @@ static uint64_t pxa2xx_timer_read(void *opaque, hwaddr offset, case OWER: return s->reset3; case OMCR11: tm ++; + /* fall through */ case OMCR10: tm ++; + /* fall through */ case OMCR9: tm ++; + /* fall through */ case OMCR8: tm ++; + /* fall through */ case OMCR7: tm ++; + /* fall through */ case OMCR6: tm ++; + /* fall through */ case OMCR5: tm ++; + /* fall through */ case OMCR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -235,19 +259,29 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, switch (offset) { case OSMR3: tm ++; + /* fall through */ case OSMR2: tm ++; + /* fall through */ case OSMR1: tm ++; + /* fall through */ case OSMR0: s->timer[tm].value = value; pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock)); break; case OSMR11: tm ++; + /* fall through */ case OSMR10: tm ++; + /* fall through */ case OSMR9: tm ++; + /* fall through */ case OSMR8: tm ++; + /* fall through */ case OSMR7: tm ++; + /* fall through */ case OSMR6: tm ++; + /* fall through */ case OSMR5: tm ++; + /* fall through */ case OSMR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -261,12 +295,19 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, pxa2xx_timer_update(s, s->lastload); break; case OSCR11: tm ++; + /* fall through */ case OSCR10: tm ++; + /* fall through */ case OSCR9: tm ++; + /* fall through */ case OSCR8: tm ++; + /* fall through */ case OSCR7: tm ++; + /* fall through */ case OSCR6: tm ++; + /* fall through */ case OSCR5: tm ++; + /* fall through */ case OSCR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -291,8 +332,11 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, s->reset3 = value; break; case OMCR7: tm ++; + /* fall through */ case OMCR6: tm ++; + /* fall through */ case OMCR5: tm ++; + /* fall through */ case OMCR4: if (!pxa2xx_timer_has_tm4(s)) goto badreg; @@ -306,8 +350,11 @@ static void pxa2xx_timer_write(void *opaque, hwaddr offset, } break; case OMCR11: tm ++; + /* fall through */ case OMCR10: tm ++; + /* fall through */ case OMCR9: tm ++; + /* fall through */ case OMCR8: tm += 4; if (!pxa2xx_timer_has_tm4(s)) goto badreg; diff --git a/hw/qxl.c b/hw/qxl.c index 9dc44b9b88..a125e294aa 100644 --- a/hw/qxl.c +++ b/hw/qxl.c @@ -80,9 +80,7 @@ #define QXL_MODE_EX(x_res, y_res) \ QXL_MODE_16_32(x_res, y_res, 0), \ - QXL_MODE_16_32(y_res, x_res, 1), \ - QXL_MODE_16_32(x_res, y_res, 2), \ - QXL_MODE_16_32(y_res, x_res, 3) + QXL_MODE_16_32(x_res, y_res, 1) static QXLMode qxl_modes[] = { QXL_MODE_EX(640, 480), @@ -306,10 +304,13 @@ static inline uint32_t msb_mask(uint32_t val) static ram_addr_t qxl_rom_size(void) { - uint32_t rom_size = sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes); + uint32_t required_rom_size = sizeof(QXLRom) + sizeof(QXLModes) + + sizeof(qxl_modes); + uint32_t rom_size = 8192; /* two pages */ - rom_size = MAX(rom_size, TARGET_PAGE_SIZE); - rom_size = msb_mask(rom_size * 2 - 1); + required_rom_size = MAX(required_rom_size, TARGET_PAGE_SIZE); + required_rom_size = msb_mask(required_rom_size * 2 - 1); + assert(required_rom_size <= rom_size); return rom_size; } @@ -945,6 +946,12 @@ static void interface_set_client_capabilities(QXLInstance *sin, { PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + if (qxl->revision < 4) { + trace_qxl_set_client_capabilities_unsupported_by_revision(qxl->id, + qxl->revision); + return; + } + if (runstate_check(RUN_STATE_INMIGRATE) || runstate_check(RUN_STATE_POSTMIGRATE)) { return; @@ -979,6 +986,11 @@ static int interface_client_monitors_config(QXLInstance *sin, QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar); int i; + if (qxl->revision < 4) { + trace_qxl_client_monitors_config_unsupported_by_device(qxl->id, + qxl->revision); + return 0; + } /* * Older windows drivers set int_mask to 0 when their ISR is called, * then later set it to ~0. So it doesn't relate to the actual interrupts diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c index 267a942f76..a97f1cdc1c 100644 --- a/hw/scsi-bus.c +++ b/hw/scsi-bus.c @@ -282,7 +282,7 @@ static const struct SCSIReqOps reqops_invalid_opcode = { static int32_t scsi_unit_attention(SCSIRequest *req, uint8_t *buf) { - if (req->dev && req->dev->unit_attention.key == UNIT_ATTENTION) { + if (req->dev->unit_attention.key == UNIT_ATTENTION) { scsi_req_build_sense(req, req->dev->unit_attention); } else if (req->bus->unit_attention.key == UNIT_ATTENTION) { scsi_req_build_sense(req, req->bus->unit_attention); diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c index 96db9a73c7..28e75bbf5b 100644 --- a/hw/scsi-disk.c +++ b/hw/scsi-disk.c @@ -1680,7 +1680,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); if (!nb_sectors) { scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY)); - return -1; + return 0; } if ((req->cmd.buf[8] & 1) == 0 && req->cmd.lba) { goto illegal_request; @@ -1749,7 +1749,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors); if (!nb_sectors) { scsi_check_condition(r, SENSE_CODE(LUN_NOT_READY)); - return -1; + return 0; } if ((req->cmd.buf[14] & 1) == 0 && req->cmd.lba) { goto illegal_request; diff --git a/hw/serial.c b/hw/serial.c index a5b2a0c609..f0ce9b0c15 100644 --- a/hw/serial.c +++ b/hw/serial.c @@ -266,8 +266,6 @@ static void serial_xmit(void *opaque) s->tsr = fifo_get(s,XMIT_FIFO); if (!s->xmit_fifo.count) s->lsr |= UART_LSR_THRE; - } else if ((s->lsr & UART_LSR_THRE)) { - return; } else { s->tsr = s->thr; s->lsr |= UART_LSR_THRE; @@ -279,7 +277,7 @@ static void serial_xmit(void *opaque) /* in loopback mode, say that we just received a char */ serial_receive1(s, &s->tsr, 1); } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { - if ((s->tsr_retry >= 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { + if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { s->tsr_retry++; qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time); return; diff --git a/hw/smc91c111.c b/hw/smc91c111.c index 36cb4ed74f..fe2389bf25 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -442,6 +442,7 @@ static void smc91c111_writeb(void *opaque, hwaddr offset, return; case 12: /* Early receive. */ s->ercv = value & 0x1f; + return; case 13: /* Ignore. */ return; diff --git a/hw/spapr.c b/hw/spapr.c index d80b792b37..e88a27aa71 100644 --- a/hw/spapr.c +++ b/hw/spapr.c @@ -77,12 +77,6 @@ #define MAX_CPUS 256 #define XICS_IRQS 1024 -#define SPAPR_PCI_BUID 0x800000020000001ULL -#define SPAPR_PCI_MEM_WIN_ADDR (0x10000000000ULL + 0xA0000000) -#define SPAPR_PCI_MEM_WIN_SIZE 0x20000000 -#define SPAPR_PCI_IO_WIN_ADDR (0x10000000000ULL + 0x80000000) -#define SPAPR_PCI_MSI_WIN_ADDR (0x10000000000ULL + 0x90000000) - #define PHANDLE_XICP 0x00001111 #define HTAB_SIZE(spapr) (1ULL << ((spapr)->htab_shift)) @@ -857,12 +851,7 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) /* Set up PCI */ spapr_pci_rtas_init(); - spapr_create_phb(spapr, "pci", SPAPR_PCI_BUID, - SPAPR_PCI_MEM_WIN_ADDR, - SPAPR_PCI_MEM_WIN_SIZE, - SPAPR_PCI_IO_WIN_ADDR, - SPAPR_PCI_MSI_WIN_ADDR); - phb = PCI_HOST_BRIDGE(QLIST_FIRST(&spapr->phbs)); + phb = spapr_create_phb(spapr, 0, "pci"); for (i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; diff --git a/hw/spapr_pci.c b/hw/spapr_pci.c index bbcc9fc968..4eacbcfd58 100644 --- a/hw/spapr_pci.c +++ b/hw/spapr_pci.c @@ -435,7 +435,7 @@ static void pci_spapr_set_irq(void *opaque, int irq_num, int level) */ sPAPRPHBState *phb = opaque; - trace_spapr_pci_lsi_set(phb->busname, irq_num, phb->lsi_table[irq_num].irq); + trace_spapr_pci_lsi_set(phb->dtbusname, irq_num, phb->lsi_table[irq_num].irq); qemu_set_irq(spapr_phb_lsi_qirq(phb, irq_num), level); } @@ -522,7 +522,63 @@ static int spapr_phb_init(SysBusDevice *s) int i; PCIBus *bus; + if (sphb->index != -1) { + hwaddr windows_base; + + if ((sphb->buid != -1) || (sphb->dma_liobn != -1) + || (sphb->mem_win_addr != -1) + || (sphb->io_win_addr != -1) + || (sphb->msi_win_addr != -1)) { + fprintf(stderr, "Either \"index\" or other parameters must" + " be specified for PAPR PHB, not both\n"); + return -1; + } + + sphb->buid = SPAPR_PCI_BASE_BUID + sphb->index; + sphb->dma_liobn = SPAPR_PCI_BASE_LIOBN + sphb->index; + + windows_base = SPAPR_PCI_WINDOW_BASE + + sphb->index * SPAPR_PCI_WINDOW_SPACING; + sphb->mem_win_addr = windows_base + SPAPR_PCI_MMIO_WIN_OFF; + sphb->io_win_addr = windows_base + SPAPR_PCI_IO_WIN_OFF; + sphb->msi_win_addr = windows_base + SPAPR_PCI_MSI_WIN_OFF; + } + + if (sphb->buid == -1) { + fprintf(stderr, "BUID not specified for PHB\n"); + return -1; + } + + if (sphb->dma_liobn == -1) { + fprintf(stderr, "LIOBN not specified for PHB\n"); + return -1; + } + + if (sphb->mem_win_addr == -1) { + fprintf(stderr, "Memory window address not specified for PHB\n"); + return -1; + } + + if (sphb->io_win_addr == -1) { + fprintf(stderr, "IO window address not specified for PHB\n"); + return -1; + } + + if (sphb->msi_win_addr == -1) { + fprintf(stderr, "MSI window address not specified for PHB\n"); + return -1; + } + + if (find_phb(spapr, sphb->buid)) { + fprintf(stderr, "PCI host bridges must have unique BUIDs\n"); + return -1; + } + sphb->dtbusname = g_strdup_printf("pci@%" PRIx64, sphb->buid); + if (!sphb->busname) { + sphb->busname = sphb->dtbusname; + } + namebuf = alloca(strlen(sphb->dtbusname) + 32); /* Initialize memory regions */ @@ -565,17 +621,19 @@ static int spapr_phb_init(SysBusDevice *s) &sphb->msiwindow); } - bus = pci_register_bus(DEVICE(s), - sphb->busname ? sphb->busname : sphb->dtbusname, + bus = pci_register_bus(DEVICE(s), sphb->busname, pci_spapr_set_irq, pci_spapr_map_irq, sphb, &sphb->memspace, &sphb->iospace, PCI_DEVFN(0, 0), PCI_NUM_PINS); phb->bus = bus; - sphb->dma_liobn = SPAPR_PCI_BASE_LIOBN | (pci_find_domain(bus) << 16); sphb->dma_window_start = 0; sphb->dma_window_size = 0x40000000; sphb->dma = spapr_tce_new_dma_context(sphb->dma_liobn, sphb->dma_window_size); + if (!sphb->dma) { + fprintf(stderr, "Unable to create TCE table for %s\n", sphb->dtbusname); + return -1; + } pci_setup_iommu(bus, spapr_pci_dma_context_fn, sphb); QLIST_INSERT_HEAD(&spapr->phbs, sphb, list); @@ -605,13 +663,17 @@ static void spapr_phb_reset(DeviceState *qdev) } static Property spapr_phb_properties[] = { - DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, 0), DEFINE_PROP_STRING("busname", sPAPRPHBState, busname), - DEFINE_PROP_HEX64("mem_win_addr", sPAPRPHBState, mem_win_addr, 0), - DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, 0x20000000), - DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, 0), - DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, 0x10000), - DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, 0), + DEFINE_PROP_INT32("index", sPAPRPHBState, index, -1), + DEFINE_PROP_HEX64("buid", sPAPRPHBState, buid, -1), + DEFINE_PROP_HEX32("liobn", sPAPRPHBState, dma_liobn, -1), + DEFINE_PROP_HEX64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1), + DEFINE_PROP_HEX64("mem_win_size", sPAPRPHBState, mem_win_size, + SPAPR_PCI_MMIO_WIN_SIZE), + DEFINE_PROP_HEX64("io_win_addr", sPAPRPHBState, io_win_addr, -1), + DEFINE_PROP_HEX64("io_win_size", sPAPRPHBState, io_win_size, + SPAPR_PCI_IO_WIN_SIZE), + DEFINE_PROP_HEX64("msi_win_addr", sPAPRPHBState, msi_win_addr, -1), DEFINE_PROP_END_OF_LIST(), }; @@ -632,25 +694,17 @@ static const TypeInfo spapr_phb_info = { .class_init = spapr_phb_class_init, }; -void spapr_create_phb(sPAPREnvironment *spapr, - const char *busname, uint64_t buid, - uint64_t mem_win_addr, uint64_t mem_win_size, - uint64_t io_win_addr, uint64_t msi_win_addr) +PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index, + const char *busname) { DeviceState *dev; dev = qdev_create(NULL, TYPE_SPAPR_PCI_HOST_BRIDGE); - - if (busname) { - qdev_prop_set_string(dev, "busname", g_strdup(busname)); - } - qdev_prop_set_uint64(dev, "buid", buid); - qdev_prop_set_uint64(dev, "mem_win_addr", mem_win_addr); - qdev_prop_set_uint64(dev, "mem_win_size", mem_win_size); - qdev_prop_set_uint64(dev, "io_win_addr", io_win_addr); - qdev_prop_set_uint64(dev, "msi_win_addr", msi_win_addr); - + qdev_prop_set_uint32(dev, "index", index); + qdev_prop_set_string(dev, "busname", busname); qdev_init_nofail(dev); + + return PCI_HOST_BRIDGE(dev); } /* Macros to operate with address in OF binding to PCI */ diff --git a/hw/spapr_pci.h b/hw/spapr_pci.h index 7b26ba1561..8bb3c62c3d 100644 --- a/hw/spapr_pci.h +++ b/hw/spapr_pci.h @@ -37,6 +37,7 @@ typedef struct sPAPRPHBState { PCIHostState parent_obj; + int32_t index; uint64_t buid; char *busname; char *dtbusname; @@ -64,18 +65,25 @@ typedef struct sPAPRPHBState { QLIST_ENTRY(sPAPRPHBState) list; } sPAPRPHBState; +#define SPAPR_PCI_BASE_BUID 0x800000020000000ULL + +#define SPAPR_PCI_WINDOW_BASE 0x10000000000ULL +#define SPAPR_PCI_WINDOW_SPACING 0x1000000000ULL +#define SPAPR_PCI_MMIO_WIN_OFF 0xA0000000 +#define SPAPR_PCI_MMIO_WIN_SIZE 0x20000000 +#define SPAPR_PCI_IO_WIN_OFF 0x80000000 +#define SPAPR_PCI_IO_WIN_SIZE 0x10000 +#define SPAPR_PCI_MSI_WIN_OFF 0x90000000 + +#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL + static inline qemu_irq spapr_phb_lsi_qirq(struct sPAPRPHBState *phb, int pin) { return xics_get_qirq(spapr->icp, phb->lsi_table[pin].irq); } -#define SPAPR_PCI_MEM_WIN_BUS_OFFSET 0x80000000ULL -#define SPAPR_PCI_IO_WIN_SIZE 0x10000 - -void spapr_create_phb(sPAPREnvironment *spapr, - const char *busname, uint64_t buid, - uint64_t mem_win_addr, uint64_t mem_win_size, - uint64_t io_win_addr, uint64_t msi_win_addr); +PCIHostState *spapr_create_phb(sPAPREnvironment *spapr, int index, + const char *busname); int spapr_populate_pci_dt(sPAPRPHBState *phb, uint32_t xics_phandle, diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c index 2054219c95..34c9ca6b65 100644 --- a/hw/spapr_vio.c +++ b/hw/spapr_vio.c @@ -492,7 +492,7 @@ VIOsPAPRBus *spapr_vio_bus_init(void) qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); bus = DO_UPCAST(VIOsPAPRBus, bus, qbus); - bus->next_reg = 0x1000; + bus->next_reg = 0x71000000; /* hcall-vio */ spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); diff --git a/hw/sun4m.c b/hw/sun4m.c index 035a011768..9903f443cb 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -1021,6 +1021,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size, hwdef->ecc_version); fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); @@ -1665,6 +1666,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size, "Sun4d"); fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); @@ -1865,6 +1867,7 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size, "Sun4c"); fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); diff --git a/hw/sun4u.c b/hw/sun4u.c index b891b84c9c..9fbda29ac4 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -878,6 +878,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, (uint8_t *)&nd_table[0].macaddr); fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0); + fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus); fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1); fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size); fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id); diff --git a/hw/unin_pci.c b/hw/unin_pci.c index 46757924b6..f1c3c20f37 100644 --- a/hw/unin_pci.c +++ b/hw/unin_pci.c @@ -22,7 +22,7 @@ * THE SOFTWARE. */ #include "hw.h" -#include "ppc_mac.h" +#include "ppc/mac.h" #include "pci/pci.h" #include "pci/pci_host.h" diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c index b839798eaf..b89d00f7cf 100644 --- a/hw/usb/dev-storage.c +++ b/hw/usb/dev-storage.c @@ -54,12 +54,12 @@ typedef struct { struct usb_msd_csw csw; SCSIRequest *req; SCSIBus bus; + /* For async completion. */ + USBPacket *packet; + /* usb-storage only */ BlockConf conf; char *serial; - SCSIDevice *scsi_dev; uint32_t removable; - /* For async completion. */ - USBPacket *packet; } MSDState; struct usb_msd_cbw { @@ -343,7 +343,8 @@ static void usb_msd_handle_control(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data) { MSDState *s = (MSDState *)dev; - int ret; + SCSIDevice *scsi_dev; + int ret, maxlun; ret = usb_desc_handle_control(dev, p, request, value, index, length, data); if (ret >= 0) { @@ -359,7 +360,19 @@ static void usb_msd_handle_control(USBDevice *dev, USBPacket *p, s->mode = USB_MSDM_CBW; break; case ClassInterfaceRequest | GetMaxLun: - data[0] = 0; + maxlun = 0; + for (;;) { + scsi_dev = scsi_device_find(&s->bus, 0, 0, maxlun+1); + if (scsi_dev == NULL) { + break; + } + if (scsi_dev->lun != maxlun+1) { + break; + } + maxlun++; + } + DPRINTF("MaxLun %d\n", maxlun); + data[0] = maxlun; p->actual_length = 1; break; default: @@ -386,6 +399,7 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) uint32_t tag; struct usb_msd_cbw cbw; uint8_t devep = p->ep->nr; + SCSIDevice *scsi_dev; switch (p->pid) { case USB_TOKEN_OUT: @@ -405,7 +419,8 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) goto fail; } DPRINTF("Command on LUN %d\n", cbw.lun); - if (cbw.lun != 0) { + scsi_dev = scsi_device_find(&s->bus, 0, 0, cbw.lun); + if (scsi_dev == NULL) { fprintf(stderr, "usb-msd: Bad LUN %d\n", cbw.lun); goto fail; } @@ -422,12 +437,12 @@ static void usb_msd_handle_data(USBDevice *dev, USBPacket *p) tag, cbw.flags, cbw.cmd_len, s->data_len); assert(le32_to_cpu(s->csw.residue) == 0); s->scsi_len = 0; - s->req = scsi_req_new(s->scsi_dev, tag, 0, cbw.cmd, NULL); + s->req = scsi_req_new(scsi_dev, tag, cbw.lun, cbw.cmd, NULL); #ifdef DEBUG_MSD scsi_req_print(s->req); #endif scsi_req_enqueue(s->req); - if (s->req->cmd.xfer != SCSI_XFER_NONE) { + if (s->req && s->req->cmd.xfer != SCSI_XFER_NONE) { scsi_req_continue(s->req); } break; @@ -553,7 +568,7 @@ static void *usb_msd_load_request(QEMUFile *f, SCSIRequest *req) return NULL; } -static const struct SCSIBusInfo usb_msd_scsi_info = { +static const struct SCSIBusInfo usb_msd_scsi_info_storage = { .tcq = false, .max_target = 0, .max_lun = 0, @@ -564,10 +579,22 @@ static const struct SCSIBusInfo usb_msd_scsi_info = { .load_request = usb_msd_load_request, }; -static int usb_msd_initfn(USBDevice *dev) +static const struct SCSIBusInfo usb_msd_scsi_info_bot = { + .tcq = false, + .max_target = 0, + .max_lun = 15, + + .transfer_data = usb_msd_transfer_data, + .complete = usb_msd_command_complete, + .cancel = usb_msd_request_cancelled, + .load_request = usb_msd_load_request, +}; + +static int usb_msd_initfn_storage(USBDevice *dev) { MSDState *s = DO_UPCAST(MSDState, dev, dev); BlockDriverState *bs = s->conf.bs; + SCSIDevice *scsi_dev; if (!bs) { error_report("drive property not set"); @@ -595,10 +622,10 @@ static int usb_msd_initfn(USBDevice *dev) } usb_desc_init(dev); - scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info); - s->scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable, + scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_storage); + scsi_dev = scsi_bus_legacy_add_drive(&s->bus, bs, 0, !!s->removable, s->conf.bootindex); - if (!s->scsi_dev) { + if (!scsi_dev) { return -1; } s->bus.qbus.allow_hotplug = 0; @@ -616,6 +643,19 @@ static int usb_msd_initfn(USBDevice *dev) return 0; } +static int usb_msd_initfn_bot(USBDevice *dev) +{ + MSDState *s = DO_UPCAST(MSDState, dev, dev); + + usb_desc_create_serial(dev); + usb_desc_init(dev); + scsi_bus_new(&s->bus, &s->dev.qdev, &usb_msd_scsi_info_bot); + s->bus.qbus.allow_hotplug = 0; + usb_msd_handle_reset(dev); + + return 0; +} + static USBDevice *usb_msd_init(USBBus *bus, const char *filename) { static int nr=0; @@ -698,12 +738,11 @@ static Property msd_properties[] = { DEFINE_PROP_END_OF_LIST(), }; -static void usb_msd_class_initfn(ObjectClass *klass, void *data) +static void usb_msd_class_initfn_common(ObjectClass *klass) { DeviceClass *dc = DEVICE_CLASS(klass); USBDeviceClass *uc = USB_DEVICE_CLASS(klass); - uc->init = usb_msd_initfn; uc->product_desc = "QEMU USB MSD"; uc->usb_desc = &desc; uc->cancel_packet = usb_msd_cancel_io; @@ -713,19 +752,44 @@ static void usb_msd_class_initfn(ObjectClass *klass, void *data) uc->handle_data = usb_msd_handle_data; dc->fw_name = "storage"; dc->vmsd = &vmstate_usb_msd; +} + +static void usb_msd_class_initfn_storage(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_msd_initfn_storage; dc->props = msd_properties; + usb_msd_class_initfn_common(klass); +} + +static void usb_msd_class_initfn_bot(ObjectClass *klass, void *data) +{ + USBDeviceClass *uc = USB_DEVICE_CLASS(klass); + + uc->init = usb_msd_initfn_bot; + usb_msd_class_initfn_common(klass); } static const TypeInfo msd_info = { .name = "usb-storage", .parent = TYPE_USB_DEVICE, .instance_size = sizeof(MSDState), - .class_init = usb_msd_class_initfn, + .class_init = usb_msd_class_initfn_storage, +}; + +static const TypeInfo bot_info = { + .name = "usb-bot", + .parent = TYPE_USB_DEVICE, + .instance_size = sizeof(MSDState), + .class_init = usb_msd_class_initfn_bot, }; static void usb_msd_register_types(void) { type_register_static(&msd_info); + type_register_static(&bot_info); usb_legacy_register("usb-storage", "disk", usb_msd_init); } diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 6a2f5f8c5d..dd9967b13d 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -1736,6 +1736,7 @@ static void ohci_mem_write(void *opaque, /* PXA27x specific registers */ case 24: /* HcStatus */ ohci->hstatus &= ~(val & ohci->hmask); + break; case 25: /* HcHReset */ ohci->hreset = val & ~OHCI_HRESET_FSBIR; diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c index 3040bc63ab..c0a790264c 100644 --- a/hw/virtio-balloon.c +++ b/hw/virtio-balloon.c @@ -14,6 +14,7 @@ */ #include "qemu/iov.h" +#include "qemu/timer.h" #include "qemu-common.h" #include "virtio.h" #include "pc.h" @@ -22,6 +23,7 @@ #include "virtio-balloon.h" #include "sysemu/kvm.h" #include "exec/address-spaces.h" +#include "qapi/visitor.h" #if defined(__linux__) #include <sys/mman.h> @@ -36,6 +38,9 @@ typedef struct VirtIOBalloon uint64_t stats[VIRTIO_BALLOON_S_NR]; VirtQueueElement stats_vq_elem; size_t stats_vq_offset; + QEMUTimer *stats_timer; + int64_t stats_last_update; + int64_t stats_poll_interval; DeviceState *qdev; } VirtIOBalloon; @@ -53,6 +58,16 @@ static void balloon_page(void *addr, int deflate) #endif } +static const char *balloon_stat_names[] = { + [VIRTIO_BALLOON_S_SWAP_IN] = "stat-swap-in", + [VIRTIO_BALLOON_S_SWAP_OUT] = "stat-swap-out", + [VIRTIO_BALLOON_S_MAJFLT] = "stat-major-faults", + [VIRTIO_BALLOON_S_MINFLT] = "stat-minor-faults", + [VIRTIO_BALLOON_S_MEMFREE] = "stat-free-memory", + [VIRTIO_BALLOON_S_MEMTOT] = "stat-total-memory", + [VIRTIO_BALLOON_S_NR] = NULL +}; + /* * reset_stats - Mark all items in the stats array as unset * @@ -67,6 +82,118 @@ static inline void reset_stats(VirtIOBalloon *dev) for (i = 0; i < VIRTIO_BALLOON_S_NR; dev->stats[i++] = -1); } +static bool balloon_stats_supported(const VirtIOBalloon *s) +{ + return s->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ); +} + +static bool balloon_stats_enabled(const VirtIOBalloon *s) +{ + return s->stats_poll_interval > 0; +} + +static void balloon_stats_destroy_timer(VirtIOBalloon *s) +{ + if (balloon_stats_enabled(s)) { + qemu_del_timer(s->stats_timer); + qemu_free_timer(s->stats_timer); + s->stats_timer = NULL; + s->stats_poll_interval = 0; + } +} + +static void balloon_stats_change_timer(VirtIOBalloon *s, int secs) +{ + qemu_mod_timer(s->stats_timer, qemu_get_clock_ms(vm_clock) + secs * 1000); +} + +static void balloon_stats_poll_cb(void *opaque) +{ + VirtIOBalloon *s = opaque; + + if (!balloon_stats_supported(s)) { + /* re-schedule */ + balloon_stats_change_timer(s, s->stats_poll_interval); + return; + } + + virtqueue_push(s->svq, &s->stats_vq_elem, s->stats_vq_offset); + virtio_notify(&s->vdev, s->svq); +} + +static void balloon_stats_get_all(Object *obj, struct Visitor *v, + void *opaque, const char *name, Error **errp) +{ + VirtIOBalloon *s = opaque; + int i; + + if (!s->stats_last_update) { + error_setg(errp, "guest hasn't updated any stats yet"); + return; + } + + visit_start_struct(v, NULL, "guest-stats", name, 0, errp); + visit_type_int(v, &s->stats_last_update, "last-update", errp); + + visit_start_struct(v, NULL, NULL, "stats", 0, errp); + for (i = 0; i < VIRTIO_BALLOON_S_NR; i++) { + visit_type_int64(v, (int64_t *) &s->stats[i], balloon_stat_names[i], + errp); + } + visit_end_struct(v, errp); + + visit_end_struct(v, errp); +} + +static void balloon_stats_get_poll_interval(Object *obj, struct Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + VirtIOBalloon *s = opaque; + visit_type_int(v, &s->stats_poll_interval, name, errp); +} + +static void balloon_stats_set_poll_interval(Object *obj, struct Visitor *v, + void *opaque, const char *name, + Error **errp) +{ + VirtIOBalloon *s = opaque; + int64_t value; + + visit_type_int(v, &value, name, errp); + if (error_is_set(errp)) { + return; + } + + if (value < 0) { + error_setg(errp, "timer value must be greater than zero"); + return; + } + + if (value == s->stats_poll_interval) { + return; + } + + if (value == 0) { + /* timer=0 disables the timer */ + balloon_stats_destroy_timer(s); + return; + } + + if (balloon_stats_enabled(s)) { + /* timer interval change */ + s->stats_poll_interval = value; + balloon_stats_change_timer(s, value); + return; + } + + /* create a new timer */ + g_assert(s->stats_timer == NULL); + s->stats_timer = qemu_new_timer_ms(vm_clock, balloon_stats_poll_cb, s); + s->stats_poll_interval = value; + balloon_stats_change_timer(s, 0); +} + static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq) { VirtIOBalloon *s = to_virtio_balloon(vdev); @@ -107,9 +234,10 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq) VirtQueueElement *elem = &s->stats_vq_elem; VirtIOBalloonStat stat; size_t offset = 0; + qemu_timeval tv; if (!virtqueue_pop(vq, elem)) { - return; + goto out; } /* Initialize the stats to get rid of any stale values. This is only @@ -128,6 +256,18 @@ static void virtio_balloon_receive_stats(VirtIODevice *vdev, VirtQueue *vq) s->stats[tag] = val; } s->stats_vq_offset = offset; + + if (qemu_gettimeofday(&tv) < 0) { + fprintf(stderr, "warning: %s: failed to get time of day\n", __func__); + goto out; + } + + s->stats_last_update = tv.tv_sec; + +out: + if (balloon_stats_enabled(s)) { + balloon_stats_change_timer(s, s->stats_poll_interval); + } } static void virtio_balloon_get_config(VirtIODevice *vdev, uint8_t *config_data) @@ -164,28 +304,6 @@ static uint32_t virtio_balloon_get_features(VirtIODevice *vdev, uint32_t f) static void virtio_balloon_stat(void *opaque, BalloonInfo *info) { VirtIOBalloon *dev = opaque; - -#if 0 - /* Disable guest-provided stats for now. For more details please check: - * https://bugzilla.redhat.com/show_bug.cgi?id=623903 - * - * If you do enable it (which is probably not going to happen as we - * need a new command for it), remember that you also need to fill the - * appropriate members of the BalloonInfo structure so that the stats - * are returned to the client. - */ - if (dev->vdev.guest_features & (1 << VIRTIO_BALLOON_F_STATS_VQ)) { - virtqueue_push(dev->svq, &dev->stats_vq_elem, dev->stats_vq_offset); - virtio_notify(&dev->vdev, dev->svq); - return; - } -#endif - - /* Stats are not supported. Clear out any stale values that might - * have been set by a more featureful guest kernel. - */ - reset_stats(dev); - info->actual = ram_size - ((uint64_t) dev->actual << VIRTIO_BALLOON_PFN_SHIFT); } @@ -255,12 +373,18 @@ VirtIODevice *virtio_balloon_init(DeviceState *dev) s->dvq = virtio_add_queue(&s->vdev, 128, virtio_balloon_handle_output); s->svq = virtio_add_queue(&s->vdev, 128, virtio_balloon_receive_stats); - reset_stats(s); - s->qdev = dev; register_savevm(dev, "virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); + object_property_add(OBJECT(dev), "guest-stats", "guest statistics", + balloon_stats_get_all, NULL, NULL, s, NULL); + + object_property_add(OBJECT(dev), "guest-stats-polling-interval", "int", + balloon_stats_get_poll_interval, + balloon_stats_set_poll_interval, + NULL, s, NULL); + return &s->vdev; } @@ -268,6 +392,7 @@ void virtio_balloon_exit(VirtIODevice *vdev) { VirtIOBalloon *s = DO_UPCAST(VirtIOBalloon, vdev, vdev); + balloon_stats_destroy_timer(s); qemu_remove_balloon_handler(s); unregister_savevm(s->qdev, "virtio-balloon", s); virtio_cleanup(vdev); diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c index 62771bb7b5..cd15ee40a8 100644 --- a/hw/vmware_vga.c +++ b/hw/vmware_vga.c @@ -296,6 +296,15 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, uint8_t *src; uint8_t *dst; + if (x < 0) { + fprintf(stderr, "%s: update x was < 0 (%d)\n", __func__, x); + w += x; + x = 0; + } + if (w < 0) { + fprintf(stderr, "%s: update w was < 0 (%d)\n", __func__, w); + w = 0; + } if (x + w > ds_get_width(s->vga.ds)) { fprintf(stderr, "%s: update width too large x: %d, w: %d\n", __func__, x, w); @@ -303,6 +312,15 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, w = ds_get_width(s->vga.ds) - x; } + if (y < 0) { + fprintf(stderr, "%s: update y was < 0 (%d)\n", __func__, y); + h += y; + y = 0; + } + if (h < 0) { + fprintf(stderr, "%s: update h was < 0 (%d)\n", __func__, h); + h = 0; + } if (y + h > ds_get_height(s->vga.ds)) { fprintf(stderr, "%s: update height too large y: %d, h: %d\n", __func__, y, h); diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c index 2254851f0a..11dfbc3ac1 100644 --- a/hw/xilinx_ethlite.c +++ b/hw/xilinx_ethlite.c @@ -89,7 +89,7 @@ eth_read(void *opaque, hwaddr addr, unsigned int size) case R_RX_CTRL1: case R_RX_CTRL0: r = s->regs[addr]; - D(qemu_log("%s %x=%x\n", __func__, addr * 4, r)); + D(qemu_log("%s " TARGET_FMT_plx "=%x\n", __func__, addr * 4, r)); break; default: @@ -115,7 +115,8 @@ eth_write(void *opaque, hwaddr addr, if (addr == R_TX_CTRL1) base = 0x800 / 4; - D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); + D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n", + __func__, addr * 4, value)); if ((value & (CTRL_P | CTRL_S)) == CTRL_S) { qemu_send_packet(&s->nic->nc, (void *) &s->regs[base], @@ -135,12 +136,16 @@ eth_write(void *opaque, hwaddr addr, break; /* Keep these native. */ + case R_RX_CTRL0: + case R_RX_CTRL1: + if (!(value & CTRL_S)) { + qemu_flush_queued_packets(&s->nic->nc); + } case R_TX_LEN0: case R_TX_LEN1: case R_TX_GIE0: - case R_RX_CTRL0: - case R_RX_CTRL1: - D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); + D(qemu_log("%s addr=" TARGET_FMT_plx " val=%x\n", + __func__, addr * 4, value)); s->regs[addr] = value; break; @@ -163,9 +168,9 @@ static const MemoryRegionOps eth_ops = { static int eth_can_rx(NetClientState *nc) { struct xlx_ethlite *s = DO_UPCAST(NICState, nc, nc)->opaque; - int r; - r = !(s->regs[R_RX_CTRL0] & CTRL_S); - return r; + unsigned int rxbase = s->rxbuf * (0x800 / 4); + + return !(s->regs[rxbase + R_RX_CTRL0] & CTRL_S); } static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) @@ -182,7 +187,7 @@ static ssize_t eth_rx(NetClientState *nc, const uint8_t *buf, size_t size) return -1; } - D(qemu_log("%s %d rxbase=%x\n", __func__, size, rxbase)); + D(qemu_log("%s %zd rxbase=%x\n", __func__, size, rxbase)); memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size); s->regs[rxbase + R_RX_CTRL0] |= CTRL_S; |